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/
|
.idea/
|
||||||
ImageBoardServerApp/bin/
|
ImageBoardServerApp/bin/
|
||||||
ImageBoardServerApp/obj/
|
ImageBoardServerApp/obj/
|
||||||
|
ImageBoardServerApp/wwwroot/img/dynamic
|
||||||
*.db
|
*.db
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
Migrations/
|
Migrations/
|
||||||
|
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
<Router AppAssembly="@typeof(App).Assembly">
|
<CascadingAuthenticationState>
|
||||||
<Found Context="routeData">
|
<Router AppAssembly="@typeof(App).Assembly">
|
||||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
|
<Found Context="routeData">
|
||||||
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
|
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
|
||||||
</Found>
|
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
|
||||||
<NotFound>
|
</Found>
|
||||||
<PageTitle>Not found</PageTitle>
|
<NotFound>
|
||||||
<LayoutView Layout="@typeof(MainLayout)">
|
<PageTitle>Not found</PageTitle>
|
||||||
<h3>404</h3>
|
<LayoutView Layout="@typeof(MainLayout)">
|
||||||
<div class="Error404">
|
<h3>404</h3>
|
||||||
<img src="static/1.jpeg" alt="noimageFound"/>
|
<div class="Error404">
|
||||||
<p role="alert">Sorry, nothing found. Please go back to the main page. Or watch the tree and find the hidden Cat..</p>
|
<img src="img/static/err/1.jpeg" alt="noimageFound"/>
|
||||||
</div>
|
<p role="alert">Sorry, nothing found. Please go back to the main page. Or watch the tree and find the hidden Cat..</p>
|
||||||
</LayoutView>
|
</div>
|
||||||
</NotFound>
|
</LayoutView>
|
||||||
</Router>
|
</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<PostData> Posts { get; set; }
|
||||||
public DbSet<ImageData> Images { get; set; }
|
public DbSet<ImageData> Images { get; set; }
|
||||||
public DbSet<CommentData> Comments { 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)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
=> optionsBuilder.UseSqlite("Data Source=./Data/Nils.db");
|
=> optionsBuilder.UseSqlite("Data Source=./Data/Nils.db");
|
||||||
|
@ -32,5 +32,18 @@ internal sealed class AppDBContext : DbContext
|
||||||
mb.Entity<UserData>()
|
mb.Entity<UserData>()
|
||||||
.HasMany(user => user.Comments)
|
.HasMany(user => user.Comments)
|
||||||
.WithOne(comment => comment.User);
|
.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;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using ImageBoardServerApp.Shared.Components;
|
|
||||||
|
|
||||||
namespace ImageBoardServerApp.Data;
|
namespace ImageBoardServerApp.Data;
|
||||||
|
|
||||||
|
@ -21,12 +20,12 @@ public class CommentData
|
||||||
public int UserID { get; set; }
|
public int UserID { get; set; }
|
||||||
|
|
||||||
//[ForeignKey("UserID")]
|
//[ForeignKey("UserID")]
|
||||||
public UserData User { get; set; }
|
public virtual UserData User { get; set; }
|
||||||
|
|
||||||
//[ForeignKey("ImageID")]
|
//[ForeignKey("ImageID")]
|
||||||
public virtual ImageData Image { get; set; }
|
public virtual ImageData? Image { get; set; }
|
||||||
|
|
||||||
public int ImageID { get; set; }
|
public int? ImageID { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public string Content { get; set; }
|
public string Content { get; set; }
|
||||||
|
@ -37,4 +36,9 @@ public class CommentData
|
||||||
[Required]
|
[Required]
|
||||||
public string Board { get; set; }
|
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; }
|
public string Board { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public Byte[] Image { get; set; }
|
public string ImageLocation { get; set; }
|
||||||
|
|
||||||
public PostData Post { get; set; }
|
public PostData Post { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class PostData
|
||||||
[Required]
|
[Required]
|
||||||
public string Content { get; set; }
|
public string Content { get; set; }
|
||||||
|
|
||||||
public string Interactions { get; set; }
|
public int Interactions { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public long CreatedAt { get; set; }
|
public long CreatedAt { get; set; }
|
||||||
|
@ -40,4 +40,6 @@ public class PostData
|
||||||
public string Board { get; set; }
|
public string Board { get; set; }
|
||||||
|
|
||||||
public List<CommentData> Comments { 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,9 +22,24 @@ public static class CommentsRepository
|
||||||
public static async Task<CommentData> getCommentByIdAsync(int postId)
|
public static async Task<CommentData> getCommentByIdAsync(int postId)
|
||||||
{
|
{
|
||||||
await using var db = new AppDBContext();
|
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)
|
public static async Task<int> createCommentAsync(CommentData commentData)
|
||||||
{
|
{
|
||||||
await using var db = new AppDBContext();
|
await using var db = new AppDBContext();
|
||||||
|
|
|
@ -16,13 +16,21 @@ public static class PostsRepository
|
||||||
return await db.Posts
|
return await db.Posts
|
||||||
.Where(post => post.Board.Equals(board))
|
.Where(post => post.Board.Equals(board))
|
||||||
.Include(post => post.Image)
|
.Include(post => post.Image)
|
||||||
|
.Include(post => post.Comments)
|
||||||
|
.Include(post => post.User)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<PostData> getPostByIdAsync(int postId)
|
public static async Task<PostData> getPostByIdAsync(int postId)
|
||||||
{
|
{
|
||||||
await using var db = new AppDBContext();
|
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)
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,12 @@ public static class UsersRepository
|
||||||
return await db.Users.FirstOrDefaultAsync(user => user.UserID == userId);
|
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)
|
public static async Task<int> createUserAsync(UserData userToCreate)
|
||||||
{
|
{
|
||||||
await using var db = new AppDBContext();
|
await using var db = new AppDBContext();
|
||||||
|
|
|
@ -13,10 +13,7 @@ public class UserData
|
||||||
public int UserID { get; set; }
|
public int UserID { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public string Ipv4Address { get; set; }
|
public long TimeBanned { get; set; }
|
||||||
|
|
||||||
[Required]
|
|
||||||
public bool Banned { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public long lastActionTimeStamp { get; set; }
|
public long lastActionTimeStamp { get; set; }
|
||||||
|
@ -24,4 +21,20 @@ public class UserData
|
||||||
public List<PostData> Posts { get; set; }
|
public List<PostData> Posts { get; set; }
|
||||||
|
|
||||||
public List<CommentData> Comments { 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>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="wwwroot\static" />
|
<Folder Include="wwwroot\img\dynamic\comment\m" />
|
||||||
|
<Folder Include="wwwroot\img\dynamic\op\m" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</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;
|
font-weight: 1000;
|
||||||
/*the text have to be in a biger Pixel number I do not know how to do it */
|
/*the text have to be in a biger Pixel number I do not know how to do it */
|
||||||
}
|
}
|
||||||
|
|
||||||
.rules_list{
|
.rules_list{
|
||||||
text-align:right;
|
text-align:left;
|
||||||
display:block;
|
display:block;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 60 ;
|
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 rel="stylesheet" href="css/bootstrap/bootstrap.min.css"/>
|
||||||
<link href="css/site.css" rel="stylesheet"/>
|
<link href="css/site.css" rel="stylesheet"/>
|
||||||
<link href="ImageBoardServerApp.styles.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"/>
|
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
using ImageBoardServerApp.Data;
|
using ImageBoardServerApp.Auth;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Design;
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
|
builder.Services.AddAuthenticationCore();
|
||||||
builder.Services.AddRazorPages();
|
builder.Services.AddRazorPages();
|
||||||
builder.Services.AddServerSideBlazor();
|
builder.Services.AddServerSideBlazor();
|
||||||
|
builder.Services.AddScoped<ProtectedSessionStorage>();
|
||||||
|
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
{
|
{
|
||||||
@foreach(var post in posts)
|
@foreach(var post in posts)
|
||||||
{
|
{
|
||||||
<Post post="@post"></Post>
|
<Post post="@post" showOpenThread="true"></Post>
|
||||||
<hr/>
|
<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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,3 +21,24 @@
|
||||||
.marg{
|
.marg{
|
||||||
margin: 2px
|
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 System.ComponentModel.DataAnnotations
|
||||||
|
@using ImageBoardServerApp.Auth
|
||||||
@using ImageBoardServerApp.Data
|
@using ImageBoardServerApp.Data
|
||||||
|
@using ImageBoardServerApp.Data.Repository
|
||||||
|
@inject AuthenticationStateProvider authStateProvider
|
||||||
|
|
||||||
<div class="threadHeader">
|
<div class="threadHeader">
|
||||||
<span>[</span>
|
@if (showOpenThread)
|
||||||
<a class="toggleOpened" onclick="@ToggleOpened">@toggleText</a>
|
{
|
||||||
<span>]</span>
|
<span>[</span>
|
||||||
|
<a class="toggleOpened" onclick="@ToggleOpened">@toggleText</a>
|
||||||
|
<span>]</span>
|
||||||
|
}
|
||||||
<span class="title">@post.Title</span>
|
<span class="title">@post.Title</span>
|
||||||
<span class="name">@post.Username</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="date">@getTimeFromUnix(post.CreatedAt)</span>
|
||||||
<span class="post-id">No.@post.PostID</span>
|
<span class="post-id">No.@post.PostID</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,10 +24,9 @@
|
||||||
{
|
{
|
||||||
<div class="threadContent">
|
<div class="threadContent">
|
||||||
<div class="threadImage">
|
<div class="threadImage">
|
||||||
<!-- TODO: Make Images Required. -->
|
|
||||||
@if (@post.Image != null)
|
@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
|
else
|
||||||
{
|
{
|
||||||
|
@ -27,27 +36,42 @@
|
||||||
<div class="threadTextContainer">
|
<div class="threadTextContainer">
|
||||||
@foreach (string s in @post.Content.Split("\n"))
|
@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>
|
</div>
|
||||||
<div class="threadFooter">
|
<div class="threadFooter">
|
||||||
<!--<RadzenButton class="bump" Text="bump"></RadzenButton> -->
|
|
||||||
<span>[</span>
|
<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>
|
||||||
<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>
|
<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>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static DateTime getTimeFromUnix(double javaTimeStamp)
|
private static DateTime getTimeFromUnix(double javaTimeStamp)
|
||||||
{
|
{
|
||||||
var dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
var dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
@ -55,6 +79,18 @@
|
||||||
return dateTime;
|
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 bool opened = true;
|
||||||
|
|
||||||
private string toggleText = "-";
|
private string toggleText = "-";
|
||||||
|
@ -68,4 +104,9 @@
|
||||||
[Parameter]
|
[Parameter]
|
||||||
[Required]
|
[Required]
|
||||||
public PostData post { get; set; }
|
public PostData post { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
[Required]
|
||||||
|
public bool showOpenThread { get; set; }
|
||||||
}
|
}
|
|
@ -16,6 +16,14 @@
|
||||||
color: #339305;
|
color: #339305;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Admin{
|
||||||
|
color: #ff191c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Mod{
|
||||||
|
color: #af13d7;
|
||||||
|
}
|
||||||
|
|
||||||
.threadHeader{
|
.threadHeader{
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +38,10 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.greenText{
|
||||||
|
color: #3caf03;
|
||||||
|
}
|
||||||
|
|
||||||
.threadImage{
|
.threadImage{
|
||||||
margin: 6px;
|
margin: 6px;
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
|
@ -43,9 +55,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.threadImage img:hover{
|
.threadImage img:hover{
|
||||||
transform: scale(3);
|
/*transform: scale(3);*/
|
||||||
/*max-width:500px;
|
max-width:500px;
|
||||||
width: 100%; */
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.threadText{
|
.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
|
@inherits LayoutComponentBase
|
||||||
|
@using ImageBoardServerApp.Auth
|
||||||
|
@inject AuthenticationStateProvider authStateProvider
|
||||||
|
@inject NavigationManager navManager
|
||||||
|
|
||||||
<PageTitle>BulletBoard</PageTitle>
|
<PageTitle>BulletBoard</PageTitle>
|
||||||
|
|
||||||
|
@ -8,9 +11,19 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
|
|
||||||
<div class="top-row px-4">
|
<div class="top-row px-4">
|
||||||
<a href="/faq">[FAQ]</a>
|
<a href="/faq">[FAQ]</a>
|
||||||
<a href="/rules">[Rules]</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>
|
</div>
|
||||||
|
|
||||||
<article class="content px-4">
|
<article class="content px-4">
|
||||||
|
@ -18,3 +31,26 @@
|
||||||
</article>
|
</article>
|
||||||
</main>
|
</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>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-item px-3">
|
<div class="nav-item px-3">
|
||||||
<NavLink class="nav-link" href="b">
|
<NavLink class="nav-link" href="m">
|
||||||
<span class="oi oi-list-rich" aria-hidden="true"></span> /b/ - Random
|
<span class="oi oi-list-rich" aria-hidden="true"></span> /m/ - Main
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
@ -6,11 +6,16 @@
|
||||||
@using Microsoft.AspNetCore.Components.Web
|
@using Microsoft.AspNetCore.Components.Web
|
||||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||||
@using Microsoft.JSInterop
|
@using Microsoft.JSInterop
|
||||||
@using ImageBoardServerApp
|
|
||||||
@using ImageBoardServerApp.Shared
|
|
||||||
@using Radzen
|
@using Radzen
|
||||||
@using Radzen.Blazor
|
@using Radzen.Blazor
|
||||||
@using ImageBoardServerApp
|
@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
|
||||||
@using ImageBoardServerApp.Shared.Components
|
@using ImageBoardServerApp.Shared.Components
|
||||||
|
@using ImageBoardServerApp.Shared.Components.Forms
|
||||||
@using ImageBoardServerApp.Data
|
@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