feat: moderation API
This commit is contained in:
parent
79b8c4799e
commit
36cb1d2043
24 changed files with 1535 additions and 45 deletions
|
@ -71,6 +71,10 @@ public class DatabaseContext(DbContextOptions options) : DbContext(options)
|
|||
public DbSet<UserFlag> UserFlags { get; init; } = null!;
|
||||
public DbSet<MemberFlag> MemberFlags { get; init; } = null!;
|
||||
|
||||
public DbSet<Report> Reports { get; init; } = null!;
|
||||
public DbSet<AuditLogEntry> AuditLog { get; init; } = null!;
|
||||
public DbSet<Notification> Notifications { get; init; } = null!;
|
||||
|
||||
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
|
||||
{
|
||||
// Snowflakes are stored as longs
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using NodaTime;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Foxnouns.Backend.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[DbContext(typeof(DatabaseContext))]
|
||||
[Migration("20241217010207_AddReports")]
|
||||
public partial class AddReports : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterDatabase().Annotation("Npgsql:PostgresExtension:hstore", ",,");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "notifications",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<long>(type: "bigint", nullable: false),
|
||||
target_id = table.Column<long>(type: "bigint", nullable: false),
|
||||
type = table.Column<int>(type: "integer", nullable: false),
|
||||
message = table.Column<string>(type: "text", nullable: true),
|
||||
localization_key = table.Column<string>(type: "text", nullable: true),
|
||||
localization_params = table.Column<Dictionary<string, string>>(
|
||||
type: "hstore",
|
||||
nullable: false
|
||||
),
|
||||
acknowledged_at = table.Column<Instant>(
|
||||
type: "timestamp with time zone",
|
||||
nullable: true
|
||||
),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_notifications", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_notifications_users_target_id",
|
||||
column: x => x.target_id,
|
||||
principalTable: "users",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "reports",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<long>(type: "bigint", nullable: false),
|
||||
reporter_id = table.Column<long>(type: "bigint", nullable: false),
|
||||
target_user_id = table.Column<long>(type: "bigint", nullable: false),
|
||||
target_member_id = table.Column<long>(type: "bigint", nullable: true),
|
||||
status = table.Column<int>(type: "integer", nullable: false),
|
||||
reason = table.Column<int>(type: "integer", nullable: false),
|
||||
target_type = table.Column<int>(type: "integer", nullable: false),
|
||||
target_snapshot = table.Column<string>(type: "text", nullable: true),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_reports", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_reports_members_target_member_id",
|
||||
column: x => x.target_member_id,
|
||||
principalTable: "members",
|
||||
principalColumn: "id"
|
||||
);
|
||||
table.ForeignKey(
|
||||
name: "fk_reports_users_reporter_id",
|
||||
column: x => x.reporter_id,
|
||||
principalTable: "users",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade
|
||||
);
|
||||
table.ForeignKey(
|
||||
name: "fk_reports_users_target_user_id",
|
||||
column: x => x.target_user_id,
|
||||
principalTable: "users",
|
||||
principalColumn: "id",
|
||||
onDelete: ReferentialAction.Cascade
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "audit_log",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<long>(type: "bigint", nullable: false),
|
||||
moderator_id = table.Column<long>(type: "bigint", nullable: false),
|
||||
moderator_username = table.Column<string>(type: "text", nullable: false),
|
||||
target_user_id = table.Column<long>(type: "bigint", nullable: true),
|
||||
target_username = table.Column<string>(type: "text", nullable: true),
|
||||
target_member_id = table.Column<long>(type: "bigint", nullable: true),
|
||||
target_member_name = table.Column<string>(type: "text", nullable: true),
|
||||
report_id = table.Column<long>(type: "bigint", nullable: true),
|
||||
type = table.Column<int>(type: "integer", nullable: false),
|
||||
reason = table.Column<string>(type: "text", nullable: true),
|
||||
cleared_fields = table.Column<string[]>(type: "text[]", nullable: true),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_audit_log", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_audit_log_reports_report_id",
|
||||
column: x => x.report_id,
|
||||
principalTable: "reports",
|
||||
principalColumn: "id"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_audit_log_report_id",
|
||||
table: "audit_log",
|
||||
column: "report_id"
|
||||
);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_notifications_target_id",
|
||||
table: "notifications",
|
||||
column: "target_id"
|
||||
);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_reports_reporter_id",
|
||||
table: "reports",
|
||||
column: "reporter_id"
|
||||
);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_reports_target_member_id",
|
||||
table: "reports",
|
||||
column: "target_member_id"
|
||||
);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_reports_target_user_id",
|
||||
table: "reports",
|
||||
column: "target_user_id"
|
||||
);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(name: "audit_log");
|
||||
|
||||
migrationBuilder.DropTable(name: "notifications");
|
||||
|
||||
migrationBuilder.DropTable(name: "reports");
|
||||
|
||||
migrationBuilder.AlterDatabase().OldAnnotation("Npgsql:PostgresExtension:hstore", ",,");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ namespace Foxnouns.Backend.Database.Migrations
|
|||
.HasAnnotation("ProductVersion", "9.0.0")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore");
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.Application", b =>
|
||||
|
@ -61,6 +62,62 @@ namespace Foxnouns.Backend.Database.Migrations
|
|||
b.ToTable("applications", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuditLogEntry", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.PrimitiveCollection<string[]>("ClearedFields")
|
||||
.HasColumnType("text[]")
|
||||
.HasColumnName("cleared_fields");
|
||||
|
||||
b.Property<long>("ModeratorId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("moderator_id");
|
||||
|
||||
b.Property<string>("ModeratorUsername")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("moderator_username");
|
||||
|
||||
b.Property<string>("Reason")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("reason");
|
||||
|
||||
b.Property<long?>("ReportId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("report_id");
|
||||
|
||||
b.Property<long?>("TargetMemberId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("target_member_id");
|
||||
|
||||
b.Property<string>("TargetMemberName")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("target_member_name");
|
||||
|
||||
b.Property<long?>("TargetUserId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("target_user_id");
|
||||
|
||||
b.Property<string>("TargetUsername")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("target_username");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("type");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_audit_log");
|
||||
|
||||
b.HasIndex("ReportId")
|
||||
.HasDatabaseName("ix_audit_log_report_id");
|
||||
|
||||
b.ToTable("audit_log", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuthMethod", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
|
@ -270,6 +327,45 @@ namespace Foxnouns.Backend.Database.Migrations
|
|||
b.ToTable("member_flags", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notification", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<Instant?>("AcknowledgedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("acknowledged_at");
|
||||
|
||||
b.Property<string>("LocalizationKey")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("localization_key");
|
||||
|
||||
b.Property<Dictionary<string, string>>("LocalizationParams")
|
||||
.HasColumnType("hstore")
|
||||
.HasColumnName("localization_params");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("message");
|
||||
|
||||
b.Property<long>("TargetId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("target_id");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("type");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_notifications");
|
||||
|
||||
b.HasIndex("TargetId")
|
||||
.HasDatabaseName("ix_notifications_target_id");
|
||||
|
||||
b.ToTable("notifications", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.PrideFlag", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
|
@ -302,6 +398,55 @@ namespace Foxnouns.Backend.Database.Migrations
|
|||
b.ToTable("pride_flags", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.Report", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<int>("Reason")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("reason");
|
||||
|
||||
b.Property<long>("ReporterId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("reporter_id");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("status");
|
||||
|
||||
b.Property<long?>("TargetMemberId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("target_member_id");
|
||||
|
||||
b.Property<string>("TargetSnapshot")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("target_snapshot");
|
||||
|
||||
b.Property<int>("TargetType")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("target_type");
|
||||
|
||||
b.Property<long>("TargetUserId")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("target_user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_reports");
|
||||
|
||||
b.HasIndex("ReporterId")
|
||||
.HasDatabaseName("ix_reports_reporter_id");
|
||||
|
||||
b.HasIndex("TargetMemberId")
|
||||
.HasDatabaseName("ix_reports_target_member_id");
|
||||
|
||||
b.HasIndex("TargetUserId")
|
||||
.HasDatabaseName("ix_reports_target_user_id");
|
||||
|
||||
b.ToTable("reports", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.TemporaryKey", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
|
@ -522,6 +667,16 @@ namespace Foxnouns.Backend.Database.Migrations
|
|||
b.ToTable("user_flags", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuditLogEntry", b =>
|
||||
{
|
||||
b.HasOne("Foxnouns.Backend.Database.Models.Report", "Report")
|
||||
.WithMany()
|
||||
.HasForeignKey("ReportId")
|
||||
.HasConstraintName("fk_audit_log_reports_report_id");
|
||||
|
||||
b.Navigation("Report");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuthMethod", b =>
|
||||
{
|
||||
b.HasOne("Foxnouns.Backend.Database.Models.FediverseApplication", "FediverseApplication")
|
||||
|
@ -584,6 +739,18 @@ namespace Foxnouns.Backend.Database.Migrations
|
|||
b.Navigation("PrideFlag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notification", b =>
|
||||
{
|
||||
b.HasOne("Foxnouns.Backend.Database.Models.User", "Target")
|
||||
.WithMany()
|
||||
.HasForeignKey("TargetId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_notifications_users_target_id");
|
||||
|
||||
b.Navigation("Target");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.PrideFlag", b =>
|
||||
{
|
||||
b.HasOne("Foxnouns.Backend.Database.Models.User", null)
|
||||
|
@ -594,6 +761,34 @@ namespace Foxnouns.Backend.Database.Migrations
|
|||
.HasConstraintName("fk_pride_flags_users_user_id");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.Report", b =>
|
||||
{
|
||||
b.HasOne("Foxnouns.Backend.Database.Models.User", "Reporter")
|
||||
.WithMany()
|
||||
.HasForeignKey("ReporterId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_reports_users_reporter_id");
|
||||
|
||||
b.HasOne("Foxnouns.Backend.Database.Models.Member", "TargetMember")
|
||||
.WithMany()
|
||||
.HasForeignKey("TargetMemberId")
|
||||
.HasConstraintName("fk_reports_members_target_member_id");
|
||||
|
||||
b.HasOne("Foxnouns.Backend.Database.Models.User", "TargetUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("TargetUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("fk_reports_users_target_user_id");
|
||||
|
||||
b.Navigation("Reporter");
|
||||
|
||||
b.Navigation("TargetMember");
|
||||
|
||||
b.Navigation("TargetUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Foxnouns.Backend.Database.Models.Token", b =>
|
||||
{
|
||||
b.HasOne("Foxnouns.Backend.Database.Models.Application", "Application")
|
||||
|
|
43
Foxnouns.Backend/Database/Models/AuditLogEntry.cs
Normal file
43
Foxnouns.Backend/Database/Models/AuditLogEntry.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
using Foxnouns.Backend.Utils;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Foxnouns.Backend.Database.Models;
|
||||
|
||||
public class AuditLogEntry : BaseModel
|
||||
{
|
||||
public Snowflake ModeratorId { get; init; }
|
||||
public string ModeratorUsername { get; init; } = string.Empty;
|
||||
public Snowflake? TargetUserId { get; init; }
|
||||
public string? TargetUsername { get; init; }
|
||||
public Snowflake? TargetMemberId { get; init; }
|
||||
public string? TargetMemberName { get; init; }
|
||||
public Snowflake? ReportId { get; init; }
|
||||
public Report? Report { get; init; }
|
||||
|
||||
public AuditLogEntryType Type { get; init; }
|
||||
public string? Reason { get; init; }
|
||||
public string[]? ClearedFields { get; init; }
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(ScreamingSnakeCaseEnumConverter))]
|
||||
public enum AuditLogEntryType
|
||||
{
|
||||
IgnoreReport,
|
||||
WarnUser,
|
||||
WarnUserAndClearProfile,
|
||||
SuspendUser,
|
||||
}
|
41
Foxnouns.Backend/Database/Models/Notification.cs
Normal file
41
Foxnouns.Backend/Database/Models/Notification.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
using Foxnouns.Backend.Utils;
|
||||
using Newtonsoft.Json;
|
||||
using NodaTime;
|
||||
|
||||
namespace Foxnouns.Backend.Database.Models;
|
||||
|
||||
public class Notification : BaseModel
|
||||
{
|
||||
public Snowflake TargetId { get; init; }
|
||||
public User Target { get; init; } = null!;
|
||||
|
||||
public NotificationType Type { get; init; }
|
||||
|
||||
public string? Message { get; init; }
|
||||
public string? LocalizationKey { get; init; }
|
||||
public Dictionary<string, string> LocalizationParams { get; init; } = [];
|
||||
|
||||
public Instant? AcknowledgedAt { get; set; }
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(ScreamingSnakeCaseEnumConverter))]
|
||||
public enum NotificationType
|
||||
{
|
||||
Notice,
|
||||
Warning,
|
||||
Suspension,
|
||||
}
|
73
Foxnouns.Backend/Database/Models/Report.cs
Normal file
73
Foxnouns.Backend/Database/Models/Report.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
using Foxnouns.Backend.Utils;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Foxnouns.Backend.Database.Models;
|
||||
|
||||
public class Report : BaseModel
|
||||
{
|
||||
public Snowflake ReporterId { get; init; }
|
||||
public User Reporter { get; init; } = null!;
|
||||
public Snowflake TargetUserId { get; init; }
|
||||
public User TargetUser { get; init; } = null!;
|
||||
|
||||
public Snowflake? TargetMemberId { get; init; }
|
||||
public Member? TargetMember { get; init; }
|
||||
|
||||
public ReportStatus Status { get; set; }
|
||||
public ReportReason Reason { get; init; }
|
||||
|
||||
public ReportTargetType TargetType { get; init; }
|
||||
public string? TargetSnapshot { get; init; }
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(ScreamingSnakeCaseEnumConverter))]
|
||||
public enum ReportTargetType
|
||||
{
|
||||
User,
|
||||
Member,
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(ScreamingSnakeCaseEnumConverter))]
|
||||
public enum ReportStatus
|
||||
{
|
||||
Open,
|
||||
Closed,
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(ScreamingSnakeCaseEnumConverter))]
|
||||
public enum ReportReason
|
||||
{
|
||||
Totalitarianism,
|
||||
HateSpeech,
|
||||
Racism,
|
||||
Homophobia,
|
||||
Transphobia,
|
||||
Queerphobia,
|
||||
Exclusionism,
|
||||
Sexism,
|
||||
Ableism,
|
||||
ChildPornography,
|
||||
PedophiliaAdvocacy,
|
||||
Harassment,
|
||||
Impersonation,
|
||||
Doxxing,
|
||||
EncouragingSelfHarm,
|
||||
Spam,
|
||||
Trolling,
|
||||
Advertisement,
|
||||
CopyrightViolation,
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue