Fixed some bugs. Added admin ui. Added word filter

This commit is contained in:
Marcel Baumgartner
2023-10-29 00:49:15 +02:00
parent c4e7e10f5e
commit 122a205f92
20 changed files with 804 additions and 31 deletions

View File

@@ -27,10 +27,11 @@ public class DataContext : DbContext
public DbSet<Coupon> Coupons { get; set; } public DbSet<Coupon> Coupons { get; set; }
public DbSet<CouponUse> CouponUses { get; set; } public DbSet<CouponUse> CouponUses { get; set; }
// Posts // Community
public DbSet<Post> Posts { get; set; } public DbSet<Post> Posts { get; set; }
public DbSet<PostComment> PostComments { get; set; } public DbSet<PostComment> PostComments { get; set; }
public DbSet<PostLike> PostLikes { get; set; } public DbSet<PostLike> PostLikes { get; set; }
public DbSet<WordFilter> WordFilters { get; set; }
public DataContext(ConfigService configService) public DataContext(ConfigService configService)
{ {

View File

@@ -0,0 +1,7 @@
namespace Moonlight.App.Database.Entities.Community;
public class WordFilter
{
public int Id { get; set; }
public string Filter { get; set; } = "";
}

View File

@@ -0,0 +1,554 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Moonlight.App.Database;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
[DbContext(typeof(DataContext))]
[Migration("20231028214520_AddedWordFilter")]
partial class AddedWordFilter
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.2");
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("AuthorId")
.HasColumnType("INTEGER");
b.Property<string>("Content")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("AuthorId");
b.ToTable("Posts");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostComment", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("AuthorId")
.HasColumnType("INTEGER");
b.Property<string>("Content")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<int?>("PostId")
.HasColumnType("INTEGER");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("AuthorId");
b.HasIndex("PostId");
b.ToTable("PostComments");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostLike", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<int?>("PostId")
.HasColumnType("INTEGER");
b.Property<int>("UserId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("PostId");
b.HasIndex("UserId");
b.ToTable("PostLikes");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.WordFilter", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Filter")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("WordFilters");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Category", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Slug")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Categories");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Coupon", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Amount")
.HasColumnType("INTEGER");
b.Property<string>("Code")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Percent")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.ToTable("Coupons");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("CouponId")
.HasColumnType("INTEGER");
b.Property<int?>("UserId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("CouponId");
b.HasIndex("UserId");
b.ToTable("CouponUses");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCode", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Amount")
.HasColumnType("INTEGER");
b.Property<string>("Code")
.IsRequired()
.HasColumnType("TEXT");
b.Property<double>("Value")
.HasColumnType("REAL");
b.HasKey("Id");
b.ToTable("GiftCodes");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("GiftCodeId")
.HasColumnType("INTEGER");
b.Property<int?>("UserId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("GiftCodeId");
b.HasIndex("UserId");
b.ToTable("GiftCodeUses");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("CategoryId")
.HasColumnType("INTEGER");
b.Property<string>("ConfigJson")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Duration")
.HasColumnType("INTEGER");
b.Property<int>("MaxPerUser")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<double>("Price")
.HasColumnType("REAL");
b.Property<string>("Slug")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Stock")
.HasColumnType("INTEGER");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.ToTable("Products");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ConfigJsonOverride")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<string>("Nickname")
.HasColumnType("TEXT");
b.Property<int>("OwnerId")
.HasColumnType("INTEGER");
b.Property<int>("ProductId")
.HasColumnType("INTEGER");
b.Property<DateTime>("RenewAt")
.HasColumnType("TEXT");
b.Property<bool>("Suspended")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("OwnerId");
b.HasIndex("ProductId");
b.ToTable("Services");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int?>("ServiceId")
.HasColumnType("INTEGER");
b.Property<int>("UserId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("ServiceId");
b.HasIndex("UserId");
b.ToTable("ServiceShares");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Transaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<double>("Price")
.HasColumnType("REAL");
b.Property<string>("Text")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int?>("UserId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("Transaction");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Avatar")
.HasColumnType("TEXT");
b.Property<double>("Balance")
.HasColumnType("REAL");
b.Property<DateTime>("CreatedAt")
.HasColumnType("TEXT");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Flags")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("Permissions")
.HasColumnType("INTEGER");
b.Property<DateTime>("TokenValidTimestamp")
.HasColumnType("TEXT");
b.Property<string>("TotpKey")
.HasColumnType("TEXT");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("Users");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
{
b.HasOne("Moonlight.App.Database.Entities.User", "Author")
.WithMany()
.HasForeignKey("AuthorId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Author");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostComment", b =>
{
b.HasOne("Moonlight.App.Database.Entities.User", "Author")
.WithMany()
.HasForeignKey("AuthorId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Moonlight.App.Database.Entities.Community.Post", null)
.WithMany("Comments")
.HasForeignKey("PostId");
b.Navigation("Author");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostLike", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Community.Post", null)
.WithMany("Likes")
.HasForeignKey("PostId");
b.HasOne("Moonlight.App.Database.Entities.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Store.Coupon", "Coupon")
.WithMany()
.HasForeignKey("CouponId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Moonlight.App.Database.Entities.User", null)
.WithMany("CouponUses")
.HasForeignKey("UserId");
b.Navigation("Coupon");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Store.GiftCode", "GiftCode")
.WithMany()
.HasForeignKey("GiftCodeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Moonlight.App.Database.Entities.User", null)
.WithMany("GiftCodeUses")
.HasForeignKey("UserId");
b.Navigation("GiftCode");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Store.Category", "Category")
.WithMany()
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
{
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Moonlight.App.Database.Entities.Store.Product", "Product")
.WithMany()
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Owner");
b.Navigation("Product");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Store.Service", null)
.WithMany("Shares")
.HasForeignKey("ServiceId");
b.HasOne("Moonlight.App.Database.Entities.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Transaction", b =>
{
b.HasOne("Moonlight.App.Database.Entities.User", null)
.WithMany("Transactions")
.HasForeignKey("UserId");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
{
b.Navigation("Comments");
b.Navigation("Likes");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
{
b.Navigation("Shares");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
{
b.Navigation("CouponUses");
b.Navigation("GiftCodeUses");
b.Navigation("Transactions");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,34 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
/// <inheritdoc />
public partial class AddedWordFilter : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "WordFilters",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Filter = table.Column<string>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_WordFilters", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "WordFilters");
}
}
}

View File

@@ -105,6 +105,21 @@ namespace Moonlight.App.Database.Migrations
b.ToTable("PostLikes"); b.ToTable("PostLikes");
}); });
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.WordFilter", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Filter")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("WordFilters");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Category", b => modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Category", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")

View File

@@ -0,0 +1,12 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace Moonlight.App.Models.Forms.Admin.Community;
public class AddWordFilter
{
[Required(ErrorMessage = "You need to specify a filter")]
[Description(
"This filters all posts and comments created using this regex. If any match is found it will block the action")]
public string Filter { get; set; } = "";
}

View File

@@ -0,0 +1,12 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace Moonlight.App.Models.Forms.Admin.Community;
public class EditWordFilter
{
[Required(ErrorMessage = "You need to specify a filter")]
[Description(
"This filters all posts and comments created using this regex. If any match is found it will block the action")]
public string Filter { get; set; } = "";
}

View File

@@ -15,17 +15,29 @@ public class PostService
private readonly Repository<Post> PostRepository; private readonly Repository<Post> PostRepository;
private readonly Repository<PostLike> PostLikeRepository; private readonly Repository<PostLike> PostLikeRepository;
private readonly Repository<PostComment> PostCommentRepository; private readonly Repository<PostComment> PostCommentRepository;
private readonly Repository<WordFilter> WordFilterRepository;
public PostService(Repository<Post> postRepository, Repository<PostLike> postLikeRepository, Repository<PostComment> postCommentRepository) public PostService(
Repository<Post> postRepository,
Repository<PostLike> postLikeRepository,
Repository<PostComment> postCommentRepository,
Repository<WordFilter> wordFilterRepository)
{ {
PostRepository = postRepository; PostRepository = postRepository;
PostLikeRepository = postLikeRepository; PostLikeRepository = postLikeRepository;
PostCommentRepository = postCommentRepository; PostCommentRepository = postCommentRepository;
WordFilterRepository = wordFilterRepository;
} }
// Posts // Posts
public async Task<Post> Create(User user, string title, string content, PostType type) public async Task<Post> Create(User user, string title, string content, PostType type)
{ {
if(await CheckTextForBadWords(title))
throw new DisplayException("Bad word detected. Please follow the community rules");
if(await CheckTextForBadWords(content))
throw new DisplayException("Bad word detected. Please follow the community rules");
var post = new Post() var post = new Post()
{ {
Author = user, Author = user,
@@ -43,6 +55,12 @@ public class PostService
public async Task Update(Post post, string title, string content) public async Task Update(Post post, string title, string content)
{ {
if(await CheckTextForBadWords(title))
throw new DisplayException("Bad word detected. Please follow the community rules");
if(await CheckTextForBadWords(content))
throw new DisplayException("Bad word detected. Please follow the community rules");
post.Title = title; post.Title = title;
post.Content = content; post.Content = content;
post.UpdatedAt = DateTime.UtcNow; post.UpdatedAt = DateTime.UtcNow;
@@ -95,6 +113,9 @@ public class PostService
if (!Regex.IsMatch(content, "^[ a-zA-Z0-9äöüßÄÖÜẞ,.;_\\n\\t-]+$")) if (!Regex.IsMatch(content, "^[ a-zA-Z0-9äöüßÄÖÜẞ,.;_\\n\\t-]+$"))
throw new DisplayException("Illegal characters in comment content"); throw new DisplayException("Illegal characters in comment content");
if(await CheckTextForBadWords(content))
throw new DisplayException("Bad word detected. Please follow the community rules");
//TODO: Swear word filter //TODO: Swear word filter
var comment = new PostComment() var comment = new PostComment()
@@ -157,4 +178,23 @@ public class PostService
await Events.OnPostLiked.InvokeAsync(postWithLikes); await Events.OnPostLiked.InvokeAsync(postWithLikes);
} }
} }
// Utils
private Task<bool> CheckTextForBadWords(string input) // This method checks for bad words using the filters added by an admin
{
var filters = WordFilterRepository
.Get()
.Select(x => x.Filter)
.ToArray();
//TODO: Add timer for regex matching to create warnings
foreach (var filter in filters)
{
if (Regex.IsMatch(input, filter))
return Task.FromResult(true);
}
return Task.FromResult(false);
}
} }

View File

@@ -57,7 +57,14 @@
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a @onclick="ToggleLike" @onclick:preventDefault href="#" class="nav-link btn btn-sm btn-color-gray-600 btn-active-color-danger fw-bold px-4 me-1 @(HasLiked ? "active" : "")"> <a @onclick="ToggleLike" @onclick:preventDefault href="#" class="nav-link btn btn-sm btn-color-gray-600 btn-active-color-danger fw-bold px-4 me-1 @(HasLiked ? "active" : "")">
<i class="bx bx-heart fs-2 me-1"></i> @if (HasLiked)
{
<i class="bx bxs-heart fs-2 me-1"></i>
}
else
{
<i class="bx bx-heart fs-2 me-1"></i>
}
@(LikesCount) Like(s) @(LikesCount) Like(s)
</a> </a>
</li> </li>

View File

@@ -54,7 +54,7 @@
<SmartForm Model="CreateForm" OnValidSubmit="FinishCreate"> <SmartForm Model="CreateForm" OnValidSubmit="FinishCreate">
<div class="modal-body"> <div class="modal-body">
<div class="row"> <div class="row">
<AutoForm Columns="6" Model="CreateForm"/> <AutoForm Columns="@(CreateForm.GetType().GetProperties().Length > 1 ? 6 : 12)" Model="CreateForm"/>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
@@ -72,7 +72,7 @@
<SmartForm Model="UpdateForm" OnValidSubmit="FinishUpdate"> <SmartForm Model="UpdateForm" OnValidSubmit="FinishUpdate">
<div class="modal-body"> <div class="modal-body">
<div class="row"> <div class="row">
<AutoForm Columns="6" Model="UpdateForm"/> <AutoForm Columns="@(UpdateForm.GetType().GetProperties().Length > 1 ? 6 : 12)" Model="UpdateForm"/>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">

View File

@@ -16,6 +16,9 @@
<div class="modal-body"> <div class="modal-body">
<div class="mb-3"> <div class="mb-3">
<label class="form-label">Title</label> <label class="form-label">Title</label>
<div class="form-text fs-5 mb-2 mt-0">
This title is used for the preview of posts. It will not be shown in a regular post view
</div>
<input @bind="Form.Title" class="form-control form-control-solid-bg"/> <input @bind="Form.Title" class="form-control form-control-solid-bg"/>
</div> </div>
<div> <div>

View File

@@ -0,0 +1,22 @@
<div class="card mb-5 mb-xl-10">
<div class="card-body pt-0 pb-0">
<ul class="nav nav-stretch nav-line-tabs nav-line-tabs-2x border-transparent fs-5 fw-bold">
<li class="nav-item mt-2">
<a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 0 ? "active" : "")" href="/admin/community">
<i class="bx bx-sm bx-group me-2"></i> Overview
</a>
</li>
<li class="nav-item mt-2">
<a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 1 ? "active" : "")" href="/admin/community/filter">
<i class="bx bx-sm bx-filter-alt me-2"></i> Filter
</a>
</li>
</ul>
</div>
</div>
@code
{
[Parameter]
public int Index { get; set; }
}

View File

@@ -94,6 +94,17 @@
</span> </span>
</a> </a>
</div> </div>
<div class="menu-item">
<a class="menu-link " href="/admin/community">
<span class="menu-icon">
<i class="bx bx-sm bx-group"></i>
</span>
<span class="menu-title">
Community
</span>
</a>
</div>
} }
</div> </div>
</div> </div>

View File

@@ -0,0 +1,38 @@
@page "/admin/community/filter"
@using Moonlight.App.Extensions.Attributes
@using Moonlight.App.Models.Enums
@using BlazorTable
@using Moonlight.App.Database.Entities.Community
@using Moonlight.App.Models.Forms.Admin.Community
@using Moonlight.App.Repositories
@attribute [RequirePermission(Permission.AdminCommunity)]
<AdminCommunityNavigation Index="1" />
<div class="card card-body border-primary fs-5 mt-5">
To protect from trollers and toxic people you can configure words using
regex expressions to block automatically to ensure no one can write bad things in the community tab.
</div>
<div class="mt-5">
<AutoCrud TItem="WordFilter"
TCreateForm="AddWordFilter"
TUpdateForm="EditWordFilter"
Title="Manage word filter"
Load="LoadData">
<Column TableItem="WordFilter" Field="@(x => x.Id)" Title="Id" Sortable="false" Filterable="true" />
<Column TableItem="WordFilter" Field="@(x => x.Filter)" Title="Filter" Sortable="false" Filterable="true" />
</AutoCrud>
</div>
@code
{
private WordFilter[] LoadData(Repository<WordFilter> repository)
{
return repository
.Get()
.ToArray();
}
}

View File

@@ -0,0 +1,8 @@
@page "/admin/community"
@using Moonlight.App.Extensions.Attributes
@using Moonlight.App.Models.Enums
@attribute [RequirePermission(Permission.AdminCommunity)]
<AdminCommunityNavigation Index="0" />

View File

@@ -3,8 +3,12 @@
@using Moonlight.App.Database.Entities.Store @using Moonlight.App.Database.Entities.Store
@using Moonlight.App.Repositories @using Moonlight.App.Repositories
@using BlazorTable @using BlazorTable
@using Moonlight.App.Extensions.Attributes
@using Moonlight.App.Models.Enums
@using Moonlight.App.Models.Forms.Admin.Store @using Moonlight.App.Models.Forms.Admin.Store
@attribute [RequirePermission(Permission.AdminStore)]
@inject Repository<Coupon> CouponRepository @inject Repository<Coupon> CouponRepository
<AdminStoreNavigation Index="1"/> <AdminStoreNavigation Index="1"/>

View File

@@ -4,6 +4,10 @@
@using Moonlight.App.Models.Forms.Admin.Store @using Moonlight.App.Models.Forms.Admin.Store
@using Moonlight.App.Repositories @using Moonlight.App.Repositories
@using BlazorTable @using BlazorTable
@using Moonlight.App.Extensions.Attributes
@using Moonlight.App.Models.Enums
@attribute [RequirePermission(Permission.AdminStore)]
@inject Repository<GiftCode> GiftCodeRepository @inject Repository<GiftCode> GiftCodeRepository

View File

@@ -1,3 +1,8 @@
@page "/admin/store" @page "/admin/store"
@using Moonlight.App.Extensions.Attributes
@using Moonlight.App.Models.Enums
@attribute [RequirePermission(Permission.AdminStore)]
<AdminStoreNavigation Index="0"/> <AdminStoreNavigation Index="0"/>

View File

@@ -14,7 +14,7 @@
<div class="row"> <div class="row">
<div class="col-md-2 col-12 mb-5"> <div class="col-md-2 col-12 mb-5">
<CommunityNavigation Index="1" /> <CommunityNavigation Index="1"/>
@if (IdentityService.Permissions[Permission.AdminCommunity]) @if (IdentityService.Permissions[Permission.AdminCommunity])
{ {
@@ -24,28 +24,26 @@
} }
</div> </div>
<div class="col-md-10 col-12"> <div class="col-md-10 col-12">
<div class="card border-primary"> <div class="card border-primary mb-5">
<div class="card-body fs-5"> <div class="card-body fs-5">
Planned events and current happenings can be found here. Planned events and current happenings can be found here.
If you want to know what will happen in the future or is going on now have a look at the posts below If you want to know what will happen in the future or is going on now have a look at the posts below
</div> </div>
</div> </div>
<div class="row mt-3"> <LazyLoader @ref="LazyLoader" Load="Load">
<LazyLoader @ref="LazyLoader" Load="Load"> @foreach (var post in Posts)
@foreach (var post in Posts) {
{ <PostView Post="post" OnUpdate="() => LazyLoader.Reload()"/>
<PostView Post="post" OnUpdate="() => LazyLoader.Reload()"/> <div class="mb-10"></div>
<div class="mb-10"></div> }
} </LazyLoader>
</LazyLoader>
</div>
</div> </div>
</div> </div>
@if (IdentityService.Permissions[Permission.AdminCommunity]) @if (IdentityService.Permissions[Permission.AdminCommunity])
{ {
<CreatePostModal @ref="CreateModal" OnUpdate="() => LazyLoader.Reload()" PostType="PostType.Event" /> <CreatePostModal @ref="CreateModal" OnUpdate="() => LazyLoader.Reload()" PostType="PostType.Event"/>
} }
@code @code

View File

@@ -11,14 +11,14 @@
<div class="row"> <div class="row">
<div class="col-md-2 col-12 mb-5"> <div class="col-md-2 col-12 mb-5">
<CommunityNavigation Index="2" /> <CommunityNavigation Index="2"/>
<div class="card card-body mt-5"> <div class="card card-body mt-5">
<button @onclick="() => CreateModal.Show()" class="btn btn-success">Create new post</button> <button @onclick="() => CreateModal.Show()" class="btn btn-success">Create new post</button>
</div> </div>
</div> </div>
<div class="col-md-10 col-12"> <div class="col-md-10 col-12">
<div class="card border-primary"> <div class="card border-primary mb-5">
<div class="card-body fs-5"> <div class="card-body fs-5">
You have a interesting project or a fun game server you want to share with the community? You have a interesting project or a fun game server you want to share with the community?
You can share it here. Please keep in mind to follow basic rules and dont offend anyone. You can share it here. Please keep in mind to follow basic rules and dont offend anyone.
@@ -26,19 +26,17 @@
</div> </div>
</div> </div>
<div class="row mt-3"> <LazyLoader @ref="LazyLoader" Load="Load">
<LazyLoader @ref="LazyLoader" Load="Load"> @foreach (var post in Posts)
@foreach (var post in Posts) {
{ <PostView Post="post" OnUpdate="() => LazyLoader.Reload()"/>
<PostView Post="post" OnUpdate="() => LazyLoader.Reload()"/> <div class="mb-10"></div>
<div class="mb-10"></div> }
} </LazyLoader>
</LazyLoader>
</div>
</div> </div>
</div> </div>
<CreatePostModal @ref="CreateModal" OnUpdate="() => LazyLoader.Reload()" PostType="PostType.Event" /> <CreatePostModal @ref="CreateModal" OnUpdate="() => LazyLoader.Reload()" PostType="PostType.Project"/>
@code @code
{ {