-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #95 from dotnetcameroon/develop
Develop - Projects section
- Loading branch information
Showing
47 changed files
with
2,215 additions
and
249 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
# secret files | ||
secrets/ | ||
hangfire.db* | ||
projects.db* | ||
|
||
# dotenv files | ||
.env | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using app.domain.Models.ExternalAppAggregate; | ||
using app.shared.Utilities; | ||
using ErrorOr; | ||
using Microsoft.AspNetCore.Identity; | ||
|
||
namespace app.business.Services; | ||
public interface IExternalAppService | ||
{ | ||
Task<ErrorOr<PagedList<Application>>> GetAllAsync(int page = 1, int size = 10, CancellationToken cancellationToken = default); | ||
Task<ErrorOr<(Application application, string secret)>> RegisterAsync(string applicationName, IPasswordHasher<Application> passwordHasher, CancellationToken cancellationToken = default); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using app.domain.Models.ProjectsAggregate; | ||
|
||
namespace app.business.Services; | ||
public interface IProjectService | ||
{ | ||
Task<Project[]> GetAllAsync(); | ||
Task RefreshAsync(IEnumerable<Project> projects); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
using System.Security.Claims; | ||
|
||
namespace app.business.Services; | ||
public interface ITokenProvider | ||
{ | ||
string Generate(IEnumerable<Claim> claims); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
@page "/admin/apps/register" | ||
@using Microsoft.AspNetCore.Identity | ||
@using app.domain.Models.ExternalAppAggregate | ||
@attribute [Authorize(Policy = Policies.AdminOnly)] | ||
@layout AdminLayout | ||
@rendermode InteractiveServer | ||
@inject NavigationManager NavigationManager | ||
@inject IExternalAppService ExternalAppService | ||
@inject IPasswordHasher<Application> PasswordHasher | ||
|
||
<PageTitle>Admin | Register External Application</PageTitle> | ||
|
||
<h1>Register External App</h1> | ||
|
||
@if (_errors.Length > 0) | ||
{ | ||
<div class="text-red-600 bg-red-100 p-4 rounded-md border border-red-300"> | ||
@foreach (var error in _errors) | ||
{ | ||
<p>* @error</p> | ||
} | ||
</div> | ||
} | ||
|
||
<div class="max-w-md"> | ||
<div class="mb-4"> | ||
<label for="appName" class="block font-bold">Application Name:</label> | ||
<InputText id="appName" class="p-2 w-full px-4 border border-gray-400 rounded-lg" @bind-Value="appModel.Name" | ||
required /> | ||
</div> | ||
|
||
<button @onclick="HandleSubmit" class="btn btn-secondary">Register Application</button> | ||
@if (!string.IsNullOrEmpty(_clientSecret)) | ||
{ | ||
<div class="mt-4 flex items-center gap-2"> | ||
<p><span class="font-bold">Application ID:</span> @_application.Id</p> | ||
</div> | ||
<div class="mt-2 p-4 bg-yellow-100 border border-yellow-400 rounded-lg"> | ||
<p class="text-yellow-800 font-bold mb-2">⚠️ Warning: Save this client secret now. It will not be shown again! | ||
</p> | ||
<div class="flex items-center gap-2"> | ||
<input id="secret" type="password" readonly value="@_clientSecret" class="flex-grow p-2 border rounded" /> | ||
<button id="secret-button" onclick="copySecretToClipboard()" class="btn btn-primary"> | ||
<i class="fa-regular fa-clipboard"></i> | ||
</button> | ||
</div> | ||
</div> | ||
} | ||
</div> | ||
|
||
@code { | ||
private AppModel appModel = new(); | ||
private string[] _errors = []; | ||
private string _clientSecret = string.Empty; | ||
private Application _application = default!; | ||
|
||
private async Task HandleSubmit() | ||
{ | ||
_errors = []; | ||
if (string.IsNullOrWhiteSpace(appModel.Name)) | ||
{ | ||
_errors = ["Application name is required"]; | ||
return; | ||
} | ||
|
||
var result = await ExternalAppService.RegisterAsync(appModel.Name, PasswordHasher); | ||
if (result.IsError) | ||
{ | ||
_errors = result.Errors.Select(e => e.Description).ToArray(); | ||
} | ||
else | ||
{ | ||
_clientSecret = result.Value.secret; | ||
_application = result.Value.application; | ||
} | ||
} | ||
|
||
private class AppModel | ||
{ | ||
public string Name { get; set; } = string.Empty; | ||
} | ||
} |
104 changes: 104 additions & 0 deletions
104
app.client/Pages/Admin/ExternalApp/RegisteredApps.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
@page "/admin/apps" | ||
@using app.domain.Models.ExternalAppAggregate | ||
@attribute [Authorize(Policy = Policies.AdminOnly)] | ||
@attribute [StreamRendering] | ||
@layout AdminLayout | ||
@inject IExternalAppService ExternalAppService | ||
|
||
<PageTitle>Admin | External Applications</PageTitle> | ||
|
||
<div class="flex justify-between items-center"> | ||
<h1 class="heading heading-1">Applications</h1> | ||
<a href="/admin/apps/register" data-enhance-nav="false" class="btn btn-secondary cursor-pointer"> | ||
<i class="fa-regular fa-square-plus"></i> | ||
Register a New Application | ||
</a> | ||
</div> | ||
|
||
@if (_isLoading) | ||
{ | ||
<p>Loading ...</p> | ||
} | ||
else | ||
{ | ||
@if (!string.IsNullOrWhiteSpace(_errorMessage)) | ||
{ | ||
<p class="text-red-600 bg-red-100 p-4 rounded-md border border-red-300">@_errorMessage</p> | ||
} | ||
else | ||
{ | ||
<table class="w-full"> | ||
<thead class="bg-primary"> | ||
<th class="text-left p-2 text-white">Applications Name</th> | ||
<th class="text-left p-2 text-white">Applications Id</th> | ||
@* <th class="text-left p-2 text-white">Actions</th> *@ | ||
</thead> | ||
<tbody class="bg-slate-100"> | ||
@foreach (var item in _applications.Items) | ||
{ | ||
<tr class="border-b-white border-b-2"> | ||
<td class="p-2">@item.ClientName</td> | ||
<td class="p-2">@item.Id</td> | ||
@* <td class="p-2"> | ||
<a data-enhance-nav="false" class="text-secondary" href="/admin/events/@item.Id"><i | ||
class="fa-solid fa-pen-to-square"></i></a> | ||
<a data-enhance-nav="false" class="text-secondary ml-4" href="/admin/events/delete/@item.Id"><i | ||
class="fa-solid fa-trash-can"></i></a> | ||
</td> *@ | ||
</tr> | ||
} | ||
</tbody> | ||
</table> | ||
} | ||
} | ||
|
||
<div class="flex justify-between items-center mt-4"> | ||
<div class="flex gap-4 items-center"> | ||
<!-- Pagination --> | ||
<p>Page @Page / @_applications.TotalPages</p> | ||
|
||
@if (_applications.HasPreviousPage) | ||
{ | ||
<a data-enhance-nav="false" href="/admin/apps?Page=@(Page - 1)" class="link link-secondary" | ||
target="_parent">Previous</a> | ||
} | ||
@if (_applications.HasNextPage) | ||
{ | ||
<a data-enhance-nav="false" href="/admin/apps?Page=@(Page + 1)" class="link link-secondary" | ||
target="_parent">Next</a> | ||
} | ||
</div> | ||
</div> | ||
|
||
@code { | ||
private const int DefaultPage = 1; | ||
private const int DefaultPageSize = 5; | ||
|
||
[SupplyParameterFromQuery] | ||
public int Page { get; set; } | ||
|
||
[SupplyParameterFromQuery] | ||
public int Size { get; set; } | ||
|
||
private string _errorMessage = string.Empty; | ||
private bool _isLoading; | ||
private PagedList<Application> _applications = PagedList.Empty<Application>(); | ||
|
||
protected override async Task OnInitializedAsync() | ||
{ | ||
Page = Page == 0 ? DefaultPage : Page; | ||
Size = Size == 0 ? DefaultPageSize : Size; | ||
_isLoading = true; | ||
ErrorOr<PagedList<Application>> appsResult = default; | ||
appsResult = await ExternalAppService.GetAllAsync(Page, Size); | ||
if (appsResult.IsError) | ||
{ | ||
_errorMessage = string.Join("\n", appsResult.Errors.Select(e => e.Description)); | ||
_isLoading = false; | ||
return; | ||
} | ||
|
||
_applications = appsResult.Value; | ||
_isLoading = false; | ||
} | ||
} |
Oops, something went wrong.