Manage mailbox aliases
This commit is contained in:
parent
6d289a7920
commit
2bec3d021a
13 changed files with 142 additions and 19 deletions
|
@ -27,6 +27,8 @@ steps:
|
|||
from_secret: AuthEndpoint
|
||||
AuthApiKey:
|
||||
from_secret: AuthApiKey
|
||||
MailboxEndpoint:
|
||||
from_secret: MailboxEndpoint
|
||||
commands:
|
||||
- curl -sL https://deb.nodesource.com/setup_12.x | bash -
|
||||
- apt-get install -y nodejs
|
||||
|
@ -37,6 +39,7 @@ steps:
|
|||
- sed -i "s/<GitEndpoint>/$GitEndpoint/g" output/appsettings.json
|
||||
- sed -i "s/<AuthEndpoint>/$AuthEndpoint/g" output/appsettings.json
|
||||
- sed -i "s/<AuthApiKey>/$AuthApiKey/g" output/appsettings.json
|
||||
- sed -i "s/<MailboxEndpoint>/$MailboxEndpoint/g" output/appsettings.json
|
||||
- cp Infrastructure/website.service output/
|
||||
- cp -r ./output/* /output
|
||||
- name: restart service
|
||||
|
|
|
@ -5,4 +5,6 @@ sed \
|
|||
-e 's/"blogApiEndpoint": ".*"/"blogApiEndpoint": ""/g' \
|
||||
-e 's/"gitApiEndpoint": ".*"/"gitApiEndpoint": ""/g' \
|
||||
-e 's/"authApiEndpoint": ".*"/"authApiEndpoint": ""/g' \
|
||||
-e 's/"authApiKey": ".*"/"authApiKey": ""/g' \
|
||||
-e 's/"mailboxesApiEndpoint": ".*"/"mailboxesApiEndpoint": ""/g' \
|
||||
$1
|
|
@ -20,7 +20,8 @@ namespace Website.Tests.Controllers {
|
|||
public void Login_WithReturnUrl_ReturnsViewThatHasModelWithReturnUrlAndFalseFailedAttempt() {
|
||||
var authenticationProvider = Substitute.For<IAuthenticationProvider>();
|
||||
var apiKeyManager = Substitute.For<IApiKeyManager>();
|
||||
var controller = new AccountController(authenticationProvider, apiKeyManager);
|
||||
var mailboxesApi = Substitute.For<IMailboxesApi>();
|
||||
var controller = new AccountController(authenticationProvider, apiKeyManager, mailboxesApi);
|
||||
|
||||
var expected = new LoginViewModel {
|
||||
ReturnUrl = "returnUrl",
|
||||
|
@ -36,7 +37,8 @@ namespace Website.Tests.Controllers {
|
|||
public void Login_WithReturnUrlAndFailedAttempt_ReturnsViewThatHasModelWithReturnUrlAndTrueFailedAttempt() {
|
||||
var authenticationProvider = Substitute.For<IAuthenticationProvider>();
|
||||
var apiKeyManager = Substitute.For<IApiKeyManager>();
|
||||
var controller = new AccountController(authenticationProvider, apiKeyManager);
|
||||
var mailboxesApi = Substitute.For<IMailboxesApi>();
|
||||
var controller = new AccountController(authenticationProvider, apiKeyManager, mailboxesApi);
|
||||
|
||||
var expected = new LoginViewModel {
|
||||
ReturnUrl = "returnUrl",
|
||||
|
@ -52,7 +54,8 @@ namespace Website.Tests.Controllers {
|
|||
public async Task Login_WithLoginRequest_WhenAuthenticationIsUnsuccessful_ReturnsViewThatHasModelWithReturnUrlAndTrueFailedAttempt() {
|
||||
var authenticationProvider = Substitute.For<IAuthenticationProvider>();
|
||||
var apiKeyManager = Substitute.For<IApiKeyManager>();
|
||||
var controller = new AccountController(authenticationProvider, apiKeyManager);
|
||||
var mailboxesApi = Substitute.For<IMailboxesApi>();
|
||||
var controller = new AccountController(authenticationProvider, apiKeyManager, mailboxesApi);
|
||||
|
||||
var request = new LoginRequest {
|
||||
Username = "username",
|
||||
|
@ -80,7 +83,8 @@ namespace Website.Tests.Controllers {
|
|||
|
||||
var authenticationProvider = Substitute.For<IAuthenticationProvider>();
|
||||
var apiKeyManager = Substitute.For<IApiKeyManager>();
|
||||
var controller = new AccountController(authenticationProvider, apiKeyManager) {
|
||||
var mailboxesApi = Substitute.For<IMailboxesApi>();
|
||||
var controller = new AccountController(authenticationProvider, apiKeyManager, mailboxesApi) {
|
||||
ControllerContext = new ControllerContext {
|
||||
HttpContext = new DefaultHttpContext {
|
||||
RequestServices = serviceProvider
|
||||
|
@ -116,7 +120,8 @@ namespace Website.Tests.Controllers {
|
|||
|
||||
var authenticationProvider = Substitute.For<IAuthenticationProvider>();
|
||||
var apiKeyManager = Substitute.For<IApiKeyManager>();
|
||||
var controller = new AccountController(authenticationProvider, apiKeyManager) {
|
||||
var mailboxesApi = Substitute.For<IMailboxesApi>();
|
||||
var controller = new AccountController(authenticationProvider, apiKeyManager, mailboxesApi) {
|
||||
ControllerContext = new ControllerContext {
|
||||
HttpContext = new DefaultHttpContext {
|
||||
RequestServices = serviceProvider
|
||||
|
@ -140,7 +145,8 @@ namespace Website.Tests.Controllers {
|
|||
public async Task Login_WithLoginRequest_WhenAuthenticationServiceFails_ReturnsViewThatHasModelWithReturnUrlAndTrueFailedAttempt() {
|
||||
var authenticationProvider = Substitute.For<IAuthenticationProvider>();
|
||||
var apiKeyManager = Substitute.For<IApiKeyManager>();
|
||||
var controller = new AccountController(authenticationProvider, apiKeyManager);
|
||||
var mailboxesApi = Substitute.For<IMailboxesApi>();
|
||||
var controller = new AccountController(authenticationProvider, apiKeyManager, mailboxesApi);
|
||||
|
||||
var request = new LoginRequest {Username = "username", Password = "password", ReturnUrl = "returnUrl"};
|
||||
|
||||
|
|
|
@ -6,22 +6,26 @@ using Microsoft.AspNetCore.Authorization;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Website.Data;
|
||||
using Website.Models.Auth;
|
||||
using Website.Models.Mailboxes;
|
||||
using Website.ViewModels;
|
||||
|
||||
namespace Website.Controllers {
|
||||
public class AccountController:Controller {
|
||||
private readonly IAuthenticationProvider _authenticationProvider;
|
||||
private readonly IApiKeyManager _apiKeyManager;
|
||||
private readonly IMailboxesApi _mailboxesApi;
|
||||
|
||||
public AccountController(IAuthenticationProvider authenticationProvider, IApiKeyManager apiKeyManager) {
|
||||
public AccountController(IAuthenticationProvider authenticationProvider, IApiKeyManager apiKeyManager, IMailboxesApi mailboxesApi) {
|
||||
_authenticationProvider = authenticationProvider;
|
||||
_apiKeyManager = apiKeyManager;
|
||||
_mailboxesApi = mailboxesApi;
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
public async Task<IActionResult> Index() {
|
||||
var keys = await _apiKeyManager.List();
|
||||
var model = new AccountViewModel(keys);
|
||||
var aliases = await _mailboxesApi.ListAliases();
|
||||
var model = new AccountViewModel(keys, aliases);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
|
@ -79,5 +83,26 @@ namespace Website.Controllers {
|
|||
await _apiKeyManager.Delete(key);
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
public async Task<IActionResult> EnableAlias(int id) {
|
||||
await _mailboxesApi.EnableAlias(id);
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
public async Task<IActionResult> DisableAlias(int id) {
|
||||
await _mailboxesApi.DisableAlias(id);
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
public async Task<IActionResult> DeleteAlias(int id) {
|
||||
await _mailboxesApi.DeleteAlias(id);
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
public async Task<IActionResult> CreateAlias(string source, string destination, bool active) {
|
||||
var alias = new NewAlias {Source = source, Destination = destination, Active = active};
|
||||
await _mailboxesApi.CreateAlias(alias);
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
}
|
||||
}
|
13
src/Website/Data/IMailboxesApi.cs
Normal file
13
src/Website/Data/IMailboxesApi.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Website.Models.Mailboxes;
|
||||
|
||||
namespace Website.Data {
|
||||
public interface IMailboxesApi {
|
||||
Task<IEnumerable<Alias>> ListAliases();
|
||||
Task EnableAlias(int id);
|
||||
Task DisableAlias(int id);
|
||||
Task CreateAlias(NewAlias alias);
|
||||
Task DeleteAlias(int id);
|
||||
}
|
||||
}
|
25
src/Website/Data/MailboxesApi.cs
Normal file
25
src/Website/Data/MailboxesApi.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Robware.Lib.ApiClient;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Website.Models.Mailboxes;
|
||||
|
||||
namespace Website.Data
|
||||
{
|
||||
public class MailboxesApi : ApiClient, IMailboxesApi
|
||||
{
|
||||
public MailboxesApi(HttpClient client, IMemoryCache cache, CacheDurations cacheDurations) : base(client, cache, cacheDurations)
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Alias>> ListAliases() => await Get<IEnumerable<Alias>>("/alias/list");
|
||||
public async Task EnableAlias(int id) => await Patch<object>("/alias/enable", null, new {id});
|
||||
|
||||
public async Task DisableAlias(int id) => await Patch<object>("/alias/disable", null, new {id});
|
||||
|
||||
public async Task CreateAlias(NewAlias alias) => await Post<object>("/alias/create", alias);
|
||||
|
||||
public async Task DeleteAlias(int id) => await Delete<object>("/alias/delete", new {id});
|
||||
}
|
||||
}
|
9
src/Website/Models/Mailboxes/Alias.cs
Normal file
9
src/Website/Models/Mailboxes/Alias.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Website.Models.Mailboxes {
|
||||
public class Alias {
|
||||
public int Id { get; set; }
|
||||
public int DomainId { get; set; }
|
||||
public string Source { get; set; }
|
||||
public string Destination { get; set; }
|
||||
public bool Active { get; set; }
|
||||
}
|
||||
}
|
7
src/Website/Models/Mailboxes/NewAlias.cs
Normal file
7
src/Website/Models/Mailboxes/NewAlias.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Website.Models.Mailboxes {
|
||||
public class NewAlias {
|
||||
public string Source { get; set; }
|
||||
public string Destination { get; set; }
|
||||
public bool Active { get; set; }
|
||||
}
|
||||
}
|
|
@ -50,6 +50,10 @@ namespace Website
|
|||
client.BaseAddress = new Uri(Configuration["authApiEndpoint"] + "api/");
|
||||
client.DefaultRequestHeaders.Add("x-api-key", new[] { Configuration["authApiKey"] });
|
||||
});
|
||||
services.AddHttpClient<IMailboxesApi, MailboxesApi>(client => {
|
||||
client.BaseAddress = new Uri(Configuration["mailboxesApiEndpoint"] + "api/");
|
||||
client.DefaultRequestHeaders.Add("x-api-key", new[] { Configuration["authApiKey"] });
|
||||
});
|
||||
|
||||
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
|
||||
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
using System.Collections.Generic;
|
||||
using Website.Models.ApiKey;
|
||||
using Website.Models.Mailboxes;
|
||||
|
||||
namespace Website.ViewModels {
|
||||
public class AccountViewModel {
|
||||
public IEnumerable<ApiKey> ApiKeys { get; }
|
||||
public IEnumerable<Alias> Aliases { get; }
|
||||
|
||||
public AccountViewModel(IEnumerable<ApiKey> apiKeys) {
|
||||
public AccountViewModel(IEnumerable<ApiKey> apiKeys, IEnumerable<Alias> aliases) {
|
||||
ApiKeys = apiKeys;
|
||||
Aliases = aliases;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,4 +27,29 @@
|
|||
<form asp-action="CreateApiKey">
|
||||
<label for="new-key-name">Name: </label><input type="text" name="name" id="new-key-name" />
|
||||
<button type="submit">Create</button>
|
||||
</form>
|
||||
|
||||
<h2>Manage Mailboxes</h2>
|
||||
<h3>Aliases</h3>
|
||||
<div class="table-scroll-container">
|
||||
<table class="actions">
|
||||
@foreach (var alias in Model.Aliases)
|
||||
{
|
||||
<tr>
|
||||
<td>@alias.Source</td>
|
||||
<td class="stretch">@alias.Destination</td>
|
||||
<td>@(alias.Active?"Enabled":"Disabled")</td>
|
||||
<td><a asp-action="EnableAlias" asp-route-id="@alias.Id"><img src="/images/enable.svg" alt="Enable" title="Enable" onclick="return confirm('Are you sure?')"/></a></td>
|
||||
<td><a asp-action="DisableAlias" asp-route-id="@alias.Id"><img src="/images/disable.svg" alt="Disable" title="Disable" onclick="return confirm('Are you sure?')"/></a></td>
|
||||
<td><a asp-action="DeleteAlias" asp-route-id="@alias.Id"><img src="/images/delete.svg" alt="Delete" title="Delete" onclick="return confirm('Are you sure?')"/></a></td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
</div>
|
||||
<h3>Create New Alias</h3>
|
||||
<form asp-action="CreateAlias">
|
||||
<label>Source: <input type="text" name="source" /></label>
|
||||
<label>Destination: <input type="text" name="destination" /></label>
|
||||
<label>@Html.CheckBox("active") Active</label>
|
||||
<button type="submit">Create</button>
|
||||
</form>
|
|
@ -6,21 +6,21 @@
|
|||
"Microsoft": "Information"
|
||||
}
|
||||
},
|
||||
"Kestrel": {
|
||||
"EndPoints": {
|
||||
"Http": {
|
||||
"Url": "https://0.0.0.0:5000"
|
||||
}
|
||||
}
|
||||
},
|
||||
"blogApiEndpoint": "",
|
||||
"gitApiEndpoint": "",
|
||||
"authApiEndpoint": "",
|
||||
"authApiKey": "",
|
||||
"mailboxesApiEndpoint": "",
|
||||
"cacheDurations": {
|
||||
"default": {
|
||||
"default": 30
|
||||
},
|
||||
"BlogApi": {
|
||||
"default": 21600, // 6 hours
|
||||
"GetPostByUrlAsync": 86400, // 1 day
|
||||
"GetPostByIdAsync": 86400 // 1 day
|
||||
},
|
||||
"GitApi": {
|
||||
"default": 3600, //1 hour
|
||||
"GetCommit": 86400 // 1 day
|
||||
"default": 1
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
"gitApiEndpoint": "<GitEndpoint>",
|
||||
"authApiEndpoint": "<AuthEndpoint>",
|
||||
"authApiKey": "<AuthApiKey>",
|
||||
"mailboxesApiEndpoint": "<MailboxEndpoint>",
|
||||
"AllowedHosts": "*",
|
||||
"Kestrel": {
|
||||
"EndPoints": {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue