1
+ using System ;
2
+ using System . Linq ;
3
+ using System . Threading . Tasks ;
4
+ using JCTools . Shortener . Models ;
5
+ using JCTools . Shortener . Settings ;
6
+ using Microsoft . AspNetCore . Http ;
7
+ using Microsoft . AspNetCore . Mvc ;
8
+ using Microsoft . AspNetCore . Mvc . Infrastructure ;
9
+ using Microsoft . AspNetCore . Mvc . Routing ;
10
+ using Microsoft . EntityFrameworkCore ;
11
+
12
+
13
+ namespace JCTools . Shortener . Services
14
+ {
15
+ internal class LinkGenerator < TDatabaseContext > : ILinkGenerator
16
+ where TDatabaseContext : DbContext , IDatabaseContext
17
+ {
18
+ /// <summary>
19
+ /// the database context to be use
20
+ /// </summary>
21
+ private readonly TDatabaseContext _context ;
22
+ private readonly IUrlHelper _urlHelper ;
23
+ public LinkGenerator (
24
+ TDatabaseContext context ,
25
+ IUrlHelperFactory urlHelperFactory ,
26
+ IActionContextAccessor actionContextAccessor
27
+ )
28
+ {
29
+ this . _context = context ;
30
+ this . _urlHelper = urlHelperFactory . GetUrlHelper ( actionContextAccessor . ActionContext ) ;
31
+ }
32
+
33
+ /// <summary>
34
+ /// Generate a random unique string token, with a configured length.
35
+ /// </summary>
36
+ /// <returns>The generate token</returns>
37
+ public async Task < string > GenerateTokenAsync ( )
38
+ {
39
+ var random = new Random ( ) ;
40
+ var token = string . Empty ;
41
+ var isValid = false ;
42
+
43
+ while ( ! isValid )
44
+ {
45
+ var chars = Enumerable . Range ( 0 , StartupExtensors . Options . ValidCharacters . Length - 1 )
46
+ . OrderBy ( o => random . Next ( ) )
47
+ . Select ( i => StartupExtensors . Options . ValidCharacters [ i ] )
48
+ . ToList ( ) ;
49
+
50
+ token = string . Join ( "" , chars ) ;
51
+ var length = random . Next ( StartupExtensors . Options . MinLength , StartupExtensors . Options . MaxLength ) ;
52
+ var start = random . Next ( 0 , token . Length - length - 1 ) ;
53
+
54
+ token = token . Substring ( start , length ) ;
55
+
56
+ isValid = ! await _context . ShortLinks . AnyAsync ( sl => sl . Token == token ) ;
57
+ }
58
+
59
+ return token ;
60
+ }
61
+
62
+ /// <summary>
63
+ /// Generate a short url with an random unique token
64
+ /// </summary>
65
+ /// <param name="relatedTo">the related url to be short</param>
66
+ /// <returns>The generate shorted link</returns>
67
+ public async Task < ShortLink > GenerateAsync ( string relatedTo )
68
+ {
69
+ var tokenEntry = new ShortLink ( )
70
+ {
71
+ Token = await GenerateTokenAsync ( ) ,
72
+ RelatedUrl = relatedTo
73
+ } ;
74
+
75
+ return tokenEntry ;
76
+ }
77
+
78
+ /// <summary>
79
+ /// Generate and save a short link with a random token
80
+ /// </summary>
81
+ /// <param name="relatedTo">the related url to be short</param>
82
+ /// <returns>The task to be execute</returns>
83
+ public async Task < ShortLink > GenerateAndSaveAsync ( string relatedTo )
84
+ {
85
+ var link = await GenerateAsync ( relatedTo ) ;
86
+ await _context . AddAsync ( link ) ;
87
+ await _context . SaveChangesAsync ( ) ;
88
+ return link ;
89
+ }
90
+ /// <summary>
91
+ /// Allows get the absolute Url for the specified short link
92
+ /// </summary>
93
+ /// <param name="link">The short link to be use for generate the absolute Url</param>
94
+ /// <returns>The generated absolute url</returns>
95
+ public string GetAbsoluteUrl ( ShortLink link ) => GetAbsoluteUrl ( link . Token ) ;
96
+
97
+ /// <summary>
98
+ /// Allows get the absolute Url for the specified toke string
99
+ /// </summary>
100
+ /// <param name="token">The toke to be use for generate the absolute Url</param>
101
+ /// <returns>The generated absolute url</returns>
102
+ public string GetAbsoluteUrl ( string token )
103
+ {
104
+ return this . _urlHelper . Action (
105
+ nameof ( Controllers . ShortenerController < TDatabaseContext > . RedirectTo ) ,
106
+ nameof ( Controllers . ShortenerController < TDatabaseContext > ) . Replace ( "Controller" , "" ) ,
107
+ new { token = token } ,
108
+ this . _urlHelper . ActionContext . HttpContext . Request . Scheme
109
+ ) ;
110
+ }
111
+ }
112
+ }
0 commit comments