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<CouponUse> CouponUses { get; set; }
// Posts
// Community
public DbSet<Post> Posts { get; set; }
public DbSet<PostComment> PostComments { get; set; }
public DbSet<PostLike> PostLikes { get; set; }
public DbSet<WordFilter> WordFilters { get; set; }
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");
});
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")

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<PostLike> PostLikeRepository;
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;
PostLikeRepository = postLikeRepository;
PostCommentRepository = postCommentRepository;
WordFilterRepository = wordFilterRepository;
}
// Posts
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()
{
Author = user,
@ -43,6 +55,12 @@ public class PostService
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.Content = content;
post.UpdatedAt = DateTime.UtcNow;
@ -95,6 +113,9 @@ public class PostService
if (!Regex.IsMatch(content, "^[ a-zA-Z0-9äöüßÄÖÜẞ,.;_\\n\\t-]+$"))
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
var comment = new PostComment()
@ -157,4 +178,23 @@ public class PostService
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 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" : "")">
<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)
</a>
</li>

View file

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

View file

@ -16,6 +16,9 @@
<div class="modal-body">
<div class="mb-3">
<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"/>
</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>
</a>
</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>

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.Repositories
@using BlazorTable
@using Moonlight.App.Extensions.Attributes
@using Moonlight.App.Models.Enums
@using Moonlight.App.Models.Forms.Admin.Store
@attribute [RequirePermission(Permission.AdminStore)]
@inject Repository<Coupon> CouponRepository
<AdminStoreNavigation Index="1"/>

View file

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

View file

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

View file

@ -14,8 +14,8 @@
<div class="row">
<div class="col-md-2 col-12 mb-5">
<CommunityNavigation Index="1" />
<CommunityNavigation Index="1"/>
@if (IdentityService.Permissions[Permission.AdminCommunity])
{
<div class="card card-body mt-5">
@ -24,28 +24,26 @@
}
</div>
<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">
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
</div>
</div>
<div class="row mt-3">
<LazyLoader @ref="LazyLoader" Load="Load">
@foreach (var post in Posts)
{
<PostView Post="post" OnUpdate="() => LazyLoader.Reload()"/>
<div class="mb-10"></div>
}
</LazyLoader>
</div>
<LazyLoader @ref="LazyLoader" Load="Load">
@foreach (var post in Posts)
{
<PostView Post="post" OnUpdate="() => LazyLoader.Reload()"/>
<div class="mb-10"></div>
}
</LazyLoader>
</div>
</div>
@if (IdentityService.Permissions[Permission.AdminCommunity])
{
<CreatePostModal @ref="CreateModal" OnUpdate="() => LazyLoader.Reload()" PostType="PostType.Event" />
<CreatePostModal @ref="CreateModal" OnUpdate="() => LazyLoader.Reload()" PostType="PostType.Event"/>
}
@code

View file

@ -11,14 +11,14 @@
<div class="row">
<div class="col-md-2 col-12 mb-5">
<CommunityNavigation Index="2" />
<CommunityNavigation Index="2"/>
<div class="card card-body mt-5">
<button @onclick="() => CreateModal.Show()" class="btn btn-success">Create new post</button>
</div>
</div>
<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">
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.
@ -26,19 +26,17 @@
</div>
</div>
<div class="row mt-3">
<LazyLoader @ref="LazyLoader" Load="Load">
@foreach (var post in Posts)
{
<PostView Post="post" OnUpdate="() => LazyLoader.Reload()"/>
<div class="mb-10"></div>
}
</LazyLoader>
</div>
<LazyLoader @ref="LazyLoader" Load="Load">
@foreach (var post in Posts)
{
<PostView Post="post" OnUpdate="() => LazyLoader.Reload()"/>
<div class="mb-10"></div>
}
</LazyLoader>
</div>
</div>
<CreatePostModal @ref="CreateModal" OnUpdate="() => LazyLoader.Reload()" PostType="PostType.Event" />
<CreatePostModal @ref="CreateModal" OnUpdate="() => LazyLoader.Reload()" PostType="PostType.Project"/>
@code
{