more fixes
This commit is contained in:
@@ -12,11 +12,15 @@ return new class extends Migration {
|
||||
$table->foreignId('artwork_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('user_id')->nullable()->index();
|
||||
|
||||
$table->binary('ip', 16);
|
||||
$table->string('user_agent')->nullable();
|
||||
// Legacy binary IP is kept for existing analytics/tests compatibility.
|
||||
$table->binary('ip', 16)->nullable();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->text('user_agent')->nullable();
|
||||
$table->text('referer')->nullable();
|
||||
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->index('created_at');
|
||||
$table->index(['artwork_id', 'created_at'], 'idx_downloads_artwork');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
return;
|
||||
Schema::table('contents', function (Blueprint $table) {
|
||||
$table->text('grid_data')->nullable()->after('views');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('contents', function (Blueprint $table) {
|
||||
$table->dropColumn('grid_data');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
<?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
|
||||
{
|
||||
Schema::table('artwork_downloads', function (Blueprint $table) {
|
||||
if (! Schema::hasColumn('artwork_downloads', 'ip_address')) {
|
||||
$table->string('ip_address', 45)->nullable()->after('ip');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('artwork_downloads', 'referer')) {
|
||||
$table->text('referer')->nullable()->after('user_agent');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('artwork_downloads', 'created_at')) {
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
Schema::table('artwork_downloads', function (Blueprint $table) {
|
||||
$table->index('created_at', 'artwork_downloads_created_at_idx');
|
||||
});
|
||||
} catch (\Throwable) {
|
||||
// Index may already exist depending on historical migration state.
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
try {
|
||||
Schema::table('artwork_downloads', function (Blueprint $table) {
|
||||
$table->dropIndex('artwork_downloads_created_at_idx');
|
||||
});
|
||||
} catch (\Throwable) {
|
||||
// Ignore when index is absent.
|
||||
}
|
||||
|
||||
Schema::table('artwork_downloads', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('artwork_downloads', 'ip_address')) {
|
||||
$table->dropColumn('ip_address');
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('artwork_downloads', 'referer')) {
|
||||
$table->dropColumn('referer');
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
<?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
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table): void {
|
||||
if (! Schema::hasColumn('users', 'cover_hash')) {
|
||||
$table->string('cover_hash', 64)->nullable()->after('last_visit_at');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('users', 'cover_ext')) {
|
||||
$table->string('cover_ext', 10)->nullable()->after('cover_hash');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('users', 'cover_position')) {
|
||||
$table->unsignedTinyInteger('cover_position')->default(50)->after('cover_ext');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table): void {
|
||||
if (Schema::hasColumn('users', 'cover_position')) {
|
||||
$table->dropColumn('cover_position');
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('users', 'cover_ext')) {
|
||||
$table->dropColumn('cover_ext');
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('users', 'cover_hash')) {
|
||||
$table->dropColumn('cover_hash');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
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('user_profiles')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Schema::table('user_profiles', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('user_profiles', 'email_notifications')) {
|
||||
$table->boolean('email_notifications')->default(true)->after('auto_post_upload');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('user_profiles', 'upload_notifications')) {
|
||||
$table->boolean('upload_notifications')->default(true)->after('email_notifications');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('user_profiles', 'follower_notifications')) {
|
||||
$table->boolean('follower_notifications')->default(true)->after('upload_notifications');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('user_profiles', 'comment_notifications')) {
|
||||
$table->boolean('comment_notifications')->default(true)->after('follower_notifications');
|
||||
}
|
||||
|
||||
if (!Schema::hasColumn('user_profiles', 'newsletter')) {
|
||||
$table->boolean('newsletter')->default(false)->after('comment_notifications');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (!Schema::hasTable('user_profiles')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Schema::table('user_profiles', function (Blueprint $table) {
|
||||
foreach (['newsletter', 'comment_notifications', 'follower_notifications', 'upload_notifications', 'email_notifications'] as $column) {
|
||||
if (Schema::hasColumn('user_profiles', $column)) {
|
||||
$table->dropColumn($column);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
<?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
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
if (! Schema::hasColumn('users', 'last_username_change_at')) {
|
||||
$table->timestamp('last_username_change_at')->nullable()->after('username_changed_at');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('users', 'last_username_change_at')) {
|
||||
$table->dropColumn('last_username_change_at');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
<?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('email_changes')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Schema::create('email_changes', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->string('new_email', 255);
|
||||
$table->string('verification_code', 128);
|
||||
$table->timestamp('expires_at');
|
||||
$table->timestamp('used_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['user_id', 'expires_at']);
|
||||
$table->index(['user_id', 'created_at']);
|
||||
$table->index('new_email');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('email_changes');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,98 @@
|
||||
<?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('stories')) {
|
||||
Schema::table('stories', function (Blueprint $table): void {
|
||||
if (! Schema::hasColumn('stories', 'creator_id')) {
|
||||
$table->foreignId('creator_id')->nullable()->after('id')->constrained('users')->nullOnDelete();
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('stories', 'story_type')) {
|
||||
$table->enum('story_type', [
|
||||
'creator_story',
|
||||
'tutorial',
|
||||
'interview',
|
||||
'project_breakdown',
|
||||
'announcement',
|
||||
'resource',
|
||||
])->default('creator_story')->after('content');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('stories', 'reading_time')) {
|
||||
$table->unsignedInteger('reading_time')->default(1)->after('story_type');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('stories', 'likes_count')) {
|
||||
$table->unsignedInteger('likes_count')->default(0)->after('views');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('stories', 'comments_count')) {
|
||||
$table->unsignedInteger('comments_count')->default(0)->after('likes_count');
|
||||
}
|
||||
});
|
||||
|
||||
if (Schema::hasColumn('stories', 'author_id') && Schema::hasTable('stories_authors')) {
|
||||
DB::statement(<<<'SQL'
|
||||
UPDATE stories s
|
||||
INNER JOIN stories_authors sa ON sa.id = s.author_id
|
||||
SET s.creator_id = sa.user_id
|
||||
WHERE s.creator_id IS NULL
|
||||
AND sa.user_id IS NOT NULL
|
||||
SQL);
|
||||
}
|
||||
}
|
||||
|
||||
if (! Schema::hasTable('story_views')) {
|
||||
Schema::create('story_views', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('story_id')->constrained('stories')->cascadeOnDelete();
|
||||
$table->foreignId('user_id')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->index(['story_id', 'created_at']);
|
||||
$table->index(['user_id', 'created_at']);
|
||||
});
|
||||
}
|
||||
|
||||
if (! Schema::hasTable('story_likes')) {
|
||||
Schema::create('story_likes', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->foreignId('story_id')->constrained('stories')->cascadeOnDelete();
|
||||
$table->foreignId('user_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
|
||||
$table->unique(['story_id', 'user_id']);
|
||||
$table->index(['story_id', 'created_at']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('story_likes');
|
||||
Schema::dropIfExists('story_views');
|
||||
|
||||
if (Schema::hasTable('stories')) {
|
||||
Schema::table('stories', function (Blueprint $table): void {
|
||||
if (Schema::hasColumn('stories', 'creator_id')) {
|
||||
$table->dropConstrainedForeignId('creator_id');
|
||||
}
|
||||
|
||||
foreach (['story_type', 'reading_time', 'likes_count', 'comments_count'] as $column) {
|
||||
if (Schema::hasColumn('stories', $column)) {
|
||||
$table->dropColumn($column);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
<?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('story_tags')) {
|
||||
Schema::create('story_tags', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('name', 120)->unique();
|
||||
$table->string('slug', 140)->unique();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
if (! Schema::hasTable('relation_story_tags')) {
|
||||
Schema::create('relation_story_tags', function (Blueprint $table): void {
|
||||
$table->foreignId('story_id')->constrained('stories')->cascadeOnDelete();
|
||||
$table->foreignId('tag_id')->constrained('story_tags')->cascadeOnDelete();
|
||||
$table->primary(['story_id', 'tag_id']);
|
||||
});
|
||||
}
|
||||
|
||||
if (Schema::hasTable('stories_tags')) {
|
||||
$legacyTags = DB::table('stories_tags')->get();
|
||||
|
||||
foreach ($legacyTags as $legacyTag) {
|
||||
DB::table('story_tags')->insertOrIgnore([
|
||||
'name' => (string) $legacyTag->name,
|
||||
'slug' => (string) $legacyTag->slug,
|
||||
'created_at' => $legacyTag->created_at ?? now(),
|
||||
'updated_at' => $legacyTag->updated_at ?? now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (Schema::hasTable('stories_tag_relation')) {
|
||||
$legacyRelation = DB::table('stories_tag_relation as relation')
|
||||
->join('stories_tags as legacy_tag', 'legacy_tag.id', '=', 'relation.tag_id')
|
||||
->join('story_tags as new_tag', 'new_tag.slug', '=', 'legacy_tag.slug')
|
||||
->get(['relation.story_id', 'new_tag.id as tag_id']);
|
||||
|
||||
foreach ($legacyRelation as $pair) {
|
||||
DB::table('relation_story_tags')->insertOrIgnore([
|
||||
'story_id' => (int) $pair->story_id,
|
||||
'tag_id' => (int) $pair->tag_id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('relation_story_tags');
|
||||
Schema::dropIfExists('story_tags');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('stories') || ! Schema::hasColumn('stories', 'status')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DB::getDriverName() === 'mysql') {
|
||||
DB::statement("ALTER TABLE stories MODIFY status ENUM('draft','published','scheduled','archived') NOT NULL DEFAULT 'draft'");
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (! Schema::hasTable('stories') || ! Schema::hasColumn('stories', 'status')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DB::getDriverName() === 'mysql') {
|
||||
DB::statement("ALTER TABLE stories MODIFY status ENUM('draft','published') NOT NULL DEFAULT 'draft'");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('reports') || ! Schema::hasColumn('reports', 'target_type')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DB::getDriverName() === 'mysql') {
|
||||
DB::statement("ALTER TABLE reports MODIFY target_type ENUM('message','conversation','user','story') NOT NULL");
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (! Schema::hasTable('reports') || ! Schema::hasColumn('reports', 'target_type')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DB::getDriverName() === 'mysql') {
|
||||
DB::statement("ALTER TABLE reports MODIFY target_type ENUM('message','conversation','user') NOT NULL");
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
<?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('stories')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DB::getDriverName() === 'mysql' && Schema::hasColumn('stories', 'status')) {
|
||||
DB::statement("ALTER TABLE stories MODIFY status ENUM('draft','pending_review','published','scheduled','archived','rejected') NOT NULL DEFAULT 'draft'");
|
||||
}
|
||||
|
||||
Schema::table('stories', function (Blueprint $table): void {
|
||||
if (! Schema::hasColumn('stories', 'scheduled_for')) {
|
||||
$table->timestamp('scheduled_for')->nullable()->after('published_at');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('stories', 'meta_title')) {
|
||||
$table->string('meta_title', 255)->nullable()->after('reading_time');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('stories', 'meta_description')) {
|
||||
$table->string('meta_description', 300)->nullable()->after('meta_title');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('stories', 'canonical_url')) {
|
||||
$table->string('canonical_url', 500)->nullable()->after('meta_description');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('stories', 'og_image')) {
|
||||
$table->string('og_image', 500)->nullable()->after('canonical_url');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('stories', 'submitted_for_review_at')) {
|
||||
$table->timestamp('submitted_for_review_at')->nullable()->after('scheduled_for');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('stories', 'reviewed_at')) {
|
||||
$table->timestamp('reviewed_at')->nullable()->after('submitted_for_review_at');
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('stories', 'reviewed_by_id')) {
|
||||
$table->foreignId('reviewed_by_id')->nullable()->after('reviewed_at')->constrained('users')->nullOnDelete();
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('stories', 'rejected_reason')) {
|
||||
$table->text('rejected_reason')->nullable()->after('reviewed_by_id');
|
||||
}
|
||||
|
||||
$table->index(['status', 'submitted_for_review_at'], 'idx_stories_review_queue');
|
||||
$table->index(['creator_id', 'status', 'updated_at'], 'idx_stories_creator_status_updated');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (! Schema::hasTable('stories')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Schema::table('stories', function (Blueprint $table): void {
|
||||
if (Schema::hasColumn('stories', 'reviewed_by_id')) {
|
||||
$table->dropConstrainedForeignId('reviewed_by_id');
|
||||
}
|
||||
|
||||
foreach ([
|
||||
'scheduled_for',
|
||||
'meta_title',
|
||||
'meta_description',
|
||||
'canonical_url',
|
||||
'og_image',
|
||||
'submitted_for_review_at',
|
||||
'reviewed_at',
|
||||
'rejected_reason',
|
||||
] as $column) {
|
||||
if (Schema::hasColumn('stories', $column)) {
|
||||
$table->dropColumn($column);
|
||||
}
|
||||
}
|
||||
|
||||
$table->dropIndex('idx_stories_review_queue');
|
||||
$table->dropIndex('idx_stories_creator_status_updated');
|
||||
});
|
||||
|
||||
if (DB::getDriverName() === 'mysql' && Schema::hasColumn('stories', 'status')) {
|
||||
DB::statement("ALTER TABLE stories MODIFY status ENUM('draft','published','scheduled','archived') NOT NULL DEFAULT 'draft'");
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user