Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
*.swp
*.*~
project.lock.json
.DS_Store
*.pyc

# Visual Studio Code
.vscode

# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
msbuild.log
msbuild.err
msbuild.wrn

# Visual Studio 2015
.vs/
19 changes: 19 additions & 0 deletions Install.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Installation Guide
-------------------------------------------------------------------------

### Required Software

- Visual Studio 2019. [Community version](https://visualstudio.microsoft.com/vs/community/)
- Net Core 3.


### Installation

- Clone the code-test project.
- Open the solution file => src\UrlShortener\UrlShortener.sln and Run!

### DataBase
- The project use SqlLite.
- After runnning for the first time, you can find the sqlLite database file under: src\UrlShortener\UrlShortener.Api\UrlShortener.db


25 changes: 25 additions & 0 deletions src/UrlShortener/CrossCutting/CodeUtilities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Linq;

namespace UrlShortener.CrossCutting
{
public static class CodeUtilities
{
private static string source = "abcdefghijklmnopqrstuvwxyz0123456789";
private static readonly Random random;

static CodeUtilities()
{
random = new Random();
}

public static string Generate(int lengh) => CreateRandomWord(lengh);

private static string CreateRandomWord(int length)
{
return new string(Enumerable.Range(1, length)
.Select(_ => source[new Random().Next(source.Length)])
.ToArray());
}
}
}
20 changes: 20 additions & 0 deletions src/UrlShortener/CrossCutting/Exceptions/BadRequestException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;

namespace UrlShortener.CrossCutting.Exceptions
{
public class BadRequestException : Exception
{
public BadRequestException()
{
}

public BadRequestException(string message) : base(message)
{
}

public BadRequestException(string message, Exception inner)
: base(message, inner)
{
}
}
}
20 changes: 20 additions & 0 deletions src/UrlShortener/CrossCutting/Exceptions/ConflictException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;

namespace UrlShortener.CrossCutting.Exceptions
{
public class ConflictException : Exception
{
public ConflictException()
{
}

public ConflictException(string message) : base(message)
{
}

public ConflictException(string message, Exception inner)
: base(message, inner)
{
}
}
}
20 changes: 20 additions & 0 deletions src/UrlShortener/CrossCutting/Exceptions/NotFoundException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;

namespace UrlShortener.CrossCutting.Exceptions
{
public class NotFoundException : Exception
{
public NotFoundException()
{
}

public NotFoundException(string message) : base(message)
{
}

public NotFoundException(string message, Exception inner)
: base(message, inner)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;

namespace UrlShortener.CrossCutting.Exceptions
{
public class UnprocessableEntityException : Exception
{
public UnprocessableEntityException()
{
}

public UnprocessableEntityException(string message) : base(message)
{
}

public UnprocessableEntityException(string message, Exception inner)
: base(message, inner)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace UrlShortener.Api.Bootstrap.Filters
{
public class ExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
var message = context.Exception.GetBaseException().Message;

var exceptionName = context.Exception.GetType().Name;

var exception = ExceptionFilterFactory.Get(exceptionName);

context.HttpContext.Response.StatusCode = exception;

context.Result = new JsonResult(message);

base.OnException(context);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Net;

namespace UrlShortener.Api.Bootstrap.Filters
{
public class ExceptionFilterFactory
{
private static IReadOnlyDictionary<string, int> Exceptions;

static ExceptionFilterFactory()
{
Exceptions = new Dictionary<string, int>
{
{"BadRequestException" , (int)HttpStatusCode.BadRequest},
{"ConflictException", (int)HttpStatusCode.Conflict},
{"UnprocessableEntityException", (int)HttpStatusCode.UnprocessableEntity},
{"NotFoundException", (int)HttpStatusCode.NotFound},
};
}

public static int Get(string name)
{
int code;

if (!Exceptions.TryGetValue(name, out code))
{
throw new ArgumentOutOfRangeException($"The name {name} is not mapped to any collection in the exception filter configuration");
}

return code;
}
}
}
17 changes: 17 additions & 0 deletions src/UrlShortener/UrlShortener.Api/Bootstrap/MappingProfile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using AutoMapper;
using UrlShortener.Domain.Dto;
using UrlShortener.Domain.Entities;

namespace UrlShortener.Api.Bootstrap
{
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<ShortUrlDto, ShortUrl>();
CreateMap<ShortUrl, ShortUrlDto>();

CreateMap<ShortUrl, UrlStatDto>();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using UrlShortener.Domain.Dto;
using UrlShortener.Domain.Interfaces;

namespace UrlShortener.Api.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ShortUrlController : ControllerBase
{
private readonly IUrlShortenerService urlShortenerService;
public ShortUrlController(IUrlShortenerService urlShortenerService)
{
this.urlShortenerService = urlShortenerService;
}

[HttpPost]
public IActionResult Post(ShortUrlDto shortUrlDto)
{
if (string.IsNullOrEmpty(shortUrlDto.Url))
{
return BadRequest("Url is not present");
}

var shortUrlCreated = this.urlShortenerService.Add(shortUrlDto);

return Created(string.Empty, shortUrlCreated);
}

[HttpGet("{code}/stats")]
public async Task<IActionResult> GetStatByCode(string code)
{
var result = await this.urlShortenerService.GetStatByCode(code);

return Ok(result);
}

[HttpGet("{code}")]
public async Task<IActionResult> GetUrlByCode(string code)
{
var url = await this.urlShortenerService.GetUrlByCode(code);

return Redirect(url);
}
}
}
26 changes: 26 additions & 0 deletions src/UrlShortener/UrlShortener.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace UrlShortener.Api
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
30 changes: 30 additions & 0 deletions src/UrlShortener/UrlShortener.Api/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:1651",
"sslPort": 44398
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"UrlShortener.Api": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Loading