189 lines
6.4 KiB
C#
189 lines
6.4 KiB
C#
using System.Text;
|
||
using System.Text.Json;
|
||
using JOBot.Backend.DAL.Context;
|
||
using JOBot.Backend.DAL.Models;
|
||
using JOBot.Backend.DTOs.HeadHunterApi;
|
||
using JOBot.Backend.Infrastructure.Config;
|
||
using JOBot.Infrastructure.Config;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.Options;
|
||
using RabbitMQ.Client;
|
||
|
||
namespace JOBot.Backend.Services;
|
||
|
||
public class HeadHunterService(
|
||
IChannel channel,
|
||
ILogger<HeadHunterService> logger,
|
||
IOptions<HeadHunterConfig> config,
|
||
IWebHostEnvironment env,
|
||
AppDbContext dbContext)
|
||
{
|
||
public enum Status
|
||
{
|
||
UserAuthRejectedError,
|
||
HeadHunterAuthRejectedError,
|
||
UserNotFoundError,
|
||
HeadHunterResponseDeserializationFailedError,
|
||
Success
|
||
}
|
||
|
||
private readonly HeadHunterConfig _config = config.Value;
|
||
|
||
/// <summary>
|
||
/// Generate HeadHunter oauth authorization link
|
||
/// </summary>
|
||
/// <param name="userId">Telegram UserId</param>
|
||
/// <returns>Link for auth</returns>
|
||
public string GenerateAuthLink(long userId)
|
||
{
|
||
return string.Format(_config.Links.AuthLink, [_config.ClientId, GetRedirectUrl(userId)]);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Auth user on HeadHunter API
|
||
/// </summary>
|
||
/// <param name="userId"></param>
|
||
/// <param name="authorizationCode"></param>
|
||
/// <param name="error"></param>
|
||
/// <returns></returns>
|
||
public async Task<Status> AuthUser(int userId, string authorizationCode, string? error) //TODO: Разбить этот метод
|
||
{
|
||
logger.LogInformation($"Authorization for user {userId} in process...");
|
||
|
||
if (!string.IsNullOrEmpty(error))
|
||
{
|
||
logger.LogWarning($"User {userId} auth completed with error {error}");
|
||
return Status.UserAuthRejectedError;
|
||
}
|
||
|
||
HeadHunterTokenResponseDto? responseDto;
|
||
if (!env.IsDevelopment()) //Production server
|
||
{
|
||
using var client = new HttpClient();
|
||
var form = new Dictionary<string, string>
|
||
{
|
||
{ "client_id", _config.ClientId },
|
||
{ "client_secret", _config.Secret },
|
||
{ "code", authorizationCode },
|
||
{ "grant_type", "authorization_code" },
|
||
{ "redirect_uri", GetRedirectUrl(userId) }
|
||
};
|
||
client.BaseAddress = new UriBuilder(_config.Links.HeadHunterApiDomain)
|
||
{
|
||
Port = -1,
|
||
Scheme = "https"
|
||
}.Uri;
|
||
client.DefaultRequestHeaders.UserAgent.ParseAdd("Jobot BackEnd Service");
|
||
|
||
using var res = await client.SendAsync(
|
||
new HttpRequestMessage(
|
||
HttpMethod.Post,
|
||
_config.Links.HeadHunterTokenRoute)
|
||
{
|
||
Content = new FormUrlEncodedContent(form)
|
||
});
|
||
|
||
if (!res.IsSuccessStatusCode)
|
||
{
|
||
logger.LogWarning($"Response of HttpRequest {_config.Links.HeadHunterApiDomain}" +
|
||
$"{_config.Links.HeadHunterTokenRoute} has unsuccessful status code {res.StatusCode}");
|
||
logger.LogWarning($"{res.Content.ReadAsStringAsync().Result}");
|
||
return Status.HeadHunterAuthRejectedError;
|
||
}
|
||
|
||
responseDto =
|
||
JsonSerializer.Deserialize<HeadHunterTokenResponseDto>(await res.Content.ReadAsStringAsync());
|
||
|
||
if (responseDto == null)
|
||
{
|
||
logger.LogWarning($"User {userId} auth completed with error " +
|
||
$"{nameof(Status.HeadHunterResponseDeserializationFailedError)}");
|
||
return Status.HeadHunterResponseDeserializationFailedError;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
responseDto = new HeadHunterTokenResponseDto("testtoken", 0, "testtoken", "--");
|
||
}
|
||
|
||
var user = await dbContext.Users.FirstOrDefaultAsync(x => x.UserId == userId);
|
||
|
||
if (user == null)
|
||
{
|
||
logger.LogWarning($"User {userId} search completed with error {nameof(Status.UserNotFoundError)}");
|
||
return Status.UserNotFoundError;
|
||
}
|
||
|
||
user.AccessToken = responseDto.AccessToken;
|
||
user.RefreshToken = responseDto.RefreshToken;
|
||
user.ExpiresIn = responseDto.ExpiresIn;
|
||
|
||
await dbContext.SaveChangesAsync();
|
||
|
||
logger.LogInformation($"User {userId} auth completed!");
|
||
|
||
await channel.BasicPublishAsync(
|
||
string.Empty,
|
||
RabbitQueues.AuthQueue,
|
||
Encoding.UTF8.GetBytes(userId.ToString()));
|
||
|
||
logger.LogInformation("RabbitMQ event was created");
|
||
|
||
return Status.Success;
|
||
}
|
||
|
||
public async Task<Status> UpdateUserAccessToken(User user)
|
||
{
|
||
if (user.RefreshToken == null)
|
||
return Status.UserAuthRejectedError;
|
||
|
||
using var client = new HttpClient(); //TODO: Написать wrapper для работы с HH API
|
||
var form = new Dictionary<string, string>
|
||
{
|
||
{ "refresh_token", user.RefreshToken },
|
||
{ "grant_type", "refresh_token" }
|
||
};
|
||
client.BaseAddress = new UriBuilder(_config.Links.HeadHunterApiDomain)
|
||
{
|
||
Port = -1,
|
||
Scheme = "https"
|
||
}.Uri;
|
||
client.DefaultRequestHeaders.UserAgent.ParseAdd("Jobot BackEnd Service");
|
||
|
||
using var res = await client.SendAsync(
|
||
new HttpRequestMessage(
|
||
HttpMethod.Post,
|
||
_config.Links.HeadHunterTokenRoute)
|
||
{
|
||
Content = new FormUrlEncodedContent(form)
|
||
});
|
||
|
||
var responseDto =
|
||
JsonSerializer.Deserialize<HeadHunterTokenResponseDto>(await res.Content.ReadAsStringAsync());
|
||
|
||
if (responseDto == null)
|
||
{
|
||
logger.LogWarning(
|
||
$"User {user.Username ?? user.UserId.ToString()} access token accept completed with error " +
|
||
$"{nameof(Status.HeadHunterResponseDeserializationFailedError)}");
|
||
return Status.HeadHunterResponseDeserializationFailedError;
|
||
}
|
||
|
||
user.RefreshToken = responseDto.RefreshToken;
|
||
user.AccessToken = responseDto.AccessToken;
|
||
await dbContext.SaveChangesAsync();
|
||
|
||
return Status.Success;
|
||
}
|
||
|
||
private string GetRedirectUrl(long userId)
|
||
{
|
||
return new UriBuilder(_config.Links.HookDomain)
|
||
{
|
||
Port = -1,
|
||
Scheme = "https",
|
||
Path = _config.Links.HookRoute,
|
||
Query = $"?userId={userId}"
|
||
}.ToString();
|
||
}
|
||
} |