Implement creator studio and upload updates

This commit is contained in:
2026-04-04 10:12:02 +02:00
parent 1da7d3bf88
commit 0b216b7ecd
15107 changed files with 31206 additions and 626514 deletions

View File

@@ -1,7 +1,7 @@
<?php
return [
'disk' => env('AVATAR_DISK', env('APP_ENV') === 'production' ? 's3' : 'public'),
'disk' => env('AVATAR_DISK', 's3'),
'sizes' => [32, 64, 128, 256, 512],
'quality' => (int) env('AVATAR_WEBP_QUALITY', 85),
];

View File

@@ -14,4 +14,9 @@ return [
* Example: https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache
*/
'purge_url' => env('CDN_PURGE_URL', null),
'cloudflare' => [
'zone_id' => env('CLOUDFLARE_ZONE_ID', null),
'api_token' => env('CLOUDFLARE_API_TOKEN', null),
],
];

View File

@@ -0,0 +1,358 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Content Moderation Configuration
|--------------------------------------------------------------------------
*/
'scanner_version' => '3.0',
'queue_threshold' => 30,
'rules' => [
'enabled' => [
\App\Services\Moderation\Rules\LinkPresenceRule::class,
\App\Services\Moderation\Rules\DomainBlacklistRule::class,
\App\Services\Moderation\Rules\SuspiciousKeywordRule::class,
\App\Services\Moderation\Rules\RegexPatternRule::class,
\App\Services\Moderation\Rules\UnicodeObfuscationRule::class,
\App\Services\Moderation\Rules\RepeatedPhraseRule::class,
\App\Services\Moderation\Rules\DuplicateCommentRule::class,
\App\Services\Moderation\Rules\NearDuplicateCampaignRule::class,
\App\Services\Moderation\Rules\KeywordStuffingRule::class,
\App\Services\Moderation\Rules\ExcessivePunctuationRule::class,
],
],
'auto_hide' => [
'enabled' => true,
'threshold' => 95,
'supported_types' => [
'artwork_comment',
'artwork_description',
'artwork_title',
],
],
'future_content_types' => [
'user_bio',
'user_profile_link',
'collection_title',
'collection_description',
'story_title',
'story_content',
'card_title',
'card_text',
],
'suggestions' => [
'provider' => env('CONTENT_MODERATION_SUGGESTION_PROVIDER', 'heuristic'),
],
'policies' => [
'default' => [
'queue_threshold' => 30,
'auto_hide_threshold' => 95,
'priority_bonus' => 0,
'review_bucket' => 'standard',
],
'strict_seo_protection' => [
'queue_threshold' => 22,
'auto_hide_threshold' => 90,
'priority_bonus' => 20,
'review_bucket' => 'urgent',
],
'new_user_strict_mode' => [
'queue_threshold' => 24,
'auto_hide_threshold' => 92,
'priority_bonus' => 14,
'review_bucket' => 'high',
],
'trusted_user_relaxed_mode' => [
'queue_threshold' => 38,
'auto_hide_threshold' => 100,
'priority_bonus' => -8,
'review_bucket' => 'standard',
],
'comments_high_volume_antispam' => [
'queue_threshold' => 20,
'auto_hide_threshold' => 88,
'priority_bonus' => 18,
'review_bucket' => 'high',
],
],
/*
|--------------------------------------------------------------------------
| Severity Thresholds
|--------------------------------------------------------------------------
| Score boundaries for severity levels.
*/
'severity_thresholds' => [
'critical' => 90,
'high' => 60,
'medium' => 30,
],
/*
|--------------------------------------------------------------------------
| Rule Weights
|--------------------------------------------------------------------------
| Score contribution per rule match.
*/
'weights' => [
'blacklisted_domain' => 70,
'suspicious_domain' => 40,
'single_external_link' => 20,
'multiple_links' => 40,
'shortened_link' => 30,
'suspicious_keyword' => 25,
'high_risk_keyword' => 40,
'unicode_obfuscation' => 30,
'repeated_phrase' => 25,
'duplicate_comment' => 35,
'near_duplicate_campaign' => 30,
'keyword_stuffing' => 20,
'excessive_punctuation' => 15,
'regex_pattern' => 30,
],
'duplicate_detection' => [
'near_duplicate_similarity' => 84,
],
'user_risk' => [
'high_modifier' => 18,
'medium_modifier' => 10,
'low_modifier' => 4,
'trusted_modifier' => -6,
],
/*
|--------------------------------------------------------------------------
| Blacklisted Domains
|--------------------------------------------------------------------------
| Domains that immediately score high. Patterns support * wildcard.
*/
'blacklisted_domains' => [
'*.casino-*.com',
'*.bet365*',
'*.pokerstars*',
'*.1xbet*',
'*.parimatch*',
'*.888casino*',
'*.slotmachine*',
'*.onlinecasino*',
'*.buycheap*',
'*.cheapviagra*',
'*.pillsonline*',
'*.pharma-*',
'*.xn--*',
'*.webcam-show*',
'*.livecam*',
'*.adult-*',
'*.porn*',
'*.xxx*',
'*.cryptoairdrop*',
'*.free-bitcoin*',
'*.moonshot-token*',
],
/*
|--------------------------------------------------------------------------
| Suspicious Domains
|--------------------------------------------------------------------------
| Domains that add moderate score.
*/
'suspicious_domains' => [
'*.tk',
'*.ml',
'*.ga',
'*.cf',
'*.gq',
'*.xyz',
'*.top',
'*.buzz',
'*.club',
'*.work',
'*.click',
'*.link',
'*.info',
'*.site',
'*.online',
'*.icu',
'*.fun',
'*.monster',
],
/*
|--------------------------------------------------------------------------
| URL Shortener Domains
|--------------------------------------------------------------------------
*/
'shortener_domains' => [
'bit.ly',
'tinyurl.com',
't.co',
'goo.gl',
'ow.ly',
'is.gd',
'buff.ly',
'adf.ly',
'bl.ink',
'shorte.st',
'clck.ru',
'cutt.ly',
'rb.gy',
'shorturl.at',
],
/*
|--------------------------------------------------------------------------
| Allowed Domains
|--------------------------------------------------------------------------
| Domains that should not be flagged.
*/
'allowed_domains' => [
'skinbase.org',
'skinbase.si',
'deviantart.com',
'artstation.com',
'behance.net',
'dribbble.com',
'pixiv.net',
'instagram.com',
'twitter.com',
'x.com',
'youtube.com',
'youtu.be',
'vimeo.com',
'github.com',
'wikipedia.org',
'imgur.com',
'flickr.com',
'unsplash.com',
'pinterest.com',
],
/*
|--------------------------------------------------------------------------
| Suspicious Keywords
|--------------------------------------------------------------------------
| Phrases that indicate spam. grouped by risk level.
*/
'keywords' => [
'high_risk' => [
'buy followers',
'buy likes',
'buy subscribers',
'free bitcoin',
'crypto giveaway',
'crypto airdrop',
'double your bitcoin',
'send btc',
'send eth',
'online casino',
'best casino',
'casino bonus',
'free spins',
'slot machine',
'sports betting',
'bet now',
'viagra',
'cialis',
'pharmacy online',
'buy cheap',
'discount pills',
'weight loss pills',
'diet pills',
'earn money fast',
'make money online',
'work from home opportunity',
'investment opportunity',
'guaranteed income',
'adult content',
'webcam show',
'live cam',
'hookup',
'dating site',
'meet singles',
'sexy girls',
'hot women',
'malware',
'hack account',
'free robux',
'free v-bucks',
],
'suspicious' => [
'visit my site',
'check my profile',
'click here',
'click the link',
'follow me',
'subscribe to my',
'check out my website',
'link in bio',
'link in description',
'free download',
'limited time offer',
'act now',
'don\'t miss out',
'exclusive deal',
'best price',
'cheap price',
'seo service',
'seo expert',
'web development service',
'marketing service',
'backlink service',
'guest post',
'sponsored post',
'promote your',
'boost your',
'increase traffic',
'grow your followers',
'dm for collab',
'dm for business',
'whatsapp me',
'telegram me',
],
],
/*
|--------------------------------------------------------------------------
| Keyword Stuffing Detection
|--------------------------------------------------------------------------
*/
'keyword_stuffing' => [
'min_word_count' => 20,
'max_unique_ratio' => 0.3, // if unique/total < this, likely stuffing
'max_single_word_frequency' => 0.25, // single word > 25% of total
],
/*
|--------------------------------------------------------------------------
| Repeated Phrase Detection
|--------------------------------------------------------------------------
*/
'repeated_phrase' => [
'min_phrase_length' => 4, // min words in phrase
'min_repetitions' => 3, // min times phrase must appear
],
/*
|--------------------------------------------------------------------------
| Excessive Punctuation Detection
|--------------------------------------------------------------------------
*/
'excessive_punctuation' => [
'max_exclamation_ratio' => 0.1, // ! per char ratio
'max_question_ratio' => 0.1,
'max_caps_ratio' => 0.7, // if > 70% uppercase
'min_length' => 20,
],
];

View File

@@ -48,16 +48,17 @@ return [
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
'throw' => false,
'report' => false,
'visibility' => 'public',
'throw' => false,
'report' => false,
],
],

View File

@@ -51,13 +51,19 @@ return [
],
'render' => [
'queue' => env('NOVA_CARDS_QUEUE', 'default'),
'preview_quality' => 86,
'og_quality' => 88,
'preview_format' => 'webp',
'og_format' => 'jpg',
'queue' => env('NOVA_CARDS_QUEUE', 'default'),
'preview_quality' => 86,
'og_quality' => 88,
'preview_format' => 'webp',
'og_format' => 'jpg',
// Directory containing TrueType font files named {preset}.ttf and default.ttf.
'fonts_dir' => env('NOVA_CARDS_FONTS_DIR', storage_path('app/fonts')),
],
// Set NOVA_CARDS_PLAYWRIGHT_RENDER=true to use the CSS/Playwright renderer
// instead of the GD fallback. Requires Node.js + `npx playwright install chromium`.
'playwright_render' => (bool) env('NOVA_CARDS_PLAYWRIGHT_RENDER', false),
'seed_demo_cards' => [
'enabled' => (bool) env('NOVA_CARDS_SEED_DEMO_CARDS', false),
'user' => [
@@ -79,42 +85,42 @@ return [
'font_presets' => [
'modern-sans' => [
'label' => 'Modern Sans',
'family' => 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
'family' => 'Inter, sans-serif',
'render_family' => 'arial',
'weight' => '600',
'recommended_use' => 'Clean motivational cards and bold statements.',
],
'elegant-serif' => [
'label' => 'Elegant Serif',
'family' => 'Georgia, Cambria, "Times New Roman", serif',
'family' => '"Playfair Display", serif',
'render_family' => 'georgia',
'weight' => '700',
'recommended_use' => 'Classic quotes and romantic layouts.',
],
'bold-poster' => [
'label' => 'Bold Poster',
'family' => 'Impact, Haettenschweiler, "Arial Narrow Bold", sans-serif',
'family' => 'Anton, sans-serif',
'render_family' => 'arial-black',
'weight' => '700',
'recommended_use' => 'High-contrast poster-like statements.',
],
'soft-handwritten' => [
'label' => 'Soft Handwritten',
'family' => '"Segoe Print", "Bradley Hand", cursive',
'family' => 'Caveat, cursive',
'render_family' => 'comic-sans',
'weight' => '400',
'recommended_use' => 'Warm, intimate, diary-like cards.',
],
'minimal-editorial' => [
'label' => 'Minimal Editorial',
'family' => '"Trebuchet MS", "Gill Sans", sans-serif',
'family' => '"Libre Franklin", sans-serif',
'render_family' => 'trebuchet',
'weight' => '600',
'recommended_use' => 'Minimal editorial compositions.',
],
'dreamy-aesthetic' => [
'label' => 'Dreamy Aesthetic',
'family' => '"Palatino Linotype", "Book Antiqua", Palatino, serif',
'family' => '"Cormorant Garamond", serif',
'render_family' => 'palatino',
'weight' => '600',
'recommended_use' => 'Poetry, wallpaper quotes, and soft mood cards.',

15
config/seo.php Normal file
View File

@@ -0,0 +1,15 @@
<?php
return [
'site_name' => env('SEO_SITE_NAME', 'Skinbase'),
'default_title' => env('SEO_DEFAULT_TITLE', 'Skinbase'),
'title_separator' => env('SEO_TITLE_SEPARATOR', ' — '),
'default_description' => env(
'SEO_DEFAULT_DESCRIPTION',
'Discover digital art, wallpapers, skins, photography, and creator collections from the Skinbase community.'
),
'default_robots' => env('SEO_DEFAULT_ROBOTS', 'index,follow'),
'keywords_enabled' => (bool) env('SEO_META_KEYWORDS', true),
'twitter_card' => env('SEO_TWITTER_CARD', 'summary_large_image'),
'fallback_image_path' => env('SEO_FALLBACK_IMAGE_PATH', '/gfx/skinbase_back_001.webp'),
];

111
config/sitemaps.php Normal file
View File

@@ -0,0 +1,111 @@
<?php
return [
'cache_ttl_seconds' => (int) env('SITEMAPS_CACHE_TTL', 900),
'refresh' => [
'build_on_request' => (bool) env('SITEMAPS_BUILD_ON_REQUEST', true),
],
'delivery' => [
'prefer_published_release' => (bool) env('SITEMAPS_PREFER_PUBLISHED_RELEASE', true),
'fallback_to_live_build' => (bool) env('SITEMAPS_FALLBACK_TO_LIVE_BUILD', true),
],
'pre_generated' => [
'enabled' => (bool) env('SITEMAPS_PREGENERATED_ENABLED', true),
'prefer' => (bool) env('SITEMAPS_PREGENERATED_PREFER', false),
'disk' => env('SITEMAPS_PREGENERATED_DISK', 'local'),
'path' => trim((string) env('SITEMAPS_PREGENERATED_PATH', 'generated-sitemaps'), '/'),
],
'releases' => [
'disk' => env('SITEMAPS_RELEASES_DISK', 'local'),
'path' => trim((string) env('SITEMAPS_RELEASES_PATH', 'sitemaps'), '/'),
'retain_successful' => (int) env('SITEMAPS_RELEASES_RETAIN_SUCCESSFUL', 3),
'retain_failed' => (int) env('SITEMAPS_RELEASES_RETAIN_FAILED', 2),
'lock_seconds' => (int) env('SITEMAPS_RELEASES_LOCK_SECONDS', 900),
],
'shards' => [
'enabled' => (bool) env('SITEMAPS_SHARDS_ENABLED', true),
'zero_pad_length' => (int) env('SITEMAPS_SHARD_ZERO_PAD_LENGTH', 4),
'force_family_indexes' => (bool) env('SITEMAPS_SHARD_FORCE_FAMILY_INDEXES', false),
'artworks' => [
'size' => (int) env('SITEMAPS_SHARD_ARTWORKS_SIZE', 10000),
],
'users' => [
'size' => (int) env('SITEMAPS_SHARD_USERS_SIZE', 10000),
],
'cards' => [
'size' => (int) env('SITEMAPS_SHARD_CARDS_SIZE', 10000),
],
'stories' => [
'size' => (int) env('SITEMAPS_SHARD_STORIES_SIZE', 10000),
],
'news' => [
'size' => (int) env('SITEMAPS_SHARD_NEWS_SIZE', 0),
],
'forum-threads' => [
'size' => (int) env('SITEMAPS_SHARD_FORUM_THREADS_SIZE', 10000),
],
'collections' => [
'size' => (int) env('SITEMAPS_SHARD_COLLECTIONS_SIZE', 10000),
],
],
'validation' => [
'forbidden_paths' => [
'/admin',
'/cp',
'/dashboard',
'/studio',
'/account',
'/login',
'/register',
'/creator/',
],
],
'news' => [
'google_variant_enabled' => (bool) env('SITEMAPS_NEWS_GOOGLE_VARIANT', true),
'google_variant_name' => 'news-google',
'google_publication_name' => env('SITEMAPS_NEWS_GOOGLE_PUBLICATION', env('APP_NAME', 'Skinbase Nova')),
'google_language' => env('SITEMAPS_NEWS_GOOGLE_LANGUAGE', env('APP_LOCALE', 'en')),
'google_lookback_hours' => (int) env('SITEMAPS_NEWS_GOOGLE_LOOKBACK_HOURS', 48),
'google_max_items' => (int) env('SITEMAPS_NEWS_GOOGLE_MAX_ITEMS', 1000),
],
'enabled' => [
'artworks',
'users',
'tags',
'categories',
'collections',
'cards',
'stories',
'news',
'news-google',
'forum-index',
'forum-categories',
'forum-threads',
'static-pages',
],
'content_type_slugs' => [
'photography',
'wallpapers',
'skins',
'other',
'digital-art',
],
'static_page_excluded_slugs' => [
'about',
'help',
'contact',
'legal-terms',
'legal-privacy',
'legal-cookies',
],
];

View File

@@ -5,6 +5,13 @@ declare(strict_types=1);
return [
'storage_root' => env('SKINBASE_STORAGE_ROOT', storage_path('app/artworks')),
'local_originals_root' => env('ARTWORKS_LOCAL_ORIGINALS_ROOT', storage_path('app/originals/artworks')),
'object_storage' => [
'disk' => env('ARTWORKS_OBJECT_DISK', 's3'),
'prefix' => env('ARTWORKS_OBJECT_PREFIX', 'artworks'),
],
'paths' => [
'tmp' => 'tmp',
'quarantine' => 'quarantine',
@@ -14,9 +21,11 @@ return [
'md' => 'md',
'lg' => 'lg',
'xl' => 'xl',
'sq' => 'sq',
],
'max_size_mb' => 50,
'max_archive_size_mb' => 200,
'max_pixels' => 12000,
'allowed_mimes' => [
@@ -27,12 +36,55 @@ return [
'allow_gif' => env('UPLOAD_ALLOW_GIF', false),
'allowed_archive_mimes' => [
'application/zip',
'application/x-zip-compressed',
'application/x-rar-compressed',
'application/vnd.rar',
'application/x-7z-compressed',
'application/x-tar',
'application/gzip',
'application/x-gzip',
'application/octet-stream',
],
'derivatives' => [
'xs' => ['max' => 320],
'sm' => ['max' => 680],
'md' => ['max' => 1024],
'lg' => ['max' => 1920],
'xl' => ['max' => 2560],
'sq' => ['size' => 512],
],
'square_thumbnails' => [
'width' => env('UPLOAD_SQ_WIDTH', 512),
'height' => env('UPLOAD_SQ_HEIGHT', 512),
'quality' => env('UPLOAD_SQ_QUALITY', 82),
'smart_crop' => env('UPLOAD_SQ_SMART_CROP', true),
'padding_ratio' => env('UPLOAD_SQ_PADDING_RATIO', 0.18),
'allow_upscale' => env('UPLOAD_SQ_ALLOW_UPSCALE', false),
'fallback_strategy' => env('UPLOAD_SQ_FALLBACK_STRATEGY', 'center'),
'log' => env('UPLOAD_SQ_LOG', false),
'preview_size' => env('UPLOAD_PREVIEW_SQ_SIZE', 320),
'subject_detector' => [
'preferred_labels' => [
'person',
'portrait',
'face',
'human',
'animal',
'lion',
'dog',
'cat',
'bird',
],
],
'saliency' => [
'sample_max_dimension' => env('UPLOAD_SQ_SALIENCY_SAMPLE_MAX', 96),
'min_total_energy' => env('UPLOAD_SQ_SALIENCY_MIN_TOTAL', 2400),
'window_ratios' => [0.55, 0.7, 0.82, 1.0],
],
],
'quality' => 85,