Added user view, added website and databases partialy
This commit is contained in:
@@ -39,6 +39,8 @@ public class DataContext : DbContext
|
|||||||
public DbSet<Revoke> Revokes { get; set; }
|
public DbSet<Revoke> Revokes { get; set; }
|
||||||
public DbSet<NotificationClient> NotificationClients { get; set; }
|
public DbSet<NotificationClient> NotificationClients { get; set; }
|
||||||
public DbSet<NotificationAction> NotificationActions { get; set; }
|
public DbSet<NotificationAction> NotificationActions { get; set; }
|
||||||
|
public DbSet<AaPanel> AaPanels { get; set; }
|
||||||
|
public DbSet<Website> Websites { get; set; }
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
|
|||||||
9
Moonlight/App/Database/Entities/AaPanel.cs
Normal file
9
Moonlight/App/Database/Entities/AaPanel.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
public class AaPanel
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Url { get; set; } = "";
|
||||||
|
public string Key { get; set; } = "";
|
||||||
|
public string BaseDomain { get; set; } = "";
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
public class Database
|
public class Database
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int AaPanelId { get; set; }
|
public int InternalAaPanelId { get; set; }
|
||||||
public User Owner { get; set; }
|
public User Owner { get; set; }
|
||||||
|
public AaPanel AaPanel { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
}
|
}
|
||||||
13
Moonlight/App/Database/Entities/Website.cs
Normal file
13
Moonlight/App/Database/Entities/Website.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
namespace Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
public class Website
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int InternalAaPanelId { get; set; }
|
||||||
|
public AaPanel AaPanel { get; set; }
|
||||||
|
public User Owner { get; set; }
|
||||||
|
public string DomainName { get; set; }
|
||||||
|
public string PhpVersion { get; set; }
|
||||||
|
public string FtpUsername { get; set; }
|
||||||
|
public string FtpPassword { get; set; }
|
||||||
|
}
|
||||||
44
Moonlight/App/Repositories/AaPanelRepository.cs
Normal file
44
Moonlight/App/Repositories/AaPanelRepository.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Repositories;
|
||||||
|
|
||||||
|
public class AaPanelRepository : IDisposable
|
||||||
|
{
|
||||||
|
private readonly DataContext DataContext;
|
||||||
|
|
||||||
|
public AaPanelRepository(DataContext dataContext)
|
||||||
|
{
|
||||||
|
DataContext = dataContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbSet<AaPanel> Get()
|
||||||
|
{
|
||||||
|
return DataContext.AaPanels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AaPanel Add(AaPanel aaPanel)
|
||||||
|
{
|
||||||
|
var x = DataContext.AaPanels.Add(aaPanel);
|
||||||
|
DataContext.SaveChanges();
|
||||||
|
return x.Entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(AaPanel aaPanel)
|
||||||
|
{
|
||||||
|
DataContext.AaPanels.Update(aaPanel);
|
||||||
|
DataContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(AaPanel aaPanel)
|
||||||
|
{
|
||||||
|
DataContext.AaPanels.Remove(aaPanel);
|
||||||
|
DataContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
DataContext.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
44
Moonlight/App/Repositories/WebsiteRepository.cs
Normal file
44
Moonlight/App/Repositories/WebsiteRepository.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Repositories;
|
||||||
|
|
||||||
|
public class WebsiteRepository : IDisposable
|
||||||
|
{
|
||||||
|
private readonly DataContext DataContext;
|
||||||
|
|
||||||
|
public WebsiteRepository(DataContext dataContext)
|
||||||
|
{
|
||||||
|
DataContext = dataContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbSet<Website> Get()
|
||||||
|
{
|
||||||
|
return DataContext.Websites;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Website Add(Website website)
|
||||||
|
{
|
||||||
|
var x = DataContext.Websites.Add(website);
|
||||||
|
DataContext.SaveChanges();
|
||||||
|
return x.Entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(Website website)
|
||||||
|
{
|
||||||
|
DataContext.Websites.Update(website);
|
||||||
|
DataContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(Website website)
|
||||||
|
{
|
||||||
|
DataContext.Websites.Remove(website);
|
||||||
|
DataContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
DataContext.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
76
Moonlight/App/Services/DatabaseService.cs
Normal file
76
Moonlight/App/Services/DatabaseService.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using aaPanelSharp;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Exceptions;
|
||||||
|
using Moonlight.App.Repositories;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Services;
|
||||||
|
|
||||||
|
public class DatabaseService
|
||||||
|
{
|
||||||
|
private readonly DatabaseRepository DatabaseRepository;
|
||||||
|
private readonly AaPanelRepository AaPanelRepository;
|
||||||
|
|
||||||
|
public DatabaseService(DatabaseRepository databaseRepository, AaPanelRepository aaPanelRepository)
|
||||||
|
{
|
||||||
|
DatabaseRepository = databaseRepository;
|
||||||
|
AaPanelRepository = aaPanelRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Database.Entities.Database> Create(string name, string password, User u, AaPanel? a = null)
|
||||||
|
{
|
||||||
|
if (DatabaseRepository.Get().Any(x => x.Name == name))
|
||||||
|
throw new DisplayException("A database with this name has been already created");
|
||||||
|
|
||||||
|
var aaPanel = a ?? AaPanelRepository.Get().First();
|
||||||
|
|
||||||
|
var access = new aaPanel(a!.Url, a.Key);
|
||||||
|
|
||||||
|
if (access.CreateDatabase(name, name, password))
|
||||||
|
{
|
||||||
|
var aaDb = access.Databases.First(x => x.Name == name);
|
||||||
|
|
||||||
|
return Task.FromResult(DatabaseRepository.Add(new()
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
AaPanel = aaPanel,
|
||||||
|
Owner = u,
|
||||||
|
InternalAaPanelId = aaDb.Id
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new DisplayException("An unknown error occured while creating the database");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task ChangePassword(Database.Entities.Database database, string newPassword)
|
||||||
|
{
|
||||||
|
var access = CreateApiAccess(database);
|
||||||
|
|
||||||
|
access.Databases.First(x => x.Id == database.InternalAaPanelId).ChangePassword(newPassword);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<string> GetPassword(Database.Entities.Database database)
|
||||||
|
{
|
||||||
|
var access = CreateApiAccess(database);
|
||||||
|
|
||||||
|
return Task.FromResult(
|
||||||
|
access.Databases
|
||||||
|
.First(x => x.Id == database.InternalAaPanelId).Password
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private aaPanel CreateApiAccess(Database.Entities.Database database)
|
||||||
|
{
|
||||||
|
if (database.AaPanel == null)
|
||||||
|
{
|
||||||
|
database = DatabaseRepository
|
||||||
|
.Get()
|
||||||
|
.Include(x => x.AaPanel)
|
||||||
|
.First(x => x.Id == database.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new aaPanel(database.AaPanel.Url, database.AaPanel.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
Moonlight/App/Services/TrashMailDetectorService.cs
Normal file
46
Moonlight/App/Services/TrashMailDetectorService.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System.Net;
|
||||||
|
using Logging.Net;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Services;
|
||||||
|
|
||||||
|
public class TrashMailDetectorService
|
||||||
|
{
|
||||||
|
private string[] Domains;
|
||||||
|
|
||||||
|
public TrashMailDetectorService()
|
||||||
|
{
|
||||||
|
Logger.Info("Fetching trash mail list from github repository");
|
||||||
|
|
||||||
|
using var wc = new WebClient();
|
||||||
|
|
||||||
|
var lines = wc
|
||||||
|
.DownloadString("https://raw.githubusercontent.com/Endelon-Hosting/TrashMailDomainDetector/main/trashmail_domains.md")
|
||||||
|
.Replace("\r\n", "\n")
|
||||||
|
.Split(new [] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
Domains = GetDomains(lines).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<string> GetDomains(string[] lines)
|
||||||
|
{
|
||||||
|
foreach (var line in lines)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(line))
|
||||||
|
{
|
||||||
|
if (line.Contains("."))
|
||||||
|
{
|
||||||
|
var domain = line.Remove(0, line.IndexOf(".", StringComparison.Ordinal) + 1).Trim();
|
||||||
|
if (domain.Contains("."))
|
||||||
|
{
|
||||||
|
yield return domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsTrashEmail(string mail)
|
||||||
|
{
|
||||||
|
return Domains.Contains(mail.Split('@')[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -67,13 +67,13 @@ public class UserService
|
|||||||
LastName = lastname,
|
LastName = lastname,
|
||||||
State = "",
|
State = "",
|
||||||
Status = UserStatus.Unverified,
|
Status = UserStatus.Unverified,
|
||||||
CreatedAt = DateTime.Now,
|
CreatedAt = DateTime.UtcNow,
|
||||||
DiscordDiscriminator = "",
|
DiscordDiscriminator = "",
|
||||||
DiscordId = -1,
|
DiscordId = -1,
|
||||||
DiscordUsername = "",
|
DiscordUsername = "",
|
||||||
TotpEnabled = false,
|
TotpEnabled = false,
|
||||||
TotpSecret = "",
|
TotpSecret = "",
|
||||||
UpdatedAt = DateTime.Now,
|
UpdatedAt = DateTime.UtcNow,
|
||||||
TokenValidTime = DateTime.Now.AddDays(-5)
|
TokenValidTime = DateTime.Now.AddDays(-5)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
39
Moonlight/App/Services/WebsiteService.cs
Normal file
39
Moonlight/App/Services/WebsiteService.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using aaPanelSharp;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Exceptions;
|
||||||
|
using Moonlight.App.Repositories;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Services;
|
||||||
|
|
||||||
|
public class WebsiteService
|
||||||
|
{
|
||||||
|
private readonly WebsiteRepository WebsiteRepository;
|
||||||
|
|
||||||
|
public WebsiteService(WebsiteRepository websiteRepository)
|
||||||
|
{
|
||||||
|
WebsiteRepository = websiteRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Website Create(AaPanel aaPanel, User user, string name)
|
||||||
|
{
|
||||||
|
if (WebsiteRepository.Get().Any(x => x.DomainName == name))
|
||||||
|
throw new DisplayException("A website with this domain has already been created");
|
||||||
|
|
||||||
|
var access = new aaPanel(aaPanel.Url, aaPanel.Key);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private aaPanel CreateApiAccess(Website website)
|
||||||
|
{
|
||||||
|
if (website.AaPanel == null)
|
||||||
|
{
|
||||||
|
website = WebsiteRepository
|
||||||
|
.Get()
|
||||||
|
.Include(x => x.AaPanel)
|
||||||
|
.First(x => x.Id == website.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new aaPanel(website.AaPanel.Url, website.AaPanel.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,6 +56,8 @@
|
|||||||
<_ContentIncludedByDefault Remove="wwwroot\css\open-iconic\ICON-LICENSE" />
|
<_ContentIncludedByDefault Remove="wwwroot\css\open-iconic\ICON-LICENSE" />
|
||||||
<_ContentIncludedByDefault Remove="wwwroot\css\open-iconic\README.md" />
|
<_ContentIncludedByDefault Remove="wwwroot\css\open-iconic\README.md" />
|
||||||
<_ContentIncludedByDefault Remove="wwwroot\css\site.css" />
|
<_ContentIncludedByDefault Remove="wwwroot\css\site.css" />
|
||||||
|
<_ContentIncludedByDefault Remove="Shared\Components\Tables\Column.razor" />
|
||||||
|
<_ContentIncludedByDefault Remove="Shared\Components\Tables\Table.razor" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ namespace Moonlight
|
|||||||
builder.Services.AddScoped<SubscriptionLimitRepository>();
|
builder.Services.AddScoped<SubscriptionLimitRepository>();
|
||||||
builder.Services.AddScoped<RevokeRepository>();
|
builder.Services.AddScoped<RevokeRepository>();
|
||||||
builder.Services.AddScoped<NotificationRepository>();
|
builder.Services.AddScoped<NotificationRepository>();
|
||||||
|
builder.Services.AddScoped<AaPanelRepository>();
|
||||||
|
builder.Services.AddScoped<WebsiteRepository>();
|
||||||
|
|
||||||
builder.Services.AddScoped<AuditLogEntryRepository>();
|
builder.Services.AddScoped<AuditLogEntryRepository>();
|
||||||
builder.Services.AddScoped<ErrorLogEntryRepository>();
|
builder.Services.AddScoped<ErrorLogEntryRepository>();
|
||||||
@@ -100,6 +102,8 @@ namespace Moonlight
|
|||||||
builder.Services.AddScoped<ErrorLogService>();
|
builder.Services.AddScoped<ErrorLogService>();
|
||||||
builder.Services.AddScoped<LogService>();
|
builder.Services.AddScoped<LogService>();
|
||||||
builder.Services.AddScoped<MailService>();
|
builder.Services.AddScoped<MailService>();
|
||||||
|
builder.Services.AddSingleton<TrashMailDetectorService>();
|
||||||
|
builder.Services.AddScoped<WebsiteService>();
|
||||||
|
|
||||||
// Support
|
// Support
|
||||||
builder.Services.AddSingleton<SupportServerService>();
|
builder.Services.AddSingleton<SupportServerService>();
|
||||||
|
|||||||
2
Moonlight/Shared/Views/Admin/AaPanels/Index.razor
Normal file
2
Moonlight/Shared/Views/Admin/AaPanels/Index.razor
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
@page "/admin/aapanels"
|
||||||
|
|
||||||
5
Moonlight/Shared/Views/Admin/Databases/Index.razor
Normal file
5
Moonlight/Shared/Views/Admin/Databases/Index.razor
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
@page "/admin/databases"
|
||||||
|
|
||||||
|
<OnlyAdmin>
|
||||||
|
|
||||||
|
</OnlyAdmin>
|
||||||
@@ -10,11 +10,24 @@
|
|||||||
|
|
||||||
<OnlyAdmin>
|
<OnlyAdmin>
|
||||||
<LazyLoader Load="Load">
|
<LazyLoader Load="Load">
|
||||||
<div class="row mb-5">
|
<div class="row">
|
||||||
<a class="btn btn-success" href="/admin/domains/new">Add new domain</a>
|
<div class="card">
|
||||||
|
<div class="card-header border-0 pt-5">
|
||||||
|
<h3 class="card-title align-items-start flex-column">
|
||||||
|
<span class="card-label fw-bold fs-3 mb-1">
|
||||||
|
<TL>Domains</TL>
|
||||||
|
</span>
|
||||||
|
</h3>
|
||||||
|
<div class="card-toolbar">
|
||||||
|
<a href="/admin/domains/new" class="btn btn-sm btn-light-success">
|
||||||
|
<i class="bx bx-layer-plus"></i>
|
||||||
|
<TL>New domain</TL>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-5">
|
</div>
|
||||||
<Table TableItem="Domain" Items="Domains" PageSize="25" TableHeadClass="border-bottom border-gray-200 fs-6 text-gray-600 fw-bold bg-light bg-opacity-75">
|
<div class="card-body pt-0">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<Table TableItem="Domain" Items="Domains" PageSize="25" TableClass="table table-row-bordered table-row-gray-100 align-middle gs-0 gy-3" TableHeadClass="fw-bold text-muted">
|
||||||
<Column TableItem="Domain" Title="@(SmartTranslateService.Translate("Id"))" Field="@(x => x.Id)" Sortable="true" Filterable="true" Width="10%"/>
|
<Column TableItem="Domain" Title="@(SmartTranslateService.Translate("Id"))" Field="@(x => x.Id)" Sortable="true" Filterable="true" Width="10%"/>
|
||||||
<Column TableItem="Domain" Title="@(SmartTranslateService.Translate("Name"))" Field="@(x => x.Name)" Sortable="true" Filterable="true" Width="10%"/>
|
<Column TableItem="Domain" Title="@(SmartTranslateService.Translate("Name"))" Field="@(x => x.Name)" Sortable="true" Filterable="true" Width="10%"/>
|
||||||
<Column TableItem="Domain" Title="@(SmartTranslateService.Translate("Shared domain"))" Field="@(x => x.SharedDomain)" Sortable="true" Filterable="true" Width="10%">
|
<Column TableItem="Domain" Title="@(SmartTranslateService.Translate("Shared domain"))" Field="@(x => x.SharedDomain)" Sortable="true" Filterable="true" Width="10%">
|
||||||
@@ -24,25 +37,28 @@
|
|||||||
</Column>
|
</Column>
|
||||||
<Column TableItem="Domain" Title="@(SmartTranslateService.Translate("Owner"))" Field="@(x => x.Owner)" Sortable="true" Filterable="true" Width="10%">
|
<Column TableItem="Domain" Title="@(SmartTranslateService.Translate("Owner"))" Field="@(x => x.Owner)" Sortable="true" Filterable="true" Width="10%">
|
||||||
<Template>
|
<Template>
|
||||||
<a class="invisible-a" href="/admin/users/view/@(context.Owner.Id)">@(context.Owner.Email)</a>
|
<a href="/admin/users/view/@(context.Owner.Id)">@(context.Owner.Email)</a>
|
||||||
</Template>
|
</Template>
|
||||||
</Column>
|
</Column>
|
||||||
<Column TableItem="Domain" Title="@(SmartTranslateService.Translate("Manage"))" Field="@(x => x.Id)" Sortable="false" Filterable="false" Width="10%">
|
<Column TableItem="Domain" Title="@(SmartTranslateService.Translate("Manage"))" Field="@(x => x.Id)" Sortable="false" Filterable="false" Width="10%">
|
||||||
<Template>
|
<Template>
|
||||||
<a class="invisible-a" href="/domain/@(context.Id)">Manage</a>
|
<a href="/domain/@(context.Id)">Manage</a>
|
||||||
</Template>
|
</Template>
|
||||||
</Column>
|
</Column>
|
||||||
<Column TableItem="Domain" Title="" Field="@(x => x.Id)" Sortable="false" Filterable="false" Width="10%">
|
<Column TableItem="Domain" Title="" Field="@(x => x.Id)" Sortable="false" Filterable="false" Width="10%">
|
||||||
<Template>
|
<Template>
|
||||||
<WButton Text="@(SmartTranslateService.Translate("Delete"))"
|
<WButton Text="@(SmartTranslateService.Translate("Delete"))"
|
||||||
WorkingText="@(SmartTranslateService.Translate("Deleting"))"
|
WorkingText="@(SmartTranslateService.Translate("Deleting"))"
|
||||||
CssClasses="btn-danger"
|
CssClasses="btn-sm btn-danger"
|
||||||
OnClick="() => Delete(context)">
|
OnClick="() => Delete(context)">
|
||||||
</WButton>
|
</WButton>
|
||||||
</Template>
|
</Template>
|
||||||
</Column>
|
</Column>
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
</OnlyAdmin>
|
</OnlyAdmin>
|
||||||
|
|
||||||
|
|||||||
@@ -9,30 +9,36 @@
|
|||||||
@inject SmartTranslateService SmartTranslateService
|
@inject SmartTranslateService SmartTranslateService
|
||||||
|
|
||||||
<OnlyAdmin>
|
<OnlyAdmin>
|
||||||
<div class="row mb-5">
|
<div class="row">
|
||||||
<div class="card card-body">
|
<LazyLoader Load="Load">
|
||||||
<a href="/admin/servers/new" class="btn btn-success">
|
<div class="card">
|
||||||
<TL>Create new server</TL>
|
<div class="card-header border-0 pt-5">
|
||||||
|
<h3 class="card-title align-items-start flex-column">
|
||||||
|
<span class="card-label fw-bold fs-3 mb-1"><TL>Servers</TL></span>
|
||||||
|
</h3>
|
||||||
|
<div class="card-toolbar">
|
||||||
|
<a href="/admin/servers/new" class="btn btn-sm btn-light-success">
|
||||||
|
<i class="bx bx-layer-plus"></i>
|
||||||
|
<TL>New server</TL>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="card-body pt-0">
|
||||||
<LazyLoader Load="Load">
|
|
||||||
<div class="card card-body">
|
|
||||||
@if (Servers.Any())
|
@if (Servers.Any())
|
||||||
{
|
{
|
||||||
<Table TableItem="Server" Items="Servers" PageSize="25" TableHeadClass="border-bottom border-gray-200 fs-6 text-gray-600 fw-bold bg-light bg-opacity-75">
|
<div class="table-responsive">
|
||||||
<Column TableItem="Server" Title="@(SmartTranslateService.Translate("Id"))" Field="@(x => x.Id)" Sortable="true" Filterable="true" Width="10%"/>
|
<Table TableItem="Server" Items="Servers" PageSize="25" TableClass="table table-row-bordered table-row-gray-100 align-middle gs-0 gy-3" TableHeadClass="fw-bold text-muted">
|
||||||
<Column TableItem="Server" Title="@(SmartTranslateService.Translate("Name"))" Field="@(x => x.Name)" Sortable="true" Filterable="true" Width="20%"/>
|
<Column TableItem="Server" Title="@(SmartTranslateService.Translate("Id"))" Field="@(x => x.Id)" Sortable="true" Filterable="true"/>
|
||||||
<Column TableItem="Server" Title="@(SmartTranslateService.Translate("Cores"))" Field="@(x => x.Cpu)" Sortable="true" Filterable="true" Width="20%"/>
|
<Column TableItem="Server" Title="@(SmartTranslateService.Translate("Name"))" Field="@(x => x.Name)" Sortable="true" Filterable="true"/>
|
||||||
<Column TableItem="Server" Title="@(SmartTranslateService.Translate("Memory"))" Field="@(x => x.Memory)" Sortable="true" Filterable="true" Width="20%"/>
|
<Column TableItem="Server" Title="@(SmartTranslateService.Translate("Cores"))" Field="@(x => x.Cpu)" Sortable="true" Filterable="true"/>
|
||||||
<Column TableItem="Server" Title="@(SmartTranslateService.Translate("Disk"))" Field="@(x => x.Disk)" Sortable="true" Filterable="true" Width="20%"/>
|
<Column TableItem="Server" Title="@(SmartTranslateService.Translate("Memory"))" Field="@(x => x.Memory)" Sortable="true" Filterable="true"/>
|
||||||
<Column TableItem="Server" Title="@(SmartTranslateService.Translate("Owner"))" Field="@(x => x.Owner)" Sortable="true" Filterable="true" Width="20%">
|
<Column TableItem="Server" Title="@(SmartTranslateService.Translate("Disk"))" Field="@(x => x.Disk)" Sortable="true" Filterable="true"/>
|
||||||
|
<Column TableItem="Server" Title="@(SmartTranslateService.Translate("Owner"))" Field="@(x => x.Owner)" Sortable="true" Filterable="true">
|
||||||
<Template>
|
<Template>
|
||||||
<a href="/admin/users/@(context.Owner.Id)/">@context.Owner.Email</a>
|
<a href="/admin/users/view/@(context.Owner.Id)/">@context.Owner.Email</a>
|
||||||
</Template>
|
</Template>
|
||||||
</Column>
|
</Column>
|
||||||
<Column TableItem="Server" Title="" Field="@(x => x.Id)" Sortable="false" Filterable="false" Width="20%">
|
<Column TableItem="Server" Title="" Field="@(x => x.Id)" Sortable="false" Filterable="false">
|
||||||
<Template>
|
<Template>
|
||||||
<a href="/admin/servers/edit/@(context.Id)">
|
<a href="/admin/servers/edit/@(context.Id)">
|
||||||
@(SmartTranslateService.Translate("Manage"))
|
@(SmartTranslateService.Translate("Manage"))
|
||||||
@@ -41,6 +47,7 @@
|
|||||||
</Column>
|
</Column>
|
||||||
<Pager ShowPageNumber="true" ShowTotalCount="true"/>
|
<Pager ShowPageNumber="true" ShowTotalCount="true"/>
|
||||||
</Table>
|
</Table>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -49,6 +56,7 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
</div>
|
</div>
|
||||||
</OnlyAdmin>
|
</OnlyAdmin>
|
||||||
|
|||||||
@@ -125,6 +125,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-5">
|
||||||
|
<div class="card card-body">
|
||||||
@if (Image != null)
|
@if (Image != null)
|
||||||
{
|
{
|
||||||
<div class="mt-9 row d-flex">
|
<div class="mt-9 row d-flex">
|
||||||
@@ -135,11 +137,15 @@
|
|||||||
{
|
{
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card card-body">
|
<div class="card card-body">
|
||||||
<label class="form-label"><TL>Name</TL></label>
|
<label class="form-label">
|
||||||
|
<TL>Name</TL>
|
||||||
|
</label>
|
||||||
<div class="input-group mb-5">
|
<div class="input-group mb-5">
|
||||||
<input @bind="variable.Key" type="text" class="form-control disabled" disabled="">
|
<input @bind="variable.Key" type="text" class="form-control disabled" disabled="">
|
||||||
</div>
|
</div>
|
||||||
<label class="form-label"><TL>Value</TL></label>
|
<label class="form-label">
|
||||||
|
<TL>Value</TL>
|
||||||
|
</label>
|
||||||
<div class="input-group mb-5">
|
<div class="input-group mb-5">
|
||||||
<input @bind="variable.Value" type="text" class="form-control">
|
<input @bind="variable.Value" type="text" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
@@ -150,12 +156,14 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="card card-body">
|
<div class="card card-body">
|
||||||
<div class="btn-group">
|
<div class="d-flex justify-content-end">
|
||||||
<a class="btn btn-primary" href="/admin/servers">
|
<a href="/admin/servers" class="btn btn-danger me-3">
|
||||||
<TL>Back</TL>
|
<TL>Cancel</TL>
|
||||||
</a>
|
</a>
|
||||||
<WButton Text="@(SmartTranslateService.Translate("Create"))"
|
<WButton Text="@(SmartTranslateService.Translate("Create"))"
|
||||||
WorkingText="@(SmartTranslateService.Translate("Creating"))"
|
WorkingText="@(SmartTranslateService.Translate("Creating"))"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<LazyLoader Load="Load">
|
<LazyLoader Load="Load">
|
||||||
<Table TableItem="LogEntry" Items="LogEntries" PageSize="25" TableHeadClass="border-bottom border-gray-200 fs-6 text-gray-600 fw-bold bg-light bg-opacity-75">
|
<Table TableItem="LogEntry" Items="LogEntries" PageSize="25" TableClass="table table-row-bordered table-row-gray-100 align-middle gs-0 gy-3" TableHeadClass="fw-bold text-muted">
|
||||||
<Column TableItem="LogEntry" Title="@(SmartTranslateService.Translate("Time"))" Field="@(x => x.CreatedAt)" Sortable="true" Filterable="false"></Column>
|
<Column TableItem="LogEntry" Title="@(SmartTranslateService.Translate("Time"))" Field="@(x => x.CreatedAt)" Sortable="true" Filterable="false"></Column>
|
||||||
<Column TableItem="LogEntry" Title="@(SmartTranslateService.Translate("Log level"))" Field="@(x => x.Level)" Sortable="true" Filterable="false"></Column>
|
<Column TableItem="LogEntry" Title="@(SmartTranslateService.Translate("Log level"))" Field="@(x => x.Level)" Sortable="true" Filterable="false"></Column>
|
||||||
<Column TableItem="LogEntry" Title="@(SmartTranslateService.Translate("Log message"))" Field="@(x => x.Message)" Sortable="false" Filterable="true"></Column>
|
<Column TableItem="LogEntry" Title="@(SmartTranslateService.Translate("Log message"))" Field="@(x => x.Message)" Sortable="false" Filterable="true"></Column>
|
||||||
|
|||||||
@@ -1,7 +1,66 @@
|
|||||||
@page "/admin/users"
|
@page "/admin/users"
|
||||||
|
|
||||||
@using Moonlight.Shared.Components.Navigations
|
@using Moonlight.Shared.Components.Navigations
|
||||||
|
@using Moonlight.App.Repositories
|
||||||
|
@using Moonlight.App.Database.Entities
|
||||||
|
@using BlazorTable
|
||||||
|
@using Moonlight.App.Services
|
||||||
|
|
||||||
|
@inject UserRepository UserRepository
|
||||||
|
@inject SmartTranslateService SmartTranslateService
|
||||||
|
|
||||||
<OnlyAdmin>
|
<OnlyAdmin>
|
||||||
<AdminSessionNavigation Index="0" />
|
<AdminSessionNavigation Index="0"/>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<LazyLoader Load="Load">
|
||||||
|
<div class="card-header border-0 pt-5">
|
||||||
|
<h3 class="card-title align-items-start flex-column">
|
||||||
|
<span class="card-label fw-bold fs-3 mb-1">
|
||||||
|
<TL>Users</TL>
|
||||||
|
</span>
|
||||||
|
</h3>
|
||||||
|
<div class="card-toolbar">
|
||||||
|
<a href="/admin/users/new" class="btn btn-sm btn-light-success">
|
||||||
|
<i class="bx bx-user-plus"></i>
|
||||||
|
<TL>New user</TL>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<Table TableItem="User" Items="Users" PageSize="25" TableClass="table table-row-bordered table-row-gray-100 align-middle gs-0 gy-3" TableHeadClass="fw-bold text-muted">
|
||||||
|
<Column TableItem="User" Title="@(SmartTranslateService.Translate("Id"))" Field="@(x => x.Id)" Sortable="true" Filterable="true"/>
|
||||||
|
<Column TableItem="User" Title="@(SmartTranslateService.Translate("Email"))" Field="@(x => x.Email)" Sortable="true" Filterable="true">
|
||||||
|
<Template>
|
||||||
|
<a href="/admin/users/view/@(context.Id)">@(context.Email)</a>
|
||||||
|
</Template>
|
||||||
|
</Column>
|
||||||
|
<Column TableItem="User" Title="@(SmartTranslateService.Translate("First name"))" Field="@(x => x.FirstName)" Sortable="true" Filterable="true"/>
|
||||||
|
<Column TableItem="User" Title="@(SmartTranslateService.Translate("Last name"))" Field="@(x => x.LastName)" Sortable="true" Filterable="true"/>
|
||||||
|
<Column TableItem="User" Title="@(SmartTranslateService.Translate("Created at"))" Field="@(x => x.CreatedAt)" Sortable="true" Filterable="true"/>
|
||||||
|
<Column TableItem="User" Title="@(SmartTranslateService.Translate("Manage"))" Field="@(x => x.Id)" Sortable="false" Filterable="false">
|
||||||
|
<Template>
|
||||||
|
<a href="/admin/users/@(context.Id)/edit">
|
||||||
|
<TL>Manage</TL>
|
||||||
|
</a>
|
||||||
|
</Template>
|
||||||
|
</Column>
|
||||||
|
<Pager ShowPageNumber="true" ShowTotalCount="true"/>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</LazyLoader>
|
||||||
|
</div>
|
||||||
</OnlyAdmin>
|
</OnlyAdmin>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
private User[] Users;
|
||||||
|
|
||||||
|
private async Task Load(LazyLoader lazyLoader)
|
||||||
|
{
|
||||||
|
Users = UserRepository.Get().ToArray();
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
66
Moonlight/Shared/Views/Admin/Users/New.razor
Normal file
66
Moonlight/Shared/Views/Admin/Users/New.razor
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
@page "/admin/users/new"
|
||||||
|
@using Moonlight.App.Database.Entities
|
||||||
|
@using Moonlight.App.Services
|
||||||
|
@using Moonlight.App.Services.Interop
|
||||||
|
|
||||||
|
@inject SmartTranslateService SmartTranslateService
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject ToastService ToastService
|
||||||
|
@inject UserService UserService
|
||||||
|
|
||||||
|
<OnlyAdmin>
|
||||||
|
<div class="row mb-5">
|
||||||
|
<div class="card card-body p-10">
|
||||||
|
<label class="form-label">
|
||||||
|
<TL>First name</TL>
|
||||||
|
</label>
|
||||||
|
<div class="input-group mb-5">
|
||||||
|
<input @bind="User.FirstName" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
|
<label class="form-label">
|
||||||
|
<TL>Last name</TL>
|
||||||
|
</label>
|
||||||
|
<div class="input-group mb-5">
|
||||||
|
<input @bind="User.LastName" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
|
<label class="form-label">
|
||||||
|
<TL>Email</TL>
|
||||||
|
</label>
|
||||||
|
<div class="input-group mb-5">
|
||||||
|
<input @bind="User.Email" type="email" class="form-control">
|
||||||
|
</div>
|
||||||
|
<label class="form-label">
|
||||||
|
<TL>Password</TL>
|
||||||
|
</label>
|
||||||
|
<div class="input-group mb-5">
|
||||||
|
<input @bind="User.Password" type="password" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="card card-body">
|
||||||
|
<div class="d-flex justify-content-end">
|
||||||
|
<a href="/admin/users" class="btn btn-danger me-3">
|
||||||
|
<TL>Cancel</TL>
|
||||||
|
</a>
|
||||||
|
<WButton Text="@(SmartTranslateService.Translate("Create"))"
|
||||||
|
WorkingText="@(SmartTranslateService.Translate("Creating"))"
|
||||||
|
CssClasses="btn-success"
|
||||||
|
OnClick="Create">
|
||||||
|
</WButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</OnlyAdmin>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
private User User = new();
|
||||||
|
|
||||||
|
private async Task Create()
|
||||||
|
{
|
||||||
|
await UserService.Register(User.Email, User.Password, User.FirstName, User.LastName);
|
||||||
|
await ToastService.Success(SmartTranslateService.Translate("User successfully created"));
|
||||||
|
NavigationManager.NavigateTo("/admin/users");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,15 +16,26 @@
|
|||||||
<OnlyAdmin>
|
<OnlyAdmin>
|
||||||
<AdminSessionNavigation Index="1"/>
|
<AdminSessionNavigation Index="1"/>
|
||||||
|
|
||||||
<div class="card card-body">
|
<div class="card">
|
||||||
<LazyLoader Load="Load">
|
<LazyLoader Load="Load">
|
||||||
<button class="btn btn-primary mb-3" @onclick="Refresh">
|
<div class="card-header border-0 pt-5">
|
||||||
|
<h3 class="card-title align-items-start flex-column">
|
||||||
|
<span class="card-label fw-bold fs-3 mb-1">
|
||||||
|
<TL>Sessions</TL>
|
||||||
|
</span>
|
||||||
|
</h3>
|
||||||
|
<div class="card-toolbar">
|
||||||
|
<button class="btn btn-sm btn-primary me-3" @onclick="Refresh">
|
||||||
|
<i class="bx bx-revision"></i>
|
||||||
<TL>Refresh</TL>
|
<TL>Refresh</TL>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-warning mb-3" @onclick="MessageAll">
|
<button class="btn btn-sm btn-warning" @onclick="MessageAll">
|
||||||
|
<i class="bx bx-message-square-dots"></i>
|
||||||
<TL>Send a message to all users</TL>
|
<TL>Send a message to all users</TL>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body pt-0">
|
||||||
@if (AllSessions == null)
|
@if (AllSessions == null)
|
||||||
{
|
{
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
@@ -34,10 +45,17 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<Table TableItem="Session" Items="AllSessions" PageSize="25" TableHeadClass="border-bottom border-gray-200 fs-6 text-gray-600 fw-bold bg-light bg-opacity-75">
|
<Table TableItem="Session" Items="AllSessions" PageSize="25" TableClass="table table-row-bordered table-row-gray-100 align-middle gs-0 gy-3" TableHeadClass="fw-bold text-muted">
|
||||||
<Column TableItem="Session" Title="@(SmartTranslateService.Translate("Email"))" Field="@(x => x.User.Id)" Sortable="true" Filterable="true" Width="20%">
|
<Column TableItem="Session" Title="@(SmartTranslateService.Translate("Email"))" Field="@(x => x.User.Id)" Sortable="true" Filterable="true" Width="20%">
|
||||||
<Template>
|
<Template>
|
||||||
<span>@(context.User == null ? "" : context.User.Email)</span>
|
@if (context.User == null)
|
||||||
|
{
|
||||||
|
<TL>Guest</TL>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a href="/admin/users/view/@(context.User.Id)">@(context.User.Email)</a>
|
||||||
|
}
|
||||||
</Template>
|
</Template>
|
||||||
</Column>
|
</Column>
|
||||||
<Column TableItem="Session" Title="@(SmartTranslateService.Translate("IP"))" Field="@(x => x.Ip)" Sortable="true" Filterable="true" Width="10%"/>
|
<Column TableItem="Session" Title="@(SmartTranslateService.Translate("IP"))" Field="@(x => x.Ip)" Sortable="true" Filterable="true" Width="10%"/>
|
||||||
@@ -53,14 +71,14 @@
|
|||||||
</Column>
|
</Column>
|
||||||
<Column TableItem="Session" Title="@(SmartTranslateService.Translate("Actions"))" Field="@(x => x.Ip)" Sortable="false" Filterable="false" Width="10%">
|
<Column TableItem="Session" Title="@(SmartTranslateService.Translate("Actions"))" Field="@(x => x.Ip)" Sortable="false" Filterable="false" Width="10%">
|
||||||
<Template>
|
<Template>
|
||||||
<button @onclick="() => Navigate(context)" class="btn btn-primary">
|
<button @onclick="() => Navigate(context)" class="btn btn-sm btn-primary">
|
||||||
<TL>Change url</TL>
|
<TL>Change url</TL>
|
||||||
</button>
|
</button>
|
||||||
</Template>
|
</Template>
|
||||||
</Column>
|
</Column>
|
||||||
<Column TableItem="Session" Title="" Field="@(x => x.Ip)" Sortable="false" Filterable="false" Width="10%">
|
<Column TableItem="Session" Title="" Field="@(x => x.Ip)" Sortable="false" Filterable="false" Width="10%">
|
||||||
<Template>
|
<Template>
|
||||||
<button @onclick="() => Message(context)" class="btn btn-warning">
|
<button @onclick="() => Message(context)" class="btn btn-sm btn-warning">
|
||||||
<TL>Message</TL>
|
<TL>Message</TL>
|
||||||
</button>
|
</button>
|
||||||
</Template>
|
</Template>
|
||||||
@@ -68,6 +86,7 @@
|
|||||||
<Pager ShowPageNumber="true" ShowTotalCount="true"/>
|
<Pager ShowPageNumber="true" ShowTotalCount="true"/>
|
||||||
</Table>
|
</Table>
|
||||||
}
|
}
|
||||||
|
</div>
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
</div>
|
</div>
|
||||||
</OnlyAdmin>
|
</OnlyAdmin>
|
||||||
@@ -110,7 +129,7 @@
|
|||||||
{
|
{
|
||||||
var url = await AlertService.Text("URL", SmartTranslateService.Translate("Enter url"), "");
|
var url = await AlertService.Text("URL", SmartTranslateService.Translate("Enter url"), "");
|
||||||
|
|
||||||
if(url == null)
|
if (url == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (url == "")
|
if (url == "")
|
||||||
|
|||||||
261
Moonlight/Shared/Views/Admin/Users/View.razor
Normal file
261
Moonlight/Shared/Views/Admin/Users/View.razor
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
@page "/admin/users/view/{Id:int}"
|
||||||
|
@using Moonlight.App.Database.Entities
|
||||||
|
@using Moonlight.App.Helpers
|
||||||
|
@using Moonlight.App.Repositories
|
||||||
|
@using Moonlight.App.Repositories.Servers
|
||||||
|
@using Microsoft.EntityFrameworkCore
|
||||||
|
@using Moonlight.App.Repositories.Domains
|
||||||
|
|
||||||
|
@inject UserRepository UserRepository
|
||||||
|
@inject ServerRepository ServerRepository
|
||||||
|
@inject DomainRepository DomainRepository
|
||||||
|
|
||||||
|
<OnlyAdmin>
|
||||||
|
<LazyLoader Load="Load">
|
||||||
|
@if (User == null)
|
||||||
|
{
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<TL>No user with this id found</TL>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card card-body mb-5">
|
||||||
|
<div class="d-flex flex-column align-items-center text-center">
|
||||||
|
<img src="/api/moonlight/avatar/@(User.Id)" class="rounded-circle" alt="Profile picture" width="150">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card card-body mb-5">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a class="btn btn-primary" href="/admin/users/edit/@(User.Id)"><TL>Edit</TL></a>
|
||||||
|
<a class="btn btn-secondary" href="/admin/users"><TL>Back to list</TL></a>
|
||||||
|
<a class="btn btn-primary" href="/admin/support/view/@(User.Id)"><TL>Open support</TL></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card card-xl-stretch mb-5">
|
||||||
|
<div class="card-header border-0">
|
||||||
|
<h3 class="card-title fw-bold text-dark">
|
||||||
|
<TL>Servers</TL>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body pt-2">
|
||||||
|
@foreach (var server in Servers)
|
||||||
|
{
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<a href="/server/@(server.Uuid)" class="fs-6">@(server.Name) - @(server.Image.Name)</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
if (server != Servers.Last())
|
||||||
|
{
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card card-xl-stretch">
|
||||||
|
<div class="card-header border-0">
|
||||||
|
<h3 class="card-title fw-bold text-dark">
|
||||||
|
<TL>Domains</TL>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body pt-2">
|
||||||
|
@foreach (var domain in Domains)
|
||||||
|
{
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<a href="/domain/@(domain.Id)" class="fs-6">@(domain.Name).@(domain.SharedDomain.Name)</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
if (domain != Domains.Last())
|
||||||
|
{
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-body fs-6">
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-lg-4 fw-semibold text-muted">
|
||||||
|
<TL>First name</TL>
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<span class="fw-bold fs-6 text-gray-800">@(User.FirstName)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-lg-4 fw-semibold text-muted">
|
||||||
|
<TL>Last name</TL>
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<span class="fw-bold fs-6 text-gray-800">@(User.LastName)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-lg-4 fw-semibold text-muted">
|
||||||
|
<TL>Email</TL>
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<span class="fw-bold fs-6 text-gray-800">@(User.Email)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-lg-4 fw-semibold text-muted">
|
||||||
|
<TL>Address</TL>
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<span class="fw-bold fs-6 text-gray-800">@(User.Address)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-lg-4 fw-semibold text-muted">
|
||||||
|
<TL>City</TL>
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<span class="fw-bold fs-6 text-gray-800">@(User.City)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-lg-4 fw-semibold text-muted">
|
||||||
|
<TL>State</TL>
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<span class="fw-bold fs-6 text-gray-800">@(User.State)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-lg-4 fw-semibold text-muted">
|
||||||
|
<TL>Country</TL>
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<span class="fw-bold fs-6 text-gray-800">@(User.Country)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-lg-4 fw-semibold text-muted">
|
||||||
|
<TL>Admin</TL>
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<span class="fw-bold fs-6 text-gray-800">
|
||||||
|
@if (User.Admin)
|
||||||
|
{
|
||||||
|
<span>✅</span>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<span>❌</span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-lg-4 fw-semibold text-muted">
|
||||||
|
<TL>Status</TL>
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<span class="fw-bold fs-6 text-gray-800">@(User.Status)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-lg-4 fw-semibold text-muted">
|
||||||
|
<TL>Totp</TL>
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<span class="fw-bold fs-6 text-gray-800">@(User.TotpEnabled)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-lg-4 fw-semibold text-muted">
|
||||||
|
<TL>Discord</TL>
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<span class="fw-bold fs-6 text-gray-800">@(User.DiscordUsername)#@(User.DiscordDiscriminator)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-lg-4 fw-semibold text-muted">
|
||||||
|
<TL>Subscription</TL>
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<span class="fw-bold fs-6 text-gray-800">
|
||||||
|
@if (User.Subscription == null)
|
||||||
|
{
|
||||||
|
<span>
|
||||||
|
<TL>None</TL>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<span>@(User.Subscription.Name)</span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="separator my-4"></div>
|
||||||
|
<div class="row">
|
||||||
|
<label class="col-lg-4 fw-semibold text-muted">
|
||||||
|
<TL>Created at</TL>
|
||||||
|
</label>
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<span class="fw-bold fs-6 text-gray-800">@(Formatter.FormatDate(User.CreatedAt))</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</LazyLoader>
|
||||||
|
</OnlyAdmin>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
[Parameter]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
private User? User;
|
||||||
|
private Server[] Servers;
|
||||||
|
private Domain[] Domains;
|
||||||
|
|
||||||
|
private Task Load(LazyLoader arg)
|
||||||
|
{
|
||||||
|
User = UserRepository.Get().FirstOrDefault(x => x.Id == Id);
|
||||||
|
|
||||||
|
if (User != null)
|
||||||
|
{
|
||||||
|
Servers = ServerRepository
|
||||||
|
.Get()
|
||||||
|
.Include(x => x.Owner)
|
||||||
|
.Include(x => x.Image)
|
||||||
|
.Where(x => x.Owner.Id == User.Id)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
Domains = DomainRepository
|
||||||
|
.Get()
|
||||||
|
.Include(x => x.SharedDomain)
|
||||||
|
.Include(x => x.Owner)
|
||||||
|
.Where(x => x.Owner.Id == User.Id)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Moonlight/Shared/Views/Test.razor
Normal file
2
Moonlight/Shared/Views/Test.razor
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
@page "/test"
|
||||||
|
|
||||||
@@ -306,3 +306,20 @@ WinSCP cannot be launched here;WinSCP cannot be launched here
|
|||||||
Create a new folder;Create a new folder
|
Create a new folder;Create a new folder
|
||||||
Enter a name;Enter a name
|
Enter a name;Enter a name
|
||||||
File upload complete;File upload complete
|
File upload complete;File upload complete
|
||||||
|
New server;New server
|
||||||
|
Sessions;Sessions
|
||||||
|
New user;New user
|
||||||
|
Created at;Created at
|
||||||
|
Mail template not found;Mail template not found
|
||||||
|
Missing admin permissions. This attempt has been logged ;)
|
||||||
|
Address;Address
|
||||||
|
City;City
|
||||||
|
State;State
|
||||||
|
Country;Country
|
||||||
|
Totp;Totp
|
||||||
|
Discord;Discord
|
||||||
|
Subscription;Subscription
|
||||||
|
None;None
|
||||||
|
No user with this id found;No user with this id found
|
||||||
|
Back to list;Back to list
|
||||||
|
New domain;New domain
|
||||||
|
|||||||
50
Moonlight/resources/mail/register.html
Normal file
50
Moonlight/resources/mail/register.html
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Welcome</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div style="background-color:#ffffff; padding: 45px 0 34px 0; border-radius: 24px; margin:40px auto; max-width: 600px;">
|
||||||
|
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" height="auto"
|
||||||
|
style="border-collapse:collapse">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="center" style="text-align:center; padding-bottom: 10px">
|
||||||
|
<div style="text-align:center; margin:0 15px 34px 15px">
|
||||||
|
<div style="margin-bottom: 10px">
|
||||||
|
<a href="https://endelon-hosting.de" rel="noopener" target="_blank">
|
||||||
|
<img alt="Logo" src="https://moonlight.endelon-hosting.de/assets/media/logo/MoonFullText.png" style="height: 35px">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 14px; font-weight: 500; margin-bottom: 27px; font-family:Arial,Helvetica,sans-serif;">
|
||||||
|
<p style="margin-bottom:9px; color:#181C32; font-size: 22px; font-weight:700">Hey {{FirstName}}, welcome to moonlight</p>
|
||||||
|
<p style="margin-bottom:2px; color:#7E8299">We are happy to welcome you in ;)</p>
|
||||||
|
</div>
|
||||||
|
<a href="https://moonlight.endelon-hosting.de" target="_blank"
|
||||||
|
style="background-color:#50cd89; border-radius:6px;display:inline-block; padding:11px 19px; color: #FFFFFF; font-size: 14px; font-weight:500;">Open Moonlight
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="center"
|
||||||
|
style="font-size: 13px; text-align:center; padding: 0 10px 10px 10px; font-weight: 500; color: #A1A5B7; font-family:Arial,Helvetica,sans-serif">
|
||||||
|
<p style="color:#181C32; font-size: 16px; font-weight: 600; margin-bottom:9px">You need help?</p>
|
||||||
|
<p style="margin-bottom:2px">We are happy to help!</p>
|
||||||
|
<p style="margin-bottom:4px">More information at
|
||||||
|
<a href="https://endelon.link/support" rel="noopener" target="_blank" style="font-weight: 600">endelon.link/support</a>.
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" valign="center"
|
||||||
|
style="font-size: 13px; padding:0 15px; text-align:center; font-weight: 500; color: #A1A5B7;font-family:Arial,Helvetica,sans-serif">
|
||||||
|
<p>Copyright 2022 Endelon Hosting </p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user