Skip to content

Commit

Permalink
C# 12 update
Browse files Browse the repository at this point in the history
  • Loading branch information
EdiWang committed Oct 13, 2023
1 parent 26f8ed0 commit 00e63ce
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 98 deletions.
63 changes: 20 additions & 43 deletions src/API/Elf.Api/Controllers/ForwardController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,7 @@ namespace Elf.Api.Controllers;

[ApiController]
[EnableRateLimiting("fixed-ip")]
public class ForwardController : ControllerBase
{
private readonly ILogger<ForwardController> _logger;
private readonly IConfiguration _configuration;
private readonly ITokenGenerator _tokenGenerator;
private readonly ILinkVerifier _linkVerifier;
private readonly IDistributedCache _cache;
private readonly IFeatureManager _featureManager;
private readonly IMediator _mediator;
private readonly IIPLocationService _ipLocationService;
private readonly CannonService _cannonService;

private StringValues UserAgent => Request.Headers["User-Agent"];

public ForwardController(
public class ForwardController(
ILogger<ForwardController> logger,
IConfiguration configuration,
ITokenGenerator tokenGenerator,
Expand All @@ -34,18 +20,9 @@ public ForwardController(
IFeatureManager featureManager,
IMediator mediator,
IIPLocationService ipLocationService,
CannonService cannonService)
{
_logger = logger;
_configuration = configuration;
_tokenGenerator = tokenGenerator;
_cache = cache;
_linkVerifier = linkVerifier;
_featureManager = featureManager;
_mediator = mediator;
_ipLocationService = ipLocationService;
_cannonService = cannonService;
}
CannonService cannonService) : ControllerBase
{
private StringValues UserAgent => Request.Headers["User-Agent"];

[AddForwarderHeader]
[HttpGet("/aka/{akaName:regex(^(?!-)([[a-zA-Z0-9-]]+)$)}")]
Expand All @@ -57,7 +34,7 @@ public async Task<IActionResult> Aka(string akaName)
var ip = Utils.GetClientIP(HttpContext) ?? "N/A";
if (string.IsNullOrWhiteSpace(UserAgent)) return BadRequest();

var token = await _mediator.Send(new GetTokenByAkaNameQuery(akaName));
var token = await mediator.Send(new GetTokenByAkaNameQuery(akaName));

// can not redirect to default url because it will confuse user that the aka points to that default url.
if (token is null) return NotFound();
Expand All @@ -81,69 +58,69 @@ public async Task<IActionResult> Forward(string token)

private async Task<IActionResult> PerformTokenRedirection(string token, string ip)
{
var isValid = _tokenGenerator.TryParseToken(token, out var validatedToken);
var isValid = tokenGenerator.TryParseToken(token, out var validatedToken);
if (!isValid) return BadRequest();

var linkEntry = await _cache.GetLink(token);
var linkEntry = await cache.GetLink(token);
if (null == linkEntry)
{
var flag = await _featureManager.IsEnabledAsync(nameof(FeatureFlags.AllowSelfRedirection));
var link = await _mediator.Send(new GetLinkByTokenQuery(validatedToken));
var flag = await featureManager.IsEnabledAsync(nameof(FeatureFlags.AllowSelfRedirection));
var link = await mediator.Send(new GetLinkByTokenQuery(validatedToken));
if (link is null)
{
var dru = _configuration["DefaultRedirectionUrl"];
var dru = configuration["DefaultRedirectionUrl"];
if (string.IsNullOrWhiteSpace(dru)) return NotFound();

var result = _linkVerifier.Verify(dru, Url, Request, flag);
var result = linkVerifier.Verify(dru, Url, Request, flag);
if (result == LinkVerifyResult.Valid) return Redirect(dru);

throw new UriFormatException("DefaultRedirectionUrl is not a valid URL.");
}

if (!link.IsEnabled) return BadRequest("This link is disabled.");

var verifyOriginUrl = _linkVerifier.Verify(link.OriginUrl, Url, Request, flag);
var verifyOriginUrl = linkVerifier.Verify(link.OriginUrl, Url, Request, flag);
switch (verifyOriginUrl)
{
case LinkVerifyResult.Valid:
// cache valid link entity only.
if (link.TTL is not null)
{
await _cache.SetLink(token, link, TimeSpan.FromSeconds(link.TTL.GetValueOrDefault()));
await cache.SetLink(token, link, TimeSpan.FromSeconds(link.TTL.GetValueOrDefault()));
}
else
{
await _cache.SetLink(token, link);
await cache.SetLink(token, link);
}
break;
case LinkVerifyResult.InvalidFormat:
throw new UriFormatException(
$"OriginUrl '{link.OriginUrl}' is not a valid URL, link ID: {link.Id}.");
case LinkVerifyResult.InvalidLocal:
_logger.LogWarning($"Local redirection is blocked. link: {JsonSerializer.Serialize(link)}");
logger.LogWarning($"Local redirection is blocked. link: {JsonSerializer.Serialize(link)}");
return BadRequest("Local redirection is blocked");
case LinkVerifyResult.InvalidSelfReference:
_logger.LogWarning(
logger.LogWarning(
$"Self reference redirection is blocked. link: {JsonSerializer.Serialize(link)}");
return BadRequest("Self reference redirection is blocked");
default:
throw new ArgumentOutOfRangeException();
}
}

linkEntry ??= await _cache.GetLink(token);
linkEntry ??= await cache.GetLink(token);

if (await _featureManager.IsEnabledAsync(nameof(FeatureFlags.EnableTracking)))
if (await featureManager.IsEnabledAsync(nameof(FeatureFlags.EnableTracking)))
{
Response.Headers.Append("X-Elf-Tracking-For", ip);
var ua = UserAgent;

_cannonService.Fire(async (IMediator mediator) =>
cannonService.Fire(async (IMediator mediator) =>
{
IPLocation location;
try
{
location = await _ipLocationService.GetLocationAsync(ip, ua);
location = await ipLocationService.GetLocationAsync(ip, ua);
}
catch (Exception)
{
Expand Down
48 changes: 18 additions & 30 deletions src/API/Elf.Api/Controllers/LinkController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,19 @@ namespace Elf.Api.Controllers;
[Authorize(AuthenticationSchemes = ElfAuthSchemas.All)]
[ApiController]
[Route("api/[controller]")]
public class LinkController : ControllerBase
{
private readonly ILinkVerifier _linkVerifier;
private readonly IDistributedCache _cache;
private readonly IFeatureManager _featureManager;
private readonly IMediator _mediator;

public LinkController(
public class LinkController(
ILinkVerifier linkVerifier,
IDistributedCache cache,
IFeatureManager featureManager, IMediator mediator)
{
_linkVerifier = linkVerifier;
_cache = cache;
_featureManager = featureManager;
_mediator = mediator;
}

IFeatureManager featureManager,
IMediator mediator) : ControllerBase
{
[HttpPost("create")]
[ProducesResponseType(typeof(string), StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Create(LinkEditModel model)
{
var flag = await _featureManager.IsEnabledAsync(nameof(FeatureFlags.AllowSelfRedirection));
var verifyResult = _linkVerifier.Verify(model.OriginUrl, Url, Request, flag);
var flag = await featureManager.IsEnabledAsync(nameof(FeatureFlags.AllowSelfRedirection));
var verifyResult = linkVerifier.Verify(model.OriginUrl, Url, Request, flag);
switch (verifyResult)
{
case LinkVerifyResult.InvalidFormat:
Expand All @@ -44,7 +32,7 @@ public async Task<IActionResult> Create(LinkEditModel model)
return BadRequest("Can not use url pointing to this site.");
}

await _mediator.Send(new CreateLinkCommand(model));
await mediator.Send(new CreateLinkCommand(model));
return NoContent();
}

Expand All @@ -53,8 +41,8 @@ public async Task<IActionResult> Create(LinkEditModel model)
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Edit(int id, LinkEditModel model)
{
var flag = await _featureManager.IsEnabledAsync(nameof(FeatureFlags.AllowSelfRedirection));
var verifyResult = _linkVerifier.Verify(model.OriginUrl, Url, Request, flag);
var flag = await featureManager.IsEnabledAsync(nameof(FeatureFlags.AllowSelfRedirection));
var verifyResult = linkVerifier.Verify(model.OriginUrl, Url, Request, flag);
switch (verifyResult)
{
case LinkVerifyResult.InvalidFormat:
Expand All @@ -65,16 +53,16 @@ public async Task<IActionResult> Edit(int id, LinkEditModel model)
return BadRequest("Can not use url pointing to this site.");
}

var token = await _mediator.Send(new EditLinkCommand(id, model));
if (token is not null) await _cache.RemoveAsync(token);
var token = await mediator.Send(new EditLinkCommand(id, model));
if (token is not null) await cache.RemoveAsync(token);
return NoContent();
}

[HttpPut("{id:int}/enable")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> SetEnable(int id, bool isEnabled)
{
await _mediator.Send(new SetEnableCommand(id, isEnabled));
await mediator.Send(new SetEnableCommand(id, isEnabled));
return NoContent();
}

Expand All @@ -85,7 +73,7 @@ public async Task<IActionResult> List(
[Range(1, int.MaxValue)] int take,
[Range(0, int.MaxValue)] int offset)
{
var (links, totalRows) = await _mediator.Send(new ListLinkQuery(offset, take, term));
var (links, totalRows) = await mediator.Send(new ListLinkQuery(offset, take, term));

var result = new PagedLinkResult
{
Expand All @@ -101,7 +89,7 @@ public async Task<IActionResult> List(
[ProducesResponseType(typeof(PagedLinkResult), StatusCodes.Status200OK)]
public async Task<IActionResult> ListByTags(ListByTagsRequest request)
{
var (links, totalRows) = await _mediator.Send(new ListByTagsCommand(request));
var (links, totalRows) = await mediator.Send(new ListByTagsCommand(request));

var result = new PagedLinkResult
{
Expand All @@ -118,7 +106,7 @@ public async Task<IActionResult> ListByTags(ListByTagsRequest request)
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> Get(int id)
{
var link = await _mediator.Send(new GetLinkQuery(id));
var link = await mediator.Send(new GetLinkQuery(id));
if (link is null) return NotFound();

return Ok(link);
Expand All @@ -129,12 +117,12 @@ public async Task<IActionResult> Get(int id)
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> Delete(int id)
{
var link = await _mediator.Send(new GetLinkQuery(id));
var link = await mediator.Send(new GetLinkQuery(id));
if (link is null) return NotFound();

await _mediator.Send(new DeleteLinkCommand(id));
await mediator.Send(new DeleteLinkCommand(id));

await _cache.RemoveAsync(link.FwToken);
await cache.RemoveAsync(link.FwToken);
return Ok();
}
}
23 changes: 7 additions & 16 deletions src/API/Elf.Api/Controllers/ReportController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,15 @@ namespace Elf.Api.Controllers;
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class ReportController : ControllerBase
public class ReportController(IConfiguration configuration, IMediator mediator) : ControllerBase
{
private readonly IConfiguration _configuration;
private readonly IMediator _mediator;

public ReportController(IConfiguration configuration, IMediator mediator)
{
_configuration = configuration;
_mediator = mediator;
}

[HttpGet("requests")]
[ProducesResponseType(typeof(PagedRequestTrack), StatusCodes.Status200OK)]
public async Task<IActionResult> Requests(
[Range(1, int.MaxValue)] int take,
[Range(0, int.MaxValue)] int offset)
{
var (requests, totalRows) = await _mediator.Send(new GetRecentRequestsQuery(offset, take));
var (requests, totalRows) = await mediator.Send(new GetRecentRequestsQuery(offset, take));

var result = new PagedRequestTrack
{
Expand All @@ -39,32 +30,32 @@ public async Task<IActionResult> Requests(
[ProducesResponseType(typeof(IReadOnlyList<MostRequestedLinkCount>), StatusCodes.Status200OK)]
public async Task<IActionResult> MostRequestedLinks(DateRangeRequest request)
{
var linkCounts = await _mediator.Send(new GetMostRequestedLinkCountQuery(request));
var linkCounts = await mediator.Send(new GetMostRequestedLinkCountQuery(request));
return Ok(linkCounts);
}

[HttpPost("requests/clienttype")]
[ProducesResponseType(typeof(IReadOnlyList<ClientTypeCount>), StatusCodes.Status200OK)]
public async Task<IActionResult> ClientType(DateRangeRequest request)
{
var types = await _mediator.Send(new GetClientTypeCountsQuery(request,
_configuration.GetSection("AppSettings:TopClientTypes").Get<int>()));
var types = await mediator.Send(new GetClientTypeCountsQuery(request,
configuration.GetSection("AppSettings:TopClientTypes").Get<int>()));
return Ok(types);
}

[HttpPost("tracking")]
[ProducesResponseType(typeof(IReadOnlyList<LinkTrackingDateCount>), StatusCodes.Status200OK)]
public async Task<IActionResult> TrackingCount(DateRangeRequest request)
{
var dateCounts = await _mediator.Send(new GetLinkTrackingDateCountQuery(request));
var dateCounts = await mediator.Send(new GetLinkTrackingDateCountQuery(request));
return Ok(dateCounts);
}

[HttpDelete("tracking/clear")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> ClearTrackingData()
{
await _mediator.Send(new ClearTrackingDataCommand());
await mediator.Send(new ClearTrackingDataCommand());
return NoContent();
}
}
14 changes: 5 additions & 9 deletions src/API/Elf.Api/Controllers/TagController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,13 @@ namespace Elf.Api.Controllers;
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class TagController : ControllerBase
public class TagController(IMediator mediator) : ControllerBase
{
private readonly IMediator _mediator;

public TagController(IMediator mediator) => _mediator = mediator;

[HttpGet("list")]
[ProducesResponseType(typeof(List<TagEntity>), StatusCodes.Status200OK)]
public async Task<IActionResult> List()
{
var list = await _mediator.Send(new GetTagsQuery());
var list = await mediator.Send(new GetTagsQuery());
return Ok(list);
}

Expand All @@ -25,7 +21,7 @@ public async Task<IActionResult> List()
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Create(CreateTagCommand command)
{
await _mediator.Send(command);
await mediator.Send(command);
return NoContent();
}

Expand All @@ -35,7 +31,7 @@ public async Task<IActionResult> Create(CreateTagCommand command)
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> Update(int id, UpdateTagRequest request)
{
var code = await _mediator.Send(new UpdateTagCommand(id, request));
var code = await mediator.Send(new UpdateTagCommand(id, request));
if (code == -1) return NotFound();

return NoContent();
Expand All @@ -47,7 +43,7 @@ public async Task<IActionResult> Update(int id, UpdateTagRequest request)
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> Delete(int id)
{
var code = await _mediator.Send(new DeleteTagCommand(id));
var code = await mediator.Send(new DeleteTagCommand(id));
if (code == -1) return NotFound();

return NoContent();
Expand Down

0 comments on commit 00e63ce

Please sign in to comment.