· 7 years ago · Oct 02, 2018, 06:50 AM
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Net.Http;
5using System.Net.Http.Headers;
6using System.Threading.Tasks;
7using Microsoft.AspNetCore.Authorization;
8using Microsoft.AspNetCore.Mvc;
9using Microsoft.Extensions.Configuration;
10using Microsoft.Extensions.Logging;
11using Newtonsoft.Json.Linq;
12using Qrmap.WebApp.Areas.Invite.Models.Influencer;
13
14namespace Qrmap.WebApp.Areas.Invite.Controllers
15{
16 /// <summary>
17 /// Handle invitations for influencers.
18 /// </summary>
19 /// <remarks>
20 /// App might be hosted at influencer.cure.media or curefluence.curemedia.se.
21 /// </remarks>
22 [Authorize]
23 [Area("Invite")]
24 public class InfluencerController : Controller
25 {
26 private static HttpClient _tokenClient;
27 private static HttpRequestMessage _tokenRequestMessage;
28 private readonly IConfiguration _configuration;
29 private readonly ILogger<InfluencerController> _logger;
30
31 public InfluencerController(
32 ILogger<InfluencerController> logger,
33 IConfiguration configuration)
34 {
35 _logger = logger;
36 _configuration = configuration;
37 TokenRequest(configuration);
38 }
39
40 /// <summary>
41 /// Retrieve invitations
42 /// </summary>
43 /// <returns></returns>
44 [HttpGet]
45 public async Task<IActionResult> Index()
46 {
47 try
48 {
49 var client = await CreateInvitationClient();
50 var invitations = await client.GetInvitations() ?? new List<Invitation>();
51 return View(invitations);
52 }
53 catch (Exception exception)
54 {
55 _logger.LogError(exception, "Failed to retrieve invitations");
56 ViewData["Error"] = "Ett fel uppstod när skickade inbjudningar skulle hämtas";
57 return View(new List<Invitation>());
58 }
59 }
60
61 /// <summary>
62 /// Display create form.
63 /// </summary>
64 /// <returns></returns>
65 [HttpGet]
66 public IActionResult Create()
67 {
68 return View(new CreateModel());
69 }
70
71 /// <summary>
72 /// Create an invitation by calling the Invitation API endpoint.
73 /// </summary>
74 /// <param name="model"></param>
75 /// <returns></returns>
76 //[ValidateAntiForgeryToken]
77 [HttpPost]
78 public async Task<IActionResult> Create(CreateModel model)
79 {
80 if (!ModelState.IsValid)
81 {
82 return View(model);
83 }
84
85 try
86 {
87 var client = await CreateInvitationClient();
88 var invite = model.CreateInvitationRequest(User);
89 var response = await client.CreateInvite(invite);
90 if (response.Succeeded)
91 {
92 var result = new CreateResultModel
93 {
94 Success = true,
95 Message = $"Inbjudan skickad till <b>{model.Name} ({model.Email})</b>."
96 };
97 // Clear fields and return
98 return View(new CreateModel
99 {
100 Result = result
101 });
102 }
103
104 // API request failed. Simply return as string representation for now
105 model.Result = new CreateResultModel
106 {
107 Success = false,
108 Message = response.ToString()
109 };
110 return View(model);
111 }
112 catch (Exception exception)
113 {
114 _logger.LogError(exception, "Failed to create invite for {CreateInviteModel}", model);
115 }
116
117 var error = new CreateResultModel
118 {
119 Success = false,
120 Message = "Ett fel uppstod när inbjudan skulle skickas"
121 };
122 model.Result = error;
123 return View(model);
124 }
125
126 /// <summary>
127 /// Create and configure token request.
128 /// </summary>
129 /// <param name="configuration"></param>
130 private static void TokenRequest(IConfiguration configuration)
131 {
132 // Request token
133 _tokenClient = new HttpClient { BaseAddress = new Uri($"https://{configuration["Auth0:Domain"]}/") };
134 _tokenClient.DefaultRequestHeaders.Clear();
135 _tokenClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
136 var tokenRequestBody = new Dictionary<string, string>
137 {
138 ["client_id"] = configuration["Auth0:ClientId"],
139 ["client_secret"] = configuration["Auth0:ClientSecret"],
140 ["audience"] = configuration["InvitationAPI:Audience"],
141 ["grant_type"] = "client_credentials",
142 ["scopes"] = "create:invite"
143 };
144 _tokenRequestMessage = new HttpRequestMessage(HttpMethod.Post, "oauth/token")
145 {
146 Content = new FormUrlEncodedContent(tokenRequestBody
147 .Select(_ => new KeyValuePair<string, string>(_.Key, _.Value))
148 .ToList())
149 };
150 }
151
152 private async Task<InvitationClient> CreateInvitationClient()
153 {
154 var a = _configuration.GetValue<string>("InvitationAPI:BaseUri");
155 var accessToken = await GetAccessToken().ConfigureAwait(false);
156 var client = new InvitationClient(
157 _configuration.GetValue<string>("InvitationAPI:BaseUri"),
158 accessToken);
159 return client;
160 }
161
162 /// <summary>
163 /// Get <c>access_token</c> from <see cref="_tokenClient" /> using <see cref="_tokenRequestMessage" />.
164 /// </summary>
165 /// <remarks>
166 /// Access token is granted to application (for M2M communication). For granular control implement oauth at server to
167 /// govern to whom to grant scope access. E.g. create:invite or jus read:invite.
168 /// </remarks>
169 /// <returns>
170 /// An <c>access_token</c> on success, otherwise <c>null</c>.
171 /// </returns>
172 private async Task<string> GetAccessToken()
173 {
174 try
175 {
176 var response = await _tokenClient.SendAsync(_tokenRequestMessage);
177 if (_logger.IsEnabled(LogLevel.Debug))
178 {
179 var rateLimit = Auth0RateLimit.From(response.Headers);
180 _logger.LogDebug(new EventId(1, "Auth0"), "Rate limit {@Auth0RateLimit}", rateLimit);
181 }
182
183 // Allow for inspecting headers of Debug is enabled
184 response.EnsureSuccessStatusCode();
185 var json = await response.Content.ReadAsStringAsync();
186 var jObject = JObject.Parse(json);
187 return jObject.Value<string>("access_token");
188 }
189 catch (Exception exception)
190 {
191 _logger.LogCritical(new EventId(2, "Auth0"), exception, "Failed to retrieve access token");
192 return null;
193 }
194 }
195 }
196}