Merge branch 'Eric' into 'master'
Merge Eric into Master See merge request limited_dev/imageboard!4
This commit is contained in:
commit
b63eb1973c
59 changed files with 1309 additions and 376 deletions
25
.dockerignore
Normal file
25
.dockerignore
Normal file
|
@ -0,0 +1,25 @@
|
|||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/.idea
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/azds.yaml
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
LICENSE
|
||||
README.md
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,7 +1,10 @@
|
|||
.idea/
|
||||
ImageBoardServerApp/bin/
|
||||
ImageBoardServerApp/obj/
|
||||
ImageBoardServerApp/wwwroot/img/dynamic
|
||||
*.db
|
||||
*.db-shm
|
||||
*.db-wal
|
||||
Migrations/
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
<Router AppAssembly="@typeof(App).Assembly">
|
||||
<Found Context="routeData">
|
||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
|
||||
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
|
||||
</Found>
|
||||
<NotFound>
|
||||
<PageTitle>Not found</PageTitle>
|
||||
<LayoutView Layout="@typeof(MainLayout)">
|
||||
<h3>404</h3>
|
||||
<div class="Error404">
|
||||
<img src="static/1.jpeg" alt="noimageFound"/>
|
||||
<p role="alert">Sorry, nothing found. Please go back to the main page. Or watch the tree and find the hidden Cat..</p>
|
||||
</div>
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
<CascadingAuthenticationState>
|
||||
<Router AppAssembly="@typeof(App).Assembly">
|
||||
<Found Context="routeData">
|
||||
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
|
||||
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
|
||||
</Found>
|
||||
<NotFound>
|
||||
<PageTitle>Not found</PageTitle>
|
||||
<LayoutView Layout="@typeof(MainLayout)">
|
||||
<h3>404</h3>
|
||||
<div class="Error404">
|
||||
<img src="img/static/err/1.jpeg" alt="noimageFound"/>
|
||||
<p role="alert">Sorry, nothing found. Please go back to the main page. Or watch the tree and find the hidden Cat..</p>
|
||||
</div>
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
</CascadingAuthenticationState>
|
|
@ -0,0 +1,61 @@
|
|||
using System.Security.Claims;
|
||||
using ImageBoardServerApp.Data;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
|
||||
|
||||
namespace ImageBoardServerApp.Auth;
|
||||
|
||||
public class CustomAuthenticationStateProvider : AuthenticationStateProvider
|
||||
{
|
||||
private readonly ProtectedSessionStorage _sessionStorage;
|
||||
private ClaimsPrincipal _anonymous = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
|
||||
public CustomAuthenticationStateProvider(ProtectedSessionStorage sessionStorage)
|
||||
{
|
||||
_sessionStorage = sessionStorage;
|
||||
}
|
||||
|
||||
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var userSessionStorageResult = await _sessionStorage.GetAsync<UserData>("UserSession");
|
||||
var userSession = userSessionStorageResult.Success ? userSessionStorageResult.Value : null;
|
||||
if (userSession == null)
|
||||
return await Task.FromResult(new AuthenticationState(_anonymous));
|
||||
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
|
||||
{
|
||||
//new Claim(ClaimTypes.Email, userSession.Email),
|
||||
new Claim(ClaimTypes.Name, userSession.Email),
|
||||
new Claim(ClaimTypes.Role, userSession.Role)
|
||||
}, "CustomAuth"));
|
||||
return await Task.FromResult(new AuthenticationState(claimsPrincipal));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return await Task.FromResult(new AuthenticationState(_anonymous));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateAuthenticationStateAsync(UserData session)
|
||||
{
|
||||
ClaimsPrincipal claimsPrincipal;
|
||||
|
||||
if (session != null)
|
||||
{
|
||||
await _sessionStorage.SetAsync("UserSession", session);
|
||||
claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.Email, session.Email),
|
||||
new Claim(ClaimTypes.Email, session.Role)
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
await _sessionStorage.DeleteAsync("UserSession");
|
||||
claimsPrincipal = _anonymous;
|
||||
}
|
||||
|
||||
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(claimsPrincipal)));
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace ImageBoardServerApp.Data;
|
||||
|
||||
public class AccountData
|
||||
{
|
||||
[Required]
|
||||
[DatabaseGenerated((DatabaseGeneratedOption.Identity))]
|
||||
[Key]
|
||||
public int AccountID { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Password { get; set; }
|
||||
|
||||
[Required]
|
||||
public int PermissionInteger { get; set; }
|
||||
}
|
|
@ -8,7 +8,7 @@ internal sealed class AppDBContext : DbContext
|
|||
public DbSet<PostData> Posts { get; set; }
|
||||
public DbSet<ImageData> Images { get; set; }
|
||||
public DbSet<CommentData> Comments { get; set; }
|
||||
public DbSet<AccountData> Accounts { get; set; }
|
||||
public DbSet<ReportData> Reports { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
=> optionsBuilder.UseSqlite("Data Source=./Data/Nils.db");
|
||||
|
@ -32,5 +32,18 @@ internal sealed class AppDBContext : DbContext
|
|||
mb.Entity<UserData>()
|
||||
.HasMany(user => user.Comments)
|
||||
.WithOne(comment => comment.User);
|
||||
|
||||
mb.Entity<ReportData>()
|
||||
.HasOne(report => report.UserReported)
|
||||
.WithMany(user => user.RecivedReports);
|
||||
mb.Entity<ReportData>()
|
||||
.HasOne(report => report.UserReporter)
|
||||
.WithMany(user => user.SubmittedReports);
|
||||
mb.Entity<ReportData>()
|
||||
.HasOne(report => report.ReportedPost)
|
||||
.WithOne(post => post.Report);
|
||||
mb.Entity<ReportData>()
|
||||
.HasOne(report => report.ReportedComment)
|
||||
.WithOne(comment => comment.Report);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using ImageBoardServerApp.Shared.Components;
|
||||
|
||||
namespace ImageBoardServerApp.Data;
|
||||
|
||||
|
@ -21,12 +20,12 @@ public class CommentData
|
|||
public int UserID { get; set; }
|
||||
|
||||
//[ForeignKey("UserID")]
|
||||
public UserData User { get; set; }
|
||||
public virtual UserData User { get; set; }
|
||||
|
||||
//[ForeignKey("ImageID")]
|
||||
public virtual ImageData Image { get; set; }
|
||||
|
||||
public int ImageID { get; set; }
|
||||
public virtual ImageData? Image { get; set; }
|
||||
|
||||
public int? ImageID { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Content { get; set; }
|
||||
|
@ -37,4 +36,9 @@ public class CommentData
|
|||
[Required]
|
||||
public string Board { get; set; }
|
||||
|
||||
[Required]
|
||||
public long CreatedAt { get; set; }
|
||||
|
||||
public ReportData? Report { get; set; }
|
||||
|
||||
}
|
|
@ -15,7 +15,7 @@ public class ImageData
|
|||
public string Board { get; set; }
|
||||
|
||||
[Required]
|
||||
public Byte[] Image { get; set; }
|
||||
public string ImageLocation { get; set; }
|
||||
|
||||
public PostData Post { get; set; }
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ public class PostData
|
|||
[Required]
|
||||
public string Content { get; set; }
|
||||
|
||||
public string Interactions { get; set; }
|
||||
public int Interactions { get; set; }
|
||||
|
||||
[Required]
|
||||
public long CreatedAt { get; set; }
|
||||
|
@ -40,4 +40,6 @@ public class PostData
|
|||
public string Board { get; set; }
|
||||
|
||||
public List<CommentData> Comments { get; set; }
|
||||
|
||||
public ReportData? Report { get; set; }
|
||||
}
|
42
ImageBoardServerApp/Data/ReportData.cs
Normal file
42
ImageBoardServerApp/Data/ReportData.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace ImageBoardServerApp.Data;
|
||||
|
||||
public class ReportData
|
||||
{
|
||||
[Required]
|
||||
[DatabaseGenerated((DatabaseGeneratedOption.Identity))]
|
||||
[Key]
|
||||
public int ReportID { get; set; }
|
||||
|
||||
[Required]
|
||||
public int UserReportedID { get; set; }
|
||||
|
||||
[Required]
|
||||
public UserData UserReported { get; set; }
|
||||
|
||||
[Required]
|
||||
public int UserReporterID { get; set; }
|
||||
|
||||
[Required]
|
||||
public UserData UserReporter { get; set; }
|
||||
|
||||
public int? ReportedCommentID { get; set; }
|
||||
|
||||
public CommentData? ReportedComment { get; set; }
|
||||
|
||||
public int? ReportedPostID { get; set; }
|
||||
|
||||
public PostData? ReportedPost { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Type { get; set; }
|
||||
|
||||
[Required]
|
||||
public string ReportReason { get; set; }
|
||||
|
||||
public string ReportExlaination { get; set; }
|
||||
|
||||
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ImageBoardServerApp.Data.Repository;
|
||||
|
||||
public static class AccountsRepository
|
||||
{
|
||||
public static async Task<List<AccountData>> getAccountsAsync()
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
return await db.Accounts.ToListAsync();
|
||||
}
|
||||
|
||||
public static async Task<List<AccountData>> getAccountsByMailAsync(string email)
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
return await db.Accounts
|
||||
.Where(acc => acc.Email.Equals(email))
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public static async Task<AccountData> getAccountByIdAsync(int accountId)
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
return await db.Accounts.FirstOrDefaultAsync(post => post.AccountID == accountId);
|
||||
}
|
||||
|
||||
public static async Task<int> createAccountAsync(AccountData accountToCreate)
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
await db.Accounts.AddAsync(accountToCreate);
|
||||
if (await db.SaveChangesAsync() >= 1)
|
||||
{
|
||||
Console.WriteLine($"Created post with ID: {accountToCreate.AccountID}");
|
||||
return accountToCreate.AccountID;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static async Task<bool> updateAccountAsync(AccountData accountToUpdate)
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
db.Accounts.Update(accountToUpdate);
|
||||
return await db.SaveChangesAsync() >= 1;
|
||||
}
|
||||
|
||||
public static async Task<bool> deleteAccountAsync(int postId)
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
AccountData accountToDelete = await getAccountByIdAsync(postId);
|
||||
db.Remove(accountToDelete);
|
||||
return await db.SaveChangesAsync() >= 1;
|
||||
}
|
||||
}
|
|
@ -22,8 +22,23 @@ public static class CommentsRepository
|
|||
public static async Task<CommentData> getCommentByIdAsync(int postId)
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
return await db.Comments.FirstOrDefaultAsync(comment => comment.PostID == postId);
|
||||
return await db.Comments
|
||||
.Where(comment => comment.CommentID == postId)
|
||||
.Include(comment => comment.Image)
|
||||
.Include(comment => comment.Post)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
/*public static async Task<PostData> getPostByIdAsync(int postId)
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
return await db.Posts
|
||||
.Where(post => post.PostID == postId)
|
||||
.Include(post => post.Image)
|
||||
.Include(post => post.Comments)
|
||||
.FirstOrDefaultAsync();
|
||||
//return await db.Posts.FirstOrDefaultAsync(post => post.PostID == postId);
|
||||
}*/
|
||||
|
||||
public static async Task<int> createCommentAsync(CommentData commentData)
|
||||
{
|
||||
|
|
|
@ -16,13 +16,21 @@ public static class PostsRepository
|
|||
return await db.Posts
|
||||
.Where(post => post.Board.Equals(board))
|
||||
.Include(post => post.Image)
|
||||
.Include(post => post.Comments)
|
||||
.Include(post => post.User)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public static async Task<PostData> getPostByIdAsync(int postId)
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
return await db.Posts.FirstOrDefaultAsync(post => post.PostID == postId);
|
||||
return await db.Posts
|
||||
.Where(post => post.PostID == postId)
|
||||
.Include(post => post.Image)
|
||||
.Include(post => post.Comments)
|
||||
.Include(post => post.User)
|
||||
.FirstOrDefaultAsync();
|
||||
//return await db.Posts.FirstOrDefaultAsync(post => post.PostID == postId);
|
||||
}
|
||||
|
||||
public static async Task<int> createPostAsync(PostData postToCreate)
|
||||
|
|
45
ImageBoardServerApp/Data/Repository/ReportsRepository.cs
Normal file
45
ImageBoardServerApp/Data/Repository/ReportsRepository.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ImageBoardServerApp.Data.Repository;
|
||||
|
||||
public static class ReportsRepository
|
||||
{
|
||||
public static async Task<List<ReportData>> getReportsAsync()
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
return await db.Reports.ToListAsync();
|
||||
}
|
||||
|
||||
public static async Task<ReportData> getReportByIdAsync(int reportId)
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
return await db.Reports.FirstOrDefaultAsync(report => report.ReportID == reportId);
|
||||
}
|
||||
|
||||
public static async Task<int> createReportAsync(ReportData reportData)
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
await db.Reports.AddAsync(reportData);
|
||||
if (await db.SaveChangesAsync() >= 1)
|
||||
{
|
||||
return reportData.ReportID;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static async Task<bool> updateReportAsync(ReportData reportData)
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
db.Reports.Update(reportData);
|
||||
return await db.SaveChangesAsync() >= 1;
|
||||
}
|
||||
|
||||
public static async Task<bool> deleteReportAsync(int reportId)
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
ReportData reportData = await getReportByIdAsync(reportId);
|
||||
db.Remove(reportData);
|
||||
return await db.SaveChangesAsync() >= 1;
|
||||
}
|
||||
}
|
|
@ -15,6 +15,12 @@ public static class UsersRepository
|
|||
await using var db = new AppDBContext();
|
||||
return await db.Users.FirstOrDefaultAsync(user => user.UserID == userId);
|
||||
}
|
||||
|
||||
public static async Task<UserData> getUserByEmailAsync(string email)
|
||||
{
|
||||
await using var db = new AppDBContext();
|
||||
return await db.Users.FirstOrDefaultAsync(user => user.Email == email);
|
||||
}
|
||||
|
||||
public static async Task<int> createUserAsync(UserData userToCreate)
|
||||
{
|
||||
|
|
|
@ -11,12 +11,9 @@ public class UserData
|
|||
[DatabaseGenerated((DatabaseGeneratedOption.Identity))]
|
||||
[Key]
|
||||
public int UserID { get; set; }
|
||||
|
||||
|
||||
[Required]
|
||||
public string Ipv4Address { get; set; }
|
||||
|
||||
[Required]
|
||||
public bool Banned { get; set; }
|
||||
public long TimeBanned { get; set; }
|
||||
|
||||
[Required]
|
||||
public long lastActionTimeStamp { get; set; }
|
||||
|
@ -24,4 +21,20 @@ public class UserData
|
|||
public List<PostData> Posts { get; set; }
|
||||
|
||||
public List<CommentData> Comments { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Password { get; set; }
|
||||
|
||||
[Required]
|
||||
public int PermissionInteger { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Role { get; set; }
|
||||
|
||||
public List<ReportData> SubmittedReports { get; set; }
|
||||
|
||||
public List<ReportData> RecivedReports { get; set; }
|
||||
}
|
20
ImageBoardServerApp/Dockerfile
Normal file
20
ImageBoardServerApp/Dockerfile
Normal file
|
@ -0,0 +1,20 @@
|
|||
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["ImageBoardServerApp/ImageBoardServerApp.csproj", "ImageBoardServerApp/"]
|
||||
RUN dotnet restore "ImageBoardServerApp/ImageBoardServerApp.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/BlazorServerTest"
|
||||
RUN dotnet build "BlazorServerTest.csproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "ImageBoardServerApp.csproj" -c Release -o /app/publish
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "ImageBoardServerApp.dll"]
|
|
@ -19,7 +19,8 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\static" />
|
||||
<Folder Include="wwwroot\img\dynamic\comment\m" />
|
||||
<Folder Include="wwwroot\img\dynamic\op\m" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
50
ImageBoardServerApp/Pages/Accounts/Login.razor
Normal file
50
ImageBoardServerApp/Pages/Accounts/Login.razor
Normal file
|
@ -0,0 +1,50 @@
|
|||
@page "/login"
|
||||
@using ImageBoardServerApp.Data.Repository
|
||||
@using ImageBoardServerApp.Auth
|
||||
@inject IJSRuntime js
|
||||
@inject AuthenticationStateProvider authStateProvider
|
||||
@inject NavigationManager navManager
|
||||
|
||||
<h3>Login to bulletbroards</h3>
|
||||
<div>
|
||||
<form>
|
||||
<div>
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" id="email" @bind="Email" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" @bind="Password" />
|
||||
</div>
|
||||
<a @onclick="login" href="javascript:void(0)">[Login]</a>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@code {
|
||||
private string Email { get; set; }
|
||||
private string Password { get; set; }
|
||||
|
||||
private bool verified;
|
||||
|
||||
private async Task login()
|
||||
{
|
||||
Console.WriteLine("loggin you in...");
|
||||
var user = await UsersRepository.getUserByEmailAsync(Email);
|
||||
if (user == null)
|
||||
{
|
||||
await js.InvokeVoidAsync("alert", "User does not exist");
|
||||
verified = false;
|
||||
return;
|
||||
}
|
||||
verified = BCrypt.Net.BCrypt.Verify(Password, user.Password);
|
||||
if (verified)
|
||||
{
|
||||
verified = true;
|
||||
var customAuthStateProvider = (CustomAuthenticationStateProvider)authStateProvider;
|
||||
await customAuthStateProvider.UpdateAuthenticationStateAsync(user);
|
||||
navManager.NavigateTo("/", true);
|
||||
return;
|
||||
}
|
||||
await js.InvokeVoidAsync("alert", $"Wrong Password");
|
||||
}
|
||||
}
|
67
ImageBoardServerApp/Pages/Accounts/Register.razor
Normal file
67
ImageBoardServerApp/Pages/Accounts/Register.razor
Normal file
|
@ -0,0 +1,67 @@
|
|||
@page "/register"
|
||||
@using ImageBoardServerApp.Data.Repository
|
||||
@using ImageBoardServerApp.Auth
|
||||
@inject IJSRuntime js
|
||||
@inject AuthenticationStateProvider authStateProvider
|
||||
@inject NavigationManager navManager
|
||||
|
||||
<h3>Register to bulletbroards</h3>
|
||||
<div>
|
||||
<form>
|
||||
<div>
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" id="email" @bind="Email" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" @bind="Password" />
|
||||
</div>
|
||||
<a @onclick="login" href="javascript:void(0)">[Register]</a>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@code {
|
||||
private string Email { get; set; }
|
||||
private string Password { get; set; }
|
||||
|
||||
private bool verified;
|
||||
|
||||
private async Task login()
|
||||
{
|
||||
Console.WriteLine("Registering...");
|
||||
UserData userToCreate = new UserData()
|
||||
{
|
||||
Email = Email,
|
||||
Password = BCrypt.Net.BCrypt.HashPassword(Password),
|
||||
Role = "User",
|
||||
PermissionInteger = 1,
|
||||
TimeBanned = -1
|
||||
};
|
||||
if (await UsersRepository.getUserByEmailAsync(Email) != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await UsersRepository.createUserAsync(userToCreate);
|
||||
Console.WriteLine("loggin you in...");
|
||||
var user = await UsersRepository.getUserByEmailAsync(Email);
|
||||
if (user == null)
|
||||
{
|
||||
await js.InvokeVoidAsync("alert", "User does not exist");
|
||||
verified = false;
|
||||
return;
|
||||
}
|
||||
verified = BCrypt.Net.BCrypt.Verify(Password, user.Password);
|
||||
if (verified)
|
||||
{
|
||||
verified = true;
|
||||
var customAuthStateProvider = (CustomAuthenticationStateProvider)authStateProvider;
|
||||
await customAuthStateProvider.UpdateAuthenticationStateAsync(user);
|
||||
navManager.NavigateTo("/", true);
|
||||
return;
|
||||
}
|
||||
await js.InvokeVoidAsync("alert", $"Wrong Password");
|
||||
}
|
||||
}
|
||||
@code {
|
||||
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
@page "/b/"
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using ImageBoardServerApp.Data
|
||||
|
||||
<Board board="@b"/>
|
||||
|
||||
@code {
|
||||
|
||||
private BoardData b { get; set; } = new()
|
||||
{
|
||||
BoardID = 0,
|
||||
maxThreads = 10,
|
||||
Tag = "b",
|
||||
Topic = "Random"
|
||||
};
|
||||
}
|
40
ImageBoardServerApp/Pages/Basic/Index.razor
Normal file
40
ImageBoardServerApp/Pages/Basic/Index.razor
Normal file
|
@ -0,0 +1,40 @@
|
|||
@page "/"
|
||||
@using ImageBoardServerApp.Data.Repository
|
||||
@using ImageBoardServerApp.Auth
|
||||
@inject AuthenticationStateProvider authStateProvider
|
||||
|
||||
<h1>BulletBoard</h1>
|
||||
<span>This is a simple Imageboard made in Razor.</span>
|
||||
<br/>
|
||||
<span>We're currently hosting @amountOfPosts Threads, @amountOfComments Comments and @amountOfUsers Users.</span>
|
||||
<sr/>
|
||||
<span>@Details</span>
|
||||
|
||||
@code{
|
||||
private string Details { get; set; }
|
||||
|
||||
private int amountOfPosts = -1;
|
||||
private int amountOfComments = -1;
|
||||
private int amountOfUsers = -1;
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var cauthStateProvder = (CustomAuthenticationStateProvider)authStateProvider;
|
||||
var user = await cauthStateProvder.GetAuthenticationStateAsync();
|
||||
if (user.User.Identity.IsAuthenticated)
|
||||
{
|
||||
var usr = user.User.Identity.Name;
|
||||
Details = $"Welcome {usr}";
|
||||
}
|
||||
else
|
||||
{
|
||||
Details = "Please log in first.";
|
||||
}
|
||||
var posts = await PostsRepository.getPostsAsync();
|
||||
amountOfPosts = posts.Count;
|
||||
var comments = await CommentsRepository.getCommentsAsync();
|
||||
amountOfComments = comments.Count;
|
||||
var users = await UsersRepository.getUsersAsync();
|
||||
amountOfUsers = users.Count;
|
||||
}
|
||||
|
||||
}
|
14
ImageBoardServerApp/Pages/Basic/Index.razor.css
Normal file
14
ImageBoardServerApp/Pages/Basic/Index.razor.css
Normal file
|
@ -0,0 +1,14 @@
|
|||
.loginlink{
|
||||
display: block;
|
||||
font-size: 10px;
|
||||
color: #c6cfd0;
|
||||
}
|
||||
|
||||
.imblue{
|
||||
color: #0a53be;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.loginwrapper{
|
||||
display: flex;
|
||||
}
|
20
ImageBoardServerApp/Pages/Basic/Rules.razor
Normal file
20
ImageBoardServerApp/Pages/Basic/Rules.razor
Normal file
|
@ -0,0 +1,20 @@
|
|||
@page "/rules"
|
||||
<div class="rules_headline">
|
||||
<h3>Rules</h3>
|
||||
</div>
|
||||
<ul type="1" class="rules_list">
|
||||
<li>You may not post stuff that would get us into trouble with the feds.</li>
|
||||
<li>You may not post NSFW / NSFL on this platform.</li>
|
||||
<li>You may not post political content on this platform.</li>
|
||||
<li>You may not plan or participate in "raids" on this platform.</li>
|
||||
<li>You have to be atleast 18 years old to post.</li>
|
||||
<li>You may not post through VPNs, Proxies or the TOR network.</li>
|
||||
<li>You may not post posts, which are not of the same topic as the target board.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
}
|
|
@ -3,8 +3,9 @@
|
|||
font-weight: 1000;
|
||||
/*the text have to be in a biger Pixel number I do not know how to do it */
|
||||
}
|
||||
|
||||
.rules_list{
|
||||
text-align:right;
|
||||
text-align:left;
|
||||
display:block;
|
||||
font-size: 14px;
|
||||
font-weight: 60 ;
|
17
ImageBoardServerApp/Pages/Boards/M.razor
Normal file
17
ImageBoardServerApp/Pages/Boards/M.razor
Normal file
|
@ -0,0 +1,17 @@
|
|||
@page "/m/"
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using ImageBoardServerApp.Data
|
||||
|
||||
<img class="banner" src="img/static/banner/mban.png" alt="No Banner found"/>
|
||||
<Board board="@m"/>
|
||||
|
||||
@code {
|
||||
|
||||
private BoardData m { get; set; } = new()
|
||||
{
|
||||
BoardID = 0,
|
||||
maxThreads = 10,
|
||||
Tag = "m",
|
||||
Topic = "Main"
|
||||
};
|
||||
}
|
3
ImageBoardServerApp/Pages/Boards/M.razor.css
Normal file
3
ImageBoardServerApp/Pages/Boards/M.razor.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
.banner{
|
||||
justify-content: center;
|
||||
}
|
17
ImageBoardServerApp/Pages/Components/ReportPage.razor
Normal file
17
ImageBoardServerApp/Pages/Components/ReportPage.razor
Normal file
|
@ -0,0 +1,17 @@
|
|||
@page "/report/{type}/{board}/{id}"
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
<h3>Report</h3>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
[Required]
|
||||
public string type { get; set; }
|
||||
|
||||
[Parameter]
|
||||
[Required]
|
||||
public string board { get; set; }
|
||||
|
||||
[Parameter]
|
||||
[Required]
|
||||
public string id { get; set; }
|
||||
}
|
44
ImageBoardServerApp/Pages/Components/ThreadPage.razor
Normal file
44
ImageBoardServerApp/Pages/Components/ThreadPage.razor
Normal file
|
@ -0,0 +1,44 @@
|
|||
@page "/{boardName}/thread/{threadId}"
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using ImageBoardServerApp.Data.Repository
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<h3>Thread #@threadId on /@boardName/</h3>
|
||||
<Post post="@post" showOpenThread="false"/>
|
||||
<hr/>
|
||||
|
||||
@foreach (var comment in post.Comments)
|
||||
{
|
||||
<Comment comment="comment"/>
|
||||
<hr/>
|
||||
}
|
||||
<CommentForm post="post"/>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
[Required]
|
||||
public string boardName { get; set; }
|
||||
|
||||
[Parameter]
|
||||
[Required]
|
||||
public string threadId { get; set; }
|
||||
|
||||
private PostData post;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
post = await PostsRepository.getPostByIdAsync(int.Parse(threadId));
|
||||
}
|
||||
catch (FormatException fe)
|
||||
{
|
||||
NavigationManager.NavigateTo("/notfound");
|
||||
return;
|
||||
}
|
||||
if(post.Board != boardName)
|
||||
NavigationManager.NavigateTo("/notfound");
|
||||
if(post == null)
|
||||
NavigationManager.NavigateTo("/notfound");
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
@page "/"
|
||||
|
||||
<h1>BulletBoard</h1>
|
||||
<div>
|
||||
This is a simple Imageboard made in Razor.
|
||||
</div>
|
||||
<div>
|
||||
|
||||
</div>
|
|
@ -1,58 +0,0 @@
|
|||
@page "/Login"
|
||||
@using ImageBoardServerApp.Data.Repository
|
||||
<h3>Login</h3>
|
||||
<div>
|
||||
<form>
|
||||
<div>
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" id="email" @bind="Email" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" @bind="Password" />
|
||||
</div>
|
||||
<button type="submit" @onclick="SubmitForm">Submit</button>
|
||||
</form>
|
||||
|
||||
@if (tried)
|
||||
{
|
||||
@if (verified)
|
||||
{
|
||||
<span>Verifed!</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>False login</span>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Plz login</span>
|
||||
}
|
||||
|
||||
</div>
|
||||
@code {
|
||||
private string Email { get; set; }
|
||||
private string Password { get; set; }
|
||||
|
||||
private bool verified = false;
|
||||
private bool tried = false;
|
||||
|
||||
private async Task SubmitForm()
|
||||
{
|
||||
tried = true;
|
||||
AccountData target = (await AccountsRepository.getAccountsByMailAsync(Email))[0];
|
||||
if (target == null)
|
||||
{
|
||||
verified = false;
|
||||
return;
|
||||
}
|
||||
verified = BCrypt.Net.BCrypt.Verify(Password, target.Password);
|
||||
if (verified)
|
||||
{
|
||||
verified = true;
|
||||
return;
|
||||
}
|
||||
verified = false;
|
||||
}
|
||||
}
|
32
ImageBoardServerApp/Pages/Moderation/ModMenu.razor
Normal file
32
ImageBoardServerApp/Pages/Moderation/ModMenu.razor
Normal file
|
@ -0,0 +1,32 @@
|
|||
@page "/modmenu"
|
||||
@using ImageBoardServerApp.Auth
|
||||
@inject AuthenticationStateProvider authStateProvider
|
||||
@inject NavigationManager navManager
|
||||
|
||||
|
||||
<h3>ModMenu</h3>
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<span>Welcome @mail to the mod menu</span>
|
||||
<div>
|
||||
<a href="/modmenu/reports">[Reports]</a>
|
||||
<a href="/modmenu/users">[Users]</a>
|
||||
</div>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<a href="/login">You do not have permission to view this menu.</a>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
@code {
|
||||
private string mail { get; set; } = "";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var cauthStateProvder = (CustomAuthenticationStateProvider)authStateProvider;
|
||||
var user = await cauthStateProvder.GetAuthenticationStateAsync();
|
||||
if (user.User.Identity.IsAuthenticated)
|
||||
{
|
||||
mail = user.User.Identity.Name;
|
||||
}
|
||||
}
|
||||
}
|
5
ImageBoardServerApp/Pages/Moderation/ReportsPage.razor
Normal file
5
ImageBoardServerApp/Pages/Moderation/ReportsPage.razor
Normal file
|
@ -0,0 +1,5 @@
|
|||
@page "/modmenu/reports"
|
||||
<Reports />
|
||||
@code {
|
||||
|
||||
}
|
6
ImageBoardServerApp/Pages/Moderation/UsersPage.razor
Normal file
6
ImageBoardServerApp/Pages/Moderation/UsersPage.razor
Normal file
|
@ -0,0 +1,6 @@
|
|||
@page "/modmenu/users"
|
||||
<h3>UsersPage</h3>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
@page "/rules"
|
||||
<div class="rules_headline">
|
||||
<h3>Rules</h3>
|
||||
</div>
|
||||
<ul type="1" class="rules_list">
|
||||
<li>nudes are forbidden!</li>
|
||||
<li>nacket pictures are forbidden!</li>
|
||||
<li>no political statements!</li>
|
||||
<li>Trees are nice!</li>
|
||||
<li>Cats are nice!</li>
|
||||
<li>Be mentely Unstable!:-)</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css"/>
|
||||
<link href="css/site.css" rel="stylesheet"/>
|
||||
<link href="ImageBoardServerApp.styles.css" rel="stylesheet"/>
|
||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||
<link rel="icon" type="image/png" href="/img/static/logo.png"/>
|
||||
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered"/>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
using ImageBoardServerApp.Data;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
using ImageBoardServerApp.Auth;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddAuthenticationCore();
|
||||
builder.Services.AddRazorPages();
|
||||
builder.Services.AddServerSideBlazor();
|
||||
builder.Services.AddScoped<ProtectedSessionStorage>();
|
||||
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
{
|
||||
@foreach(var post in posts)
|
||||
{
|
||||
<Post post="@post"></Post>
|
||||
<Post post="@post" showOpenThread="true"></Post>
|
||||
<hr/>
|
||||
}
|
||||
}
|
||||
|
|
108
ImageBoardServerApp/Shared/Components/Comment.razor
Normal file
108
ImageBoardServerApp/Shared/Components/Comment.razor
Normal file
|
@ -0,0 +1,108 @@
|
|||
@using System.ComponentModel.DataAnnotations
|
||||
@using ImageBoardServerApp.Auth
|
||||
@using ImageBoardServerApp.Data
|
||||
@using ImageBoardServerApp.Data.Repository
|
||||
@inject AuthenticationStateProvider authStateProvider
|
||||
|
||||
<div class="threadHeader">
|
||||
<span>[</span>
|
||||
<a class="toggleOpened" onclick="@ToggleOpened">@toggleText</a>
|
||||
<span>]</span>
|
||||
<span class="name">@comment.Username</span>
|
||||
@if (@comment.User.Role != "User")
|
||||
{
|
||||
<span class="@comment.User.Role" >##@comment.User.Role</span>
|
||||
}
|
||||
<span class="date">@getTimeFromUnix(comment.CreatedAt)</span>
|
||||
<span class="post-id">No.@comment.CommentID</span>
|
||||
</div>
|
||||
@if (opened)
|
||||
{
|
||||
<div class="threadContent">
|
||||
<div class="threadImage">
|
||||
@if (image != null)
|
||||
{
|
||||
<img src="@($"{image.ImageLocation}")" alt="No Image found" />
|
||||
}
|
||||
</div>
|
||||
<div class="threadTextContainer">
|
||||
@foreach (string s in @comment.Content.Split("\n"))
|
||||
{
|
||||
@if (s.StartsWith(">"))
|
||||
{
|
||||
<span class="threadText greenText">@s</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class='threadText'>@s</span>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="threadFooter">
|
||||
<span>[</span>
|
||||
<a @onclick="@deletePost" href="javascript:void(0)">Delete</a>
|
||||
<span>]</span>
|
||||
<span>[</span>
|
||||
<a class="report" href="/report/comment/@comment.Board/@comment.CommentID" target="_blank">Report</a>
|
||||
<span>]</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
private async Task deletePost()
|
||||
{
|
||||
var cauthStateProvder = (CustomAuthenticationStateProvider)authStateProvider;
|
||||
var user = await cauthStateProvder.GetAuthenticationStateAsync();
|
||||
var usr = user.User;
|
||||
UserData foundusr = await UsersRepository.getUserByEmailAsync(usr.Identity.Name);
|
||||
if (foundusr.PermissionInteger >= 50 || comment.UserID == foundusr.UserID)
|
||||
{
|
||||
await CommentsRepository.deleteCommentAsync(comment.CommentID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static DateTime getTimeFromUnix(double javaTimeStamp)
|
||||
{
|
||||
var dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
||||
dateTime = dateTime.AddMilliseconds( javaTimeStamp ).ToLocalTime();
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
private ImageData image;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
int i;
|
||||
try
|
||||
{
|
||||
i = (int)comment.ImageID;
|
||||
}
|
||||
catch (InvalidOperationException ioe)
|
||||
{
|
||||
i = -1;
|
||||
}
|
||||
if (i != null)
|
||||
{
|
||||
image = await ImagesRepository.getImageByIdAsync(i);
|
||||
}
|
||||
}
|
||||
|
||||
private bool opened = true;
|
||||
|
||||
private string toggleText = "-";
|
||||
|
||||
private void ToggleOpened()
|
||||
{
|
||||
opened = !opened;
|
||||
toggleText = opened ? "-" : "+";
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
[Required]
|
||||
public CommentData comment { get; set; }
|
||||
}
|
70
ImageBoardServerApp/Shared/Components/Comment.razor.css
Normal file
70
ImageBoardServerApp/Shared/Components/Comment.razor.css
Normal file
|
@ -0,0 +1,70 @@
|
|||
.toggleOpened{
|
||||
color: #0a58ca;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.toggleOpened:hover{
|
||||
color: #0a58ca; !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.title{
|
||||
color: #1e5aaf;
|
||||
}
|
||||
|
||||
.name{
|
||||
color: #339305;
|
||||
}
|
||||
|
||||
.threadHeader{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.threadFooter{
|
||||
text-align: right; !important;
|
||||
align-self: end; !important;
|
||||
}
|
||||
|
||||
.threadContent{
|
||||
text-align: left;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.greenText{
|
||||
color: #3caf03;
|
||||
}
|
||||
|
||||
.threadImage{
|
||||
margin: 6px;
|
||||
max-width: 500px;
|
||||
max-height: 500px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.threadImage img{
|
||||
max-width:150px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.threadImage img:hover{
|
||||
/*transform: scale(3);*/
|
||||
max-width:500px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.threadText{
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.threadTextContainer{
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
.Admin{
|
||||
color: #ff191c;
|
||||
}
|
||||
|
||||
.Mod{
|
||||
color: #af13d7;
|
||||
}
|
155
ImageBoardServerApp/Shared/Components/Forms/CommentForm.razor
Normal file
155
ImageBoardServerApp/Shared/Components/Forms/CommentForm.razor
Normal file
|
@ -0,0 +1,155 @@
|
|||
@using System.ComponentModel.DataAnnotations
|
||||
@using ImageBoardServerApp.Auth
|
||||
@using ImageBoardServerApp.Data.Repository
|
||||
|
||||
@inject NavigationManager navigationManager
|
||||
@inject IWebHostEnvironment env
|
||||
@inject AuthenticationStateProvider authStateProvider
|
||||
|
||||
<div>
|
||||
<span>[</span>
|
||||
<a class="toggleOpened" onclick="@ToggleOpened">@toggleText</a>
|
||||
<span>]</span>
|
||||
</div>
|
||||
@if (opened)
|
||||
{
|
||||
<div class="pd centered">
|
||||
<span>Comment on @post.Title in /@post.Board/</span>
|
||||
|
||||
<div class="centered formContent">
|
||||
<div>
|
||||
<div class="pd centered marg">
|
||||
<RadzenTextBox Placeholder="Username (Anonymous)" MaxLength="15" @bind-Value="@postUsername" Class="w-100"/>
|
||||
</div>
|
||||
|
||||
<div class="pd centered marg">
|
||||
<RadzenTextArea Placeholder="Comment..." @bind-Value="@postContent" Cols="30" Rows="6" Class="w-100"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if (hasErr)
|
||||
{
|
||||
<span class="postError">@postErr</span>
|
||||
}
|
||||
<div class="pd centered marg">
|
||||
<FormInfo/>
|
||||
<InputFile OnChange="@SingleUpload" type="file" accept="image/*"/>
|
||||
<RadzenButton class="pd" Click="@onPostClick" Text="Post!"></RadzenButton>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
private bool opened = false;
|
||||
|
||||
private string toggleText = "Open Comment Formula";
|
||||
|
||||
private void ToggleOpened()
|
||||
{
|
||||
opened = !opened;
|
||||
toggleText = opened ? "Close Comment Formula" : "Open Comment Formula";
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
[Required]
|
||||
public PostData post { get; set; }
|
||||
|
||||
string postUsername { get; set; } = "Anonymous";
|
||||
string postContent { get; set; } = "";
|
||||
|
||||
private IBrowserFile selectedFile;
|
||||
|
||||
private async Task SingleUpload(InputFileChangeEventArgs e)
|
||||
{
|
||||
selectedFile = e.GetMultipleFiles()[0];
|
||||
this.StateHasChanged();
|
||||
}
|
||||
|
||||
string postErr { get; set; }
|
||||
bool hasErr { get; set; } = false;
|
||||
|
||||
private async Task onPostClick()
|
||||
{
|
||||
var cauthStateProvder = (CustomAuthenticationStateProvider)authStateProvider;
|
||||
var user = await cauthStateProvder.GetAuthenticationStateAsync();
|
||||
var usr = user.User;
|
||||
UserData foundusr = await UsersRepository.getUserByEmailAsync(usr.Identity.Name);
|
||||
if (foundusr == null)
|
||||
{
|
||||
hasErr = true;
|
||||
postErr = "You are not logged in.";
|
||||
return;
|
||||
}
|
||||
int userID = foundusr.UserID;
|
||||
if (foundusr.TimeBanned != -1)
|
||||
{
|
||||
hasErr = true;
|
||||
postErr = "You are banned and may not comment.";
|
||||
//Maybe redirect to /banned?
|
||||
return;
|
||||
}
|
||||
foundusr.lastActionTimeStamp = DateTimeOffset.UnixEpoch.ToUnixTimeMilliseconds();
|
||||
await UsersRepository.updateUserAsync(foundusr);
|
||||
|
||||
bool hasImage = selectedFile != null;
|
||||
|
||||
CommentData commentToCreate;
|
||||
if (hasImage)
|
||||
{
|
||||
Stream stream = selectedFile.OpenReadStream(maxAllowedSize: 512000 * 4); // max 2MB
|
||||
var file = Path.GetRandomFileName() + "." + selectedFile.Name.Split(".")[selectedFile.Name.Split(".").Length - 1];
|
||||
var path = $"{env.WebRootPath}/img/dynamic/comment/{@post.Board}/{@file}";
|
||||
FileStream fs = File.Create(path);
|
||||
await stream.CopyToAsync(fs);
|
||||
stream.Close();
|
||||
fs.Close();
|
||||
|
||||
|
||||
var imageToUpload = new ImageData
|
||||
{
|
||||
Board = post.Board,
|
||||
ImageLocation = $"/img/dynamic/comment/{@post.Board}/{@file}"
|
||||
};
|
||||
int imageID = await ImagesRepository.createImageAsync(imageToUpload);
|
||||
commentToCreate = new CommentData()
|
||||
{
|
||||
PostID = post.PostID,
|
||||
UserID = userID,
|
||||
ImageID = imageID,
|
||||
Content = postContent,
|
||||
Username = postUsername,
|
||||
Board = post.Board,
|
||||
CreatedAt = DateTimeOffset.Now.ToUnixTimeMilliseconds()
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
commentToCreate = new CommentData()
|
||||
{
|
||||
PostID = post.PostID,
|
||||
UserID = userID,
|
||||
Content = postContent,
|
||||
Username = postUsername,
|
||||
Board = post.Board,
|
||||
CreatedAt = DateTimeOffset.Now.ToUnixTimeMilliseconds()
|
||||
};
|
||||
}
|
||||
|
||||
int commentId = await CommentsRepository.createCommentAsync(commentToCreate);
|
||||
if (commentId == -1)
|
||||
{
|
||||
//Open comment unsucessfull
|
||||
navigationManager.NavigateTo("/UnSuccessfulPost");
|
||||
hasErr = true;
|
||||
postErr = "There was an error and the comment could not be created. Please notify the admin.";
|
||||
Console.WriteLine("Shit sucks and did not work.");
|
||||
return;
|
||||
}
|
||||
//comment successfull
|
||||
Console.WriteLine("Post created");
|
||||
navigationManager.NavigateTo($"/{post.Board}/thread/{post.PostID}", true, true);
|
||||
opened = false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
.toggleOpened{
|
||||
color: #0a58ca;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.toggleOpened:hover{
|
||||
color: #0a58ca; !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.centered {
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pd {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.marg{
|
||||
margin: 2px
|
||||
}
|
||||
|
||||
.formImage{
|
||||
margin: 6px;
|
||||
max-width: 200px;
|
||||
max-height: 200px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.formImage img{
|
||||
max-width:150px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.formContent{
|
||||
text-align: left;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.postError{
|
||||
color: #ff191c;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<ul class="notesInfo">
|
||||
<li>The max. image size is 2MiB.</li>
|
||||
<li>Supported file types are: jpeg, png & gif</li>
|
||||
<li>Read the rules before posting</li>
|
||||
</ul>
|
|
@ -0,0 +1,8 @@
|
|||
.notesInfo{
|
||||
font-weight: 60;
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 10px;
|
||||
color: #c6cfd0;
|
||||
/*the text sice can stay like it is, if you do not want to change it.*/
|
||||
}
|
161
ImageBoardServerApp/Shared/Components/Forms/PostForm.razor
Normal file
161
ImageBoardServerApp/Shared/Components/Forms/PostForm.razor
Normal file
|
@ -0,0 +1,161 @@
|
|||
@using Radzen
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using System.IO.Pipelines
|
||||
@using System.Net.Mime
|
||||
@using System.Reflection
|
||||
@using System.Runtime.CompilerServices
|
||||
@using ImageBoardServerApp.Auth
|
||||
@using ImageBoardServerApp.Data
|
||||
@using ImageBoardServerApp.Data.Repository
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IWebHostEnvironment env
|
||||
@inject AuthenticationStateProvider authStateProvider
|
||||
|
||||
<div>
|
||||
<span>[</span>
|
||||
<a class="toggleOpened" onclick="@ToggleOpened">@toggleText</a>
|
||||
<span>]</span>
|
||||
</div>
|
||||
@if (opened)
|
||||
{
|
||||
<div class="pd centered">
|
||||
<span>Post to /@board.Tag/ - @board.Topic</span>
|
||||
|
||||
<div class="centered formContent">
|
||||
<div>
|
||||
<div class="pd centered marg">
|
||||
<RadzenTextBox Placeholder="Username (Anonymous)" MaxLength="15" @bind-Value="@postUsername" Class="w-100"/>
|
||||
</div>
|
||||
|
||||
<div class="pd centered marg">
|
||||
<RadzenTextBox Placeholder="Title" MaxLength="20" @bind-Value="@postTitle" Class="w-100"/>
|
||||
</div>
|
||||
|
||||
<div class="pd centered marg">
|
||||
<RadzenTextArea Placeholder="Content..." @bind-Value="@postContent" Cols="30" Rows="6" Class="w-100"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if (hasErr)
|
||||
{
|
||||
<span class="postError">@postErr</span>
|
||||
}
|
||||
<div class="pd centered marg">
|
||||
<FormInfo/>
|
||||
<InputFile OnChange="@SingleUpload" type="file" accept="image/*"/>
|
||||
<RadzenButton class="pd" Click="@onPostClick" Text="Post!"></RadzenButton>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
private bool opened = false;
|
||||
|
||||
private string toggleText = "Open Post Formula";
|
||||
|
||||
private void ToggleOpened()
|
||||
{
|
||||
opened = !opened;
|
||||
toggleText = opened ? "Close Post Formula" : "Open Post Formula";
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
[Required]
|
||||
public BoardData board { get; set; } = new BoardData();
|
||||
|
||||
string postUsername { get; set; } = "Anonymous";
|
||||
string postTitle { get; set; } = "";
|
||||
string postContent { get; set; } = "";
|
||||
|
||||
|
||||
private IBrowserFile selectedFile;
|
||||
|
||||
|
||||
private async Task SingleUpload(InputFileChangeEventArgs e)
|
||||
{
|
||||
selectedFile = e.GetMultipleFiles()[0];
|
||||
this.StateHasChanged();
|
||||
}
|
||||
|
||||
string postErr { get; set; }
|
||||
bool hasErr { get; set; } = false;
|
||||
|
||||
private async Task onPostClick()
|
||||
{
|
||||
|
||||
var cauthStateProvder = (CustomAuthenticationStateProvider)authStateProvider;
|
||||
var user = await cauthStateProvder.GetAuthenticationStateAsync();
|
||||
var usr = user.User;
|
||||
UserData foundusr = await UsersRepository.getUserByEmailAsync(usr.Identity.Name);
|
||||
if (foundusr == null)
|
||||
{
|
||||
hasErr = true;
|
||||
postErr = "You are not logged in.";
|
||||
return;
|
||||
}
|
||||
int userID = foundusr.UserID;
|
||||
if (foundusr.TimeBanned != -1)
|
||||
{
|
||||
hasErr = true;
|
||||
postErr = "You are banned and may not post.";
|
||||
//Maybe redirect to /banned?
|
||||
return;
|
||||
}
|
||||
foundusr.lastActionTimeStamp = DateTimeOffset.UnixEpoch.ToUnixTimeMilliseconds();
|
||||
await UsersRepository.updateUserAsync(foundusr);
|
||||
|
||||
|
||||
//TODO Add check if data is image
|
||||
|
||||
if (selectedFile == null || selectedFile.Size >= 512000 * 4)
|
||||
{
|
||||
hasErr = true;
|
||||
postErr = "You did not attach a file or the selected file is bigger then the 2MiB file limit.";
|
||||
return;
|
||||
}
|
||||
|
||||
Stream stream = selectedFile.OpenReadStream(maxAllowedSize: 512000 * 4); // max 2MB
|
||||
var file = Path.GetRandomFileName() + "." + selectedFile.Name.Split(".")[selectedFile.Name.Split(".").Length - 1];
|
||||
var path = $"{env.WebRootPath}/img/dynamic/op/{@board.Tag}/{@file}";
|
||||
FileStream fs = File.Create(path);
|
||||
await stream.CopyToAsync(fs);
|
||||
stream.Close();
|
||||
fs.Close();
|
||||
|
||||
var imageToUpload = new ImageData
|
||||
{
|
||||
Board = board.Tag,
|
||||
ImageLocation = $"/img/dynamic/op/{@board.Tag}/{@file}"
|
||||
};
|
||||
int imageID = await ImagesRepository.createImageAsync(imageToUpload);
|
||||
var postToPost = new PostData
|
||||
{
|
||||
UserID = userID,
|
||||
ImageID = imageID,
|
||||
Username = postUsername,
|
||||
Title = postTitle,
|
||||
Content = postContent,
|
||||
Interactions = 0,
|
||||
CreatedAt = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
|
||||
Board = board.Tag
|
||||
};
|
||||
int postId = await PostsRepository.createPostAsync(postToPost);
|
||||
if (postId != -1)
|
||||
{
|
||||
//Open post successfull
|
||||
NavigationManager.NavigateTo($"/{board.Tag}/thread/{postId}", true, true);
|
||||
Console.WriteLine("Post created");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Open post unsucessfull
|
||||
hasErr = true;
|
||||
postErr = "There was an error and the post could not be created. Please notify the admin.";
|
||||
Console.WriteLine("Shit sucks and did not work.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,4 +20,25 @@
|
|||
|
||||
.marg{
|
||||
margin: 2px
|
||||
}
|
||||
|
||||
.formImage{
|
||||
margin: 6px;
|
||||
max-width: 200px;
|
||||
max-height: 200px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.formImage img{
|
||||
max-width:150px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.formContent{
|
||||
text-align: left;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.postError{
|
||||
color: #ff191c;
|
||||
}
|
|
@ -1,12 +1,22 @@
|
|||
@using System.ComponentModel.DataAnnotations
|
||||
@using ImageBoardServerApp.Auth
|
||||
@using ImageBoardServerApp.Data
|
||||
@using ImageBoardServerApp.Data.Repository
|
||||
@inject AuthenticationStateProvider authStateProvider
|
||||
|
||||
<div class="threadHeader">
|
||||
<span>[</span>
|
||||
<a class="toggleOpened" onclick="@ToggleOpened">@toggleText</a>
|
||||
<span>]</span>
|
||||
@if (showOpenThread)
|
||||
{
|
||||
<span>[</span>
|
||||
<a class="toggleOpened" onclick="@ToggleOpened">@toggleText</a>
|
||||
<span>]</span>
|
||||
}
|
||||
<span class="title">@post.Title</span>
|
||||
<span class="name">@post.Username</span>
|
||||
@if (post.User.Role != "User")
|
||||
{
|
||||
<span class="@post.User.Role" >##@post.User.Role</span>
|
||||
}
|
||||
<span class="date">@getTimeFromUnix(post.CreatedAt)</span>
|
||||
<span class="post-id">No.@post.PostID</span>
|
||||
</div>
|
||||
|
@ -14,10 +24,9 @@
|
|||
{
|
||||
<div class="threadContent">
|
||||
<div class="threadImage">
|
||||
<!-- TODO: Make Images Required. -->
|
||||
@if (@post.Image != null)
|
||||
{
|
||||
<img src="@($"data:image/jpeg;base64,{Convert.ToBase64String(@post.Image.Image)}")" alt="No Image found" />
|
||||
<img src="@($"{@post.Image.ImageLocation}")" alt="No Image found" />
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -27,27 +36,42 @@
|
|||
<div class="threadTextContainer">
|
||||
@foreach (string s in @post.Content.Split("\n"))
|
||||
{
|
||||
<span class='threadText'>@s</span>
|
||||
@if (@s.StartsWith(">"))
|
||||
{
|
||||
<span class="threadText greenText">@s</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class='threadText'>@s</span>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="threadFooter">
|
||||
<!--<RadzenButton class="bump" Text="bump"></RadzenButton> -->
|
||||
<span>[</span>
|
||||
<a class="report" href="/report/@post.Board/@post.PostID" target="_blank">Report</a>
|
||||
<a @onclick="@deletePost" href="javascript:void(0)">Delete</a>
|
||||
<span>]</span>
|
||||
<span>[</span>
|
||||
<a class="openThread" href="/@post.Board/@post.PostID" target="_blank">(@post.Interactions) Open Thread</a>
|
||||
<a class="report" href="/report/op/@post.Board/@post.PostID" target="_blank">Report</a>
|
||||
<span>]</span>
|
||||
@if (showOpenThread)
|
||||
{
|
||||
<span>[</span>
|
||||
<a class="openThread" href="/@post.Board/thread/@post.PostID">(@post.Comments.Count) View Thread</a>
|
||||
<span>]</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>[</span>
|
||||
<span class="openThread">@post.Comments.Count Comments</span>
|
||||
<span>]</span>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
|
||||
|
||||
private static DateTime getTimeFromUnix(double javaTimeStamp)
|
||||
{
|
||||
var dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
@ -55,6 +79,18 @@
|
|||
return dateTime;
|
||||
}
|
||||
|
||||
private async Task deletePost()
|
||||
{
|
||||
var cauthStateProvder = (CustomAuthenticationStateProvider)authStateProvider;
|
||||
var user = await cauthStateProvder.GetAuthenticationStateAsync();
|
||||
var usr = user.User;
|
||||
UserData foundusr = await UsersRepository.getUserByEmailAsync(usr.Identity.Name);
|
||||
if (foundusr.PermissionInteger >= 50 || post.UserID == foundusr.UserID)
|
||||
{
|
||||
await PostsRepository.deletePostAsync(post.PostID);
|
||||
}
|
||||
}
|
||||
|
||||
private bool opened = true;
|
||||
|
||||
private string toggleText = "-";
|
||||
|
@ -68,4 +104,9 @@
|
|||
[Parameter]
|
||||
[Required]
|
||||
public PostData post { get; set; }
|
||||
|
||||
|
||||
[Parameter]
|
||||
[Required]
|
||||
public bool showOpenThread { get; set; }
|
||||
}
|
|
@ -16,6 +16,14 @@
|
|||
color: #339305;
|
||||
}
|
||||
|
||||
.Admin{
|
||||
color: #ff191c;
|
||||
}
|
||||
|
||||
.Mod{
|
||||
color: #af13d7;
|
||||
}
|
||||
|
||||
.threadHeader{
|
||||
text-align: left;
|
||||
}
|
||||
|
@ -30,6 +38,10 @@
|
|||
display: flex;
|
||||
}
|
||||
|
||||
.greenText{
|
||||
color: #3caf03;
|
||||
}
|
||||
|
||||
.threadImage{
|
||||
margin: 6px;
|
||||
max-width: 500px;
|
||||
|
@ -43,9 +55,9 @@
|
|||
}
|
||||
|
||||
.threadImage img:hover{
|
||||
transform: scale(3);
|
||||
/*max-width:500px;
|
||||
width: 100%; */
|
||||
/*transform: scale(3);*/
|
||||
max-width:500px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.threadText{
|
||||
|
|
|
@ -1,139 +0,0 @@
|
|||
@using Radzen
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using System.IO.Pipelines
|
||||
@using System.Net.Mime
|
||||
@using System.Reflection
|
||||
@using System.Runtime.CompilerServices
|
||||
@using ImageBoardServerApp.Data
|
||||
@using ImageBoardServerApp.Data.Repository
|
||||
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
<div>
|
||||
<span>[</span>
|
||||
<a class="toggleOpened" onclick="@ToggleOpened">@toggleText</a>
|
||||
<span>]</span>
|
||||
</div>
|
||||
@if (opened)
|
||||
{
|
||||
<div class="pd centered">
|
||||
<span>Post to /@board.Tag/ - @board.Topic</span>
|
||||
|
||||
<div class="pd centered marg">
|
||||
<RadzenTextBox Placeholder="Username (Anonymous)" MaxLength="15" Change=@(args => OnChange(args, "username")) Class="w-100"/>
|
||||
</div>
|
||||
|
||||
<div class="pd centered marg">
|
||||
<RadzenTextBox Placeholder="Title" MaxLength="20" Change=@(args => OnChange(args, "title")) Class="w-100"/>
|
||||
</div>
|
||||
|
||||
<div class="pd centered marg">
|
||||
<RadzenTextArea Placeholder="Content..." @bind-Value="@postContent" Cols="30" Rows="6" Change=@(args => OnChange(args, "Content")) Class="w-100"/>
|
||||
</div>
|
||||
|
||||
<div class="pd centered marg">
|
||||
<InputFile OnChange="@SingleUpload" type="file" accept="image/*"/>
|
||||
<RadzenButton class="pd" Click="@onPostClick" Text="Post!"></RadzenButton>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
private bool opened = false;
|
||||
|
||||
private string toggleText = "Open Post Formula";
|
||||
|
||||
private void ToggleOpened()
|
||||
{
|
||||
opened = !opened;
|
||||
toggleText = opened ? "Close Post Formula" : "Open Post Formula";
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
[Required]
|
||||
public BoardData board { get; set; } = new BoardData();
|
||||
|
||||
string postUsername = "Anonymous";
|
||||
string postTitle = "";
|
||||
string postContent = "";
|
||||
|
||||
void OnChange(string value, string name)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "title":
|
||||
postTitle = value;
|
||||
break;
|
||||
case "username":
|
||||
postUsername = value;
|
||||
break;
|
||||
case "content":
|
||||
postContent = value;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("not found.");
|
||||
break;
|
||||
}
|
||||
Console.WriteLine($"Smth changed!: {value}");
|
||||
}
|
||||
|
||||
private async Task SingleUpload(InputFileChangeEventArgs e)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
await e.File.OpenReadStream().CopyToAsync(ms);
|
||||
var bytes = ms.ToArray();
|
||||
image = bytes;
|
||||
Console.WriteLine("File has been selected!");
|
||||
ms.Close();
|
||||
}
|
||||
|
||||
private Byte[] image;
|
||||
|
||||
private async Task onPostClick()
|
||||
{
|
||||
var userToCreate = new UserData
|
||||
{
|
||||
Ipv4Address = "192.168.178.101",
|
||||
Banned = false,
|
||||
lastActionTimeStamp = DateTime.Now.Millisecond
|
||||
};
|
||||
int userID = await UsersRepository.createUserAsync(userToCreate);
|
||||
|
||||
//TODO Add check if data is image
|
||||
|
||||
|
||||
var imageToUpload = new ImageData
|
||||
{
|
||||
Board = board.Tag,
|
||||
Image = image
|
||||
};
|
||||
int imageID = await ImagesRepository.createImageAsync(imageToUpload);
|
||||
var postToPost = new PostData
|
||||
{
|
||||
UserID = userID,
|
||||
ImageID = imageID,
|
||||
Username = postUsername,
|
||||
Title = postTitle,
|
||||
Content = postContent,
|
||||
Interactions = "",
|
||||
CreatedAt = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
|
||||
Board = board.Tag
|
||||
};
|
||||
int postId = await PostsRepository.createPostAsync(postToPost);
|
||||
if (postId != -1)
|
||||
{
|
||||
//Open post successfull
|
||||
NavigationManager.NavigateTo("/SuccessfulPost");
|
||||
Console.WriteLine("Post created");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Open post unsucessfull
|
||||
NavigationManager.NavigateTo("/UnSuccessfulPost");
|
||||
Console.WriteLine("Shit sucks and did not work.");
|
||||
}
|
||||
}
|
||||
}
|
5
ImageBoardServerApp/Shared/Components/Reports.razor
Normal file
5
ImageBoardServerApp/Shared/Components/Reports.razor
Normal file
|
@ -0,0 +1,5 @@
|
|||
<h3>Reports</h3>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
@inherits LayoutComponentBase
|
||||
@using ImageBoardServerApp.Auth
|
||||
@inject AuthenticationStateProvider authStateProvider
|
||||
@inject NavigationManager navManager
|
||||
|
||||
<PageTitle>BulletBoard</PageTitle>
|
||||
|
||||
|
@ -8,13 +11,46 @@
|
|||
</div>
|
||||
|
||||
<main>
|
||||
|
||||
<div class="top-row px-4">
|
||||
<a href="/faq">[FAQ]</a>
|
||||
<a href="/rules">[Rules]</a>
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<a @onclick="logout" href="javascript:void(0)">[Logout @mail]</a>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<a href="/register">[Register]</a>
|
||||
<a href="/login">[Login]</a>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
</div>
|
||||
|
||||
<article class="content px-4">
|
||||
@Body
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
|
||||
private string mail { get; set; } = "";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var cauthStateProvder = (CustomAuthenticationStateProvider)authStateProvider;
|
||||
var user = await cauthStateProvder.GetAuthenticationStateAsync();
|
||||
if (user.User.Identity.IsAuthenticated)
|
||||
{
|
||||
mail = user.User.Identity.Name;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task logout()
|
||||
{
|
||||
var customAuthStateProvider = (CustomAuthenticationStateProvider) authStateProvider;
|
||||
await customAuthStateProvider.UpdateAuthenticationStateAsync(null);
|
||||
navManager.NavigateTo("/", true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
</NavLink>
|
||||
</div>
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="b">
|
||||
<span class="oi oi-list-rich" aria-hidden="true"></span> /b/ - Random
|
||||
<NavLink class="nav-link" href="m">
|
||||
<span class="oi oi-list-rich" aria-hidden="true"></span> /m/ - Main
|
||||
</NavLink>
|
||||
</div>
|
||||
</nav>
|
||||
|
|
|
@ -6,11 +6,16 @@
|
|||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using ImageBoardServerApp
|
||||
@using ImageBoardServerApp.Shared
|
||||
@using Radzen
|
||||
@using Radzen.Blazor
|
||||
@using ImageBoardServerApp
|
||||
@using ImageBoardServerApp.Pages
|
||||
@using ImageBoardServerApp.Pages.Boards
|
||||
@using ImageBoardServerApp.Pages.Accounts
|
||||
@using ImageBoardServerApp.Pages.Basic
|
||||
@using ImageBoardServerApp.Pages.Components
|
||||
@using ImageBoardServerApp.Pages.Status
|
||||
@using ImageBoardServerApp.Shared
|
||||
@using ImageBoardServerApp.Shared.Components
|
||||
@using ImageBoardServerApp.Data
|
||||
@using ImageBoardServerApp.Shared.Components.Forms
|
||||
@using ImageBoardServerApp.Data
|
||||
|
|
BIN
ImageBoardServerApp/wwwroot/img/static/banner/mban.png
Normal file
BIN
ImageBoardServerApp/wwwroot/img/static/banner/mban.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 168 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
BIN
ImageBoardServerApp/wwwroot/img/static/logo.png
Normal file
BIN
ImageBoardServerApp/wwwroot/img/static/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 159 KiB |
Loading…
Reference in a new issue