Refactor dashboard and upload flows
Remove dead admin UI code, redesign dashboard followers/following and upload experiences, and add schema audit tooling with repair migrations for forum and upload drift.
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (!Schema::hasTable('forum_spam_keywords')) {
|
||||
Schema::create('forum_spam_keywords', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('keyword', 120)->unique();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('forum_spam_domains')) {
|
||||
Schema::create('forum_spam_domains', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('domain', 191)->unique();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
foreach ((array) config('forum.moderation.defaults.keywords', []) as $keyword) {
|
||||
$keyword = trim((string) $keyword);
|
||||
if ($keyword === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('forum_spam_keywords')->updateOrInsert(
|
||||
['keyword' => $keyword],
|
||||
['created_at' => now()]
|
||||
);
|
||||
}
|
||||
|
||||
foreach ((array) config('forum.moderation.defaults.domains', []) as $domain) {
|
||||
$domain = strtolower(trim((string) $domain));
|
||||
if ($domain === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('forum_spam_domains')->updateOrInsert(
|
||||
['domain' => $domain],
|
||||
['created_at' => now()]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('forum_spam_domains');
|
||||
Schema::dropIfExists('forum_spam_keywords');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (!Schema::hasTable('forum_spam_learning')) {
|
||||
Schema::create('forum_spam_learning', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('content_hash', 64)->index();
|
||||
$table->string('decision', 32)->index();
|
||||
$table->string('pattern_signature', 191)->nullable()->index();
|
||||
$table->foreignId('reviewed_by')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->json('metadata')->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('forum_ai_logs')) {
|
||||
Schema::create('forum_ai_logs', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('post_id')->constrained('forum_posts')->cascadeOnDelete();
|
||||
$table->unsignedSmallInteger('ai_score')->default(0);
|
||||
$table->unsignedSmallInteger('behavior_score')->default(0);
|
||||
$table->unsignedSmallInteger('link_score')->default(0);
|
||||
$table->integer('learning_score')->default(0);
|
||||
$table->unsignedSmallInteger('firewall_score')->default(0);
|
||||
$table->unsignedSmallInteger('bot_risk_score')->default(0);
|
||||
$table->unsignedSmallInteger('risk_score')->default(0)->index();
|
||||
$table->string('decision', 32)->default('allow')->index();
|
||||
$table->string('provider', 64)->nullable()->index();
|
||||
$table->string('source_ip_hash', 64)->nullable()->index();
|
||||
$table->json('metadata')->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->index(['post_id', 'created_at']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('forum_ai_logs');
|
||||
Schema::dropIfExists('forum_spam_learning');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (!Schema::hasTable('forum_spam_learning')) {
|
||||
Schema::create('forum_spam_learning', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('content_hash', 64)->index();
|
||||
$table->string('decision', 32)->index();
|
||||
$table->string('pattern_signature', 191)->nullable()->index();
|
||||
$table->foreignId('reviewed_by')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->json('metadata')->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('forum_ai_logs')) {
|
||||
Schema::create('forum_ai_logs', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('post_id')->constrained('forum_posts')->cascadeOnDelete();
|
||||
$table->unsignedSmallInteger('ai_score')->default(0);
|
||||
$table->unsignedSmallInteger('behavior_score')->default(0);
|
||||
$table->unsignedSmallInteger('link_score')->default(0);
|
||||
$table->integer('learning_score')->default(0);
|
||||
$table->unsignedSmallInteger('firewall_score')->default(0);
|
||||
$table->unsignedSmallInteger('bot_risk_score')->default(0);
|
||||
$table->unsignedSmallInteger('risk_score')->default(0)->index();
|
||||
$table->string('decision', 32)->default('allow')->index();
|
||||
$table->string('provider', 64)->nullable()->index();
|
||||
$table->string('source_ip_hash', 64)->nullable()->index();
|
||||
$table->json('metadata')->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->index(['post_id', 'created_at']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('forum_ai_logs');
|
||||
Schema::dropIfExists('forum_spam_learning');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (!Schema::hasTable('forum_tags')) {
|
||||
Schema::create('forum_tags', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('name', 80);
|
||||
$table->string('slug', 80)->unique();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('forum_topic_tags')) {
|
||||
Schema::create('forum_topic_tags', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('topic_id')->constrained('forum_topics')->cascadeOnDelete();
|
||||
$table->foreignId('tag_id')->constrained('forum_tags')->cascadeOnDelete();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['topic_id', 'tag_id']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('forum_topic_tags');
|
||||
Schema::dropIfExists('forum_tags');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (Schema::hasTable('uploads')) {
|
||||
$missingUploadColumns = [
|
||||
'tags' => ! Schema::hasColumn('uploads', 'tags'),
|
||||
'license' => ! Schema::hasColumn('uploads', 'license'),
|
||||
'nsfw' => ! Schema::hasColumn('uploads', 'nsfw'),
|
||||
'is_scanned' => ! Schema::hasColumn('uploads', 'is_scanned'),
|
||||
'has_tags' => ! Schema::hasColumn('uploads', 'has_tags'),
|
||||
'published_at' => ! Schema::hasColumn('uploads', 'published_at'),
|
||||
'final_path' => ! Schema::hasColumn('uploads', 'final_path'),
|
||||
];
|
||||
|
||||
if (in_array(true, $missingUploadColumns, true)) {
|
||||
Schema::table('uploads', function (Blueprint $table) use ($missingUploadColumns): void {
|
||||
if ($missingUploadColumns['tags']) {
|
||||
$table->json('tags')->nullable();
|
||||
}
|
||||
|
||||
if ($missingUploadColumns['license']) {
|
||||
$table->string('license', 64)->nullable();
|
||||
}
|
||||
|
||||
if ($missingUploadColumns['nsfw']) {
|
||||
$table->boolean('nsfw')->default(false);
|
||||
}
|
||||
|
||||
if ($missingUploadColumns['is_scanned']) {
|
||||
$table->boolean('is_scanned')->default(false)->index();
|
||||
}
|
||||
|
||||
if ($missingUploadColumns['has_tags']) {
|
||||
$table->boolean('has_tags')->default(false)->index();
|
||||
}
|
||||
|
||||
if ($missingUploadColumns['published_at']) {
|
||||
$table->timestamp('published_at')->nullable()->index();
|
||||
}
|
||||
|
||||
if ($missingUploadColumns['final_path']) {
|
||||
$table->string('final_path')->nullable();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (Schema::hasTable('forum_ai_logs')) {
|
||||
$missingForumAiColumns = [
|
||||
'firewall_score' => ! Schema::hasColumn('forum_ai_logs', 'firewall_score'),
|
||||
'bot_risk_score' => ! Schema::hasColumn('forum_ai_logs', 'bot_risk_score'),
|
||||
];
|
||||
|
||||
if (in_array(true, $missingForumAiColumns, true)) {
|
||||
Schema::table('forum_ai_logs', function (Blueprint $table) use ($missingForumAiColumns): void {
|
||||
if ($missingForumAiColumns['firewall_score']) {
|
||||
$table->unsignedSmallInteger('firewall_score')->default(0);
|
||||
}
|
||||
|
||||
if ($missingForumAiColumns['bot_risk_score']) {
|
||||
$table->unsignedSmallInteger('bot_risk_score')->default(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (Schema::hasTable('forum_ai_logs')) {
|
||||
Schema::table('forum_ai_logs', function (Blueprint $table): void {
|
||||
$dropColumns = [];
|
||||
|
||||
if (Schema::hasColumn('forum_ai_logs', 'firewall_score')) {
|
||||
$dropColumns[] = 'firewall_score';
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('forum_ai_logs', 'bot_risk_score')) {
|
||||
$dropColumns[] = 'bot_risk_score';
|
||||
}
|
||||
|
||||
if ($dropColumns !== []) {
|
||||
$table->dropColumn($dropColumns);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (Schema::hasTable('uploads')) {
|
||||
Schema::table('uploads', function (Blueprint $table): void {
|
||||
$dropColumns = [];
|
||||
|
||||
foreach (['tags', 'license', 'nsfw', 'is_scanned', 'has_tags', 'published_at', 'final_path'] as $column) {
|
||||
if (Schema::hasColumn('uploads', $column)) {
|
||||
$dropColumns[] = $column;
|
||||
}
|
||||
}
|
||||
|
||||
if ($dropColumns !== []) {
|
||||
$table->dropColumn($dropColumns);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user