From c3ce5492643ac57b4a2a50d53e1322645c72753c Mon Sep 17 00:00:00 2001 From: Dwindi Ramadhana Date: Sun, 14 Jun 2026 15:47:28 +0700 Subject: [PATCH] chore: change Android Apk download status to upcoming --- .../Http/Controllers/Web/SiteController.php | 638 +++++++++++------- 1 file changed, 390 insertions(+), 248 deletions(-) diff --git a/app/app/Http/Controllers/Web/SiteController.php b/app/app/Http/Controllers/Web/SiteController.php index 5cdf8a0..ee00fca 100644 --- a/app/app/Http/Controllers/Web/SiteController.php +++ b/app/app/Http/Controllers/Web/SiteController.php @@ -18,26 +18,31 @@ class SiteController extends Controller { /** @var array */ private const CATEGORY_TO_SLUG = [ - 'Smileys & Emotion' => 'smileys', - 'People & Body' => 'people', - 'Animals & Nature' => 'animals', - 'Food & Drink' => 'food', - 'Travel & Places' => 'travel', - 'Activities' => 'activities', - 'Objects' => 'objects', - 'Symbols' => 'symbols', - 'Flags' => 'flags', + "Smileys & Emotion" => "smileys", + "People & Body" => "people", + "Animals & Nature" => "animals", + "Food & Drink" => "food", + "Travel & Places" => "travel", + "Activities" => "activities", + "Objects" => "objects", + "Symbols" => "symbols", + "Flags" => "flags", ]; private function billingMode(): string { $settings = app(SettingsService::class); - $preferred = (string) ($settings->get('billing_mode', config('dewemoji.billing.mode', 'sandbox')) ?: 'sandbox'); + $preferred = + (string) ($settings->get( + "billing_mode", + config("dewemoji.billing.mode", "sandbox"), + ) ?: + "sandbox"); if ($this->paypalConfiguredMode($preferred)) { return $preferred; } - $fallback = $preferred === 'live' ? 'sandbox' : 'live'; + $fallback = $preferred === "live" ? "sandbox" : "live"; if ($this->paypalConfiguredMode($fallback)) { return $fallback; } @@ -47,111 +52,122 @@ class SiteController extends Controller public function home(Request $request): View { - return view('site.home', [ - 'initialQuery' => trim((string) $request->query('q', '')), - 'initialCategory' => trim((string) $request->query('category', '')), - 'initialSubcategory' => trim((string) $request->query('subcategory', '')), - 'canonicalPath' => '/', - 'userTier' => $request->user()?->tier, + return view("site.home", [ + "initialQuery" => trim((string) $request->query("q", "")), + "initialCategory" => trim((string) $request->query("category", "")), + "initialSubcategory" => trim( + (string) $request->query("subcategory", ""), + ), + "canonicalPath" => "/", + "userTier" => $request->user()?->tier, ]); } public function browse(Request $request): RedirectResponse|View { - $cat = strtolower(trim((string) $request->query('cat', 'all'))); - if ($cat !== '' && $cat !== 'all' && array_key_exists($cat, $this->categorySlugMap())) { - return redirect('/'.$cat, 301); + $cat = strtolower(trim((string) $request->query("cat", "all"))); + if ( + $cat !== "" && + $cat !== "all" && + array_key_exists($cat, $this->categorySlugMap()) + ) { + return redirect("/" . $cat, 301); } - return view('site.home', [ - 'initialQuery' => trim((string) $request->query('q', '')), - 'initialCategory' => trim((string) $request->query('category', '')), - 'initialSubcategory' => trim((string) $request->query('subcategory', '')), - 'canonicalPath' => '/browse', - 'userTier' => $request->user()?->tier, + return view("site.home", [ + "initialQuery" => trim((string) $request->query("q", "")), + "initialCategory" => trim((string) $request->query("category", "")), + "initialSubcategory" => trim( + (string) $request->query("subcategory", ""), + ), + "canonicalPath" => "/browse", + "userTier" => $request->user()?->tier, ]); } public function category(string $categorySlug): View { - if ($categorySlug === 'all') { - return view('site.home', [ - 'initialQuery' => '', - 'initialCategory' => '', - 'initialSubcategory' => '', - 'canonicalPath' => '/', - 'userTier' => request()->user()?->tier, + if ($categorySlug === "all") { + return view("site.home", [ + "initialQuery" => "", + "initialCategory" => "", + "initialSubcategory" => "", + "canonicalPath" => "/", + "userTier" => request()->user()?->tier, + ]); + } + + $categoryLabel = $this->categorySlugMap()[$categorySlug] ?? ""; + abort_if($categoryLabel === "", 404); + + return view("site.home", [ + "initialQuery" => "", + "initialCategory" => $categoryLabel, + "initialSubcategory" => "", + "canonicalPath" => "/" . $categorySlug, + "userTier" => request()->user()?->tier, ]); } - $categoryLabel = $this->categorySlugMap()[$categorySlug] ?? ''; - abort_if($categoryLabel === '', 404); - - return view('site.home', [ - 'initialQuery' => '', - 'initialCategory' => $categoryLabel, - 'initialSubcategory' => '', - 'canonicalPath' => '/'.$categorySlug, - 'userTier' => request()->user()?->tier, - ]); - } - - public function categorySubcategory(string $categorySlug, string $subcategorySlug): View - { - if ($categorySlug === 'all') { + public function categorySubcategory( + string $categorySlug, + string $subcategorySlug, + ): View { + if ($categorySlug === "all") { abort(404); } - $categoryLabel = $this->categorySlugMap()[$categorySlug] ?? ''; - abort_if($categoryLabel === '', 404); + $categoryLabel = $this->categorySlugMap()[$categorySlug] ?? ""; + abort_if($categoryLabel === "", 404); - return view('site.home', [ - 'initialQuery' => '', - 'initialCategory' => $categoryLabel, - 'initialSubcategory' => $subcategorySlug, - 'canonicalPath' => '/'.$categorySlug.'/'.$subcategorySlug, - 'userTier' => request()->user()?->tier, + return view("site.home", [ + "initialQuery" => "", + "initialCategory" => $categoryLabel, + "initialSubcategory" => $subcategorySlug, + "canonicalPath" => "/" . $categorySlug . "/" . $subcategorySlug, + "userTier" => request()->user()?->tier, ]); } public function apiDocs(): View { - return view('site.api-docs'); + return view("site.api-docs"); } public function pricing(): View { $user = request()->user(); - $currencyPref = strtoupper((string) session('pricing_currency', '')); - if (!in_array($currencyPref, ['IDR', 'USD'], true)) { + $currencyPref = strtoupper((string) session("pricing_currency", "")); + if (!in_array($currencyPref, ["IDR", "USD"], true)) { $currencyPref = $this->detectPricingCurrency(request()); - session(['pricing_currency' => $currencyPref]); + session(["pricing_currency" => $currencyPref]); } - $rate = (int) config('dewemoji.pricing.usd_rate', 15000); - $plans = PricingPlan::where('status', 'active')->get()->keyBy('code'); - $defaults = config('dewemoji.pricing.defaults', []); - $fallback = collect($defaults)->keyBy('code'); + $rate = (int) config("dewemoji.pricing.usd_rate", 15000); + $plans = PricingPlan::where("status", "active")->get()->keyBy("code"); + $defaults = config("dewemoji.pricing.defaults", []); + $fallback = collect($defaults)->keyBy("code"); $getPlanAmount = function (string $code) use ($plans, $fallback): int { $plan = $plans->get($code) ?? $fallback->get($code); - return (int) ($plan['amount'] ?? $plan->amount ?? 0); + return (int) ($plan["amount"] ?? ($plan->amount ?? 0)); }; $pricing = [ - 'personal_monthly' => [ - 'idr' => $getPlanAmount('personal_monthly'), + "personal_monthly" => [ + "idr" => $getPlanAmount("personal_monthly"), ], - 'personal_annual' => [ - 'idr' => $getPlanAmount('personal_annual'), + "personal_annual" => [ + "idr" => $getPlanAmount("personal_annual"), ], - 'personal_lifetime' => [ - 'idr' => $getPlanAmount('personal_lifetime'), + "personal_lifetime" => [ + "idr" => $getPlanAmount("personal_lifetime"), ], ]; foreach ($pricing as $key => $row) { - $pricing[$key]['usd'] = $rate > 0 ? round($row['idr'] / $rate, 2) : 0; + $pricing[$key]["usd"] = + $rate > 0 ? round($row["idr"] / $rate, 2) : 0; } $hasActiveLifetime = false; @@ -159,49 +175,75 @@ class SiteController extends Controller $pendingCooldownRemaining = 0; if ($user) { $hasActiveLifetime = Subscription::query() - ->where('user_id', $user->id) - ->where('plan', 'personal_lifetime') - ->where('status', 'active') + ->where("user_id", $user->id) + ->where("plan", "personal_lifetime") + ->where("status", "active") ->where(function ($query) { - $query->whereNull('expires_at') - ->orWhere('expires_at', '>', now()); + $query + ->whereNull("expires_at") + ->orWhere("expires_at", ">", now()); }) ->exists(); $hasPendingPayment = Payment::query() - ->where('user_id', $user->id) - ->where('status', 'pending') + ->where("user_id", $user->id) + ->where("status", "pending") ->exists(); - $cooldown = (int) config('dewemoji.billing.pending_cooldown_seconds', 120); + $cooldown = (int) config( + "dewemoji.billing.pending_cooldown_seconds", + 120, + ); if ($cooldown > 0) { $latestPending = Payment::query() - ->where('user_id', $user->id) - ->where('status', 'pending') - ->orderByDesc('id') + ->where("user_id", $user->id) + ->where("status", "pending") + ->orderByDesc("id") ->first(); if ($latestPending && $latestPending->created_at) { - $age = max(0, now()->getTimestamp() - $latestPending->created_at->getTimestamp()); + $age = max( + 0, + now()->getTimestamp() - + $latestPending->created_at->getTimestamp(), + ); $pendingCooldownRemaining = max(0, $cooldown - $age); } } } - return view('site.pricing', [ - 'currencyPref' => $currencyPref, - 'usdRate' => $rate, - 'pricing' => $pricing, - 'payments' => [ - 'qris_url' => (string) config('dewemoji.payments.qris_url', ''), - 'paypal_url' => (string) config('dewemoji.payments.paypal_url', ''), + return view("site.pricing", [ + "currencyPref" => $currencyPref, + "usdRate" => $rate, + "pricing" => $pricing, + "payments" => [ + "qris_url" => (string) config("dewemoji.payments.qris_url", ""), + "paypal_url" => (string) config( + "dewemoji.payments.paypal_url", + "", + ), ], - 'pakasirEnabled' => (bool) config('dewemoji.billing.providers.pakasir.enabled', false) - && (string) config('dewemoji.billing.providers.pakasir.api_base', '') !== '' - && (string) config('dewemoji.billing.providers.pakasir.api_key', '') !== '' - && (string) config('dewemoji.billing.providers.pakasir.project', '') !== '', - 'paypalEnabled' => $this->paypalEnabled($this->billingMode()), - 'paypalPlans' => $this->paypalPlanAvailability($this->billingMode()), - 'hasActiveLifetime' => $hasActiveLifetime, - 'hasPendingPayment' => $hasPendingPayment, - 'pendingCooldownRemaining' => $pendingCooldownRemaining, + "pakasirEnabled" => + (bool) config( + "dewemoji.billing.providers.pakasir.enabled", + false, + ) && + (string) config( + "dewemoji.billing.providers.pakasir.api_base", + "", + ) !== "" && + (string) config( + "dewemoji.billing.providers.pakasir.api_key", + "", + ) !== "" && + (string) config( + "dewemoji.billing.providers.pakasir.project", + "", + ) !== "", + "paypalEnabled" => $this->paypalEnabled($this->billingMode()), + "paypalPlans" => $this->paypalPlanAvailability( + $this->billingMode(), + ), + "hasActiveLifetime" => $hasActiveLifetime, + "hasPendingPayment" => $hasPendingPayment, + "pendingCooldownRemaining" => $pendingCooldownRemaining, ]); } @@ -211,23 +253,43 @@ class SiteController extends Controller return true; } - $fallback = $mode === 'live' ? 'sandbox' : 'live'; + $fallback = $mode === "live" ? "sandbox" : "live"; return $this->paypalConfiguredMode($fallback); } private function paypalConfiguredMode(string $mode): bool { - $enabled = (bool) config('dewemoji.billing.providers.paypal.enabled', false); - $clientId = (string) config("dewemoji.billing.providers.paypal.{$mode}.client_id", ''); - $clientSecret = (string) config("dewemoji.billing.providers.paypal.{$mode}.client_secret", ''); - $apiBase = (string) config("dewemoji.billing.providers.paypal.{$mode}.api_base", ''); + $enabled = (bool) config( + "dewemoji.billing.providers.paypal.enabled", + false, + ); + $clientId = (string) config( + "dewemoji.billing.providers.paypal.{$mode}.client_id", + "", + ); + $clientSecret = (string) config( + "dewemoji.billing.providers.paypal.{$mode}.client_secret", + "", + ); + $apiBase = (string) config( + "dewemoji.billing.providers.paypal.{$mode}.api_base", + "", + ); - return $enabled && $clientId !== '' && $clientSecret !== '' && $apiBase !== ''; + return $enabled && + $clientId !== "" && + $clientSecret !== "" && + $apiBase !== ""; } private function paypalPlanAvailability(string $mode): array { - $plans = PricingPlan::whereIn('code', ['personal_monthly', 'personal_annual'])->get()->keyBy('code'); + $plans = PricingPlan::whereIn("code", [ + "personal_monthly", + "personal_annual", + ]) + ->get() + ->keyBy("code"); $fromDb = function (string $code) use ($plans, $mode): bool { $plan = $plans->get($code); @@ -235,157 +297,188 @@ class SiteController extends Controller return false; } $meta = $plan->meta ?? []; - return (string) ($meta['paypal'][$mode]['plan']['id'] ?? '') !== ''; + return (string) ($meta["paypal"][$mode]["plan"]["id"] ?? "") !== ""; }; $fromEnv = function (string $code) use ($mode): bool { - return (string) config("dewemoji.billing.providers.paypal.plan_ids.{$mode}.{$code}", '') !== ''; + return (string) config( + "dewemoji.billing.providers.paypal.plan_ids.{$mode}.{$code}", + "", + ) !== ""; }; return [ - 'personal_monthly' => $fromDb('personal_monthly') || $fromEnv('personal_monthly'), - 'personal_annual' => $fromDb('personal_annual') || $fromEnv('personal_annual'), + "personal_monthly" => + $fromDb("personal_monthly") || $fromEnv("personal_monthly"), + "personal_annual" => + $fromDb("personal_annual") || $fromEnv("personal_annual"), ]; } public function setPricingCurrency(Request $request): RedirectResponse { $data = $request->validate([ - 'currency' => 'required|string|in:IDR,USD', + "currency" => "required|string|in:IDR,USD", ]); - session(['pricing_currency' => $data['currency']]); + session(["pricing_currency" => $data["currency"]]); return back(); } public function support(): View { - return view('site.support'); + return view("site.support"); } public function download(): View { - $downloadBaseUrl = rtrim((string) config('dewemoji.apk_release.public_base_url', ''), '/'); - $androidEnabled = (bool) config('dewemoji.apk_release.enabled', false) && $downloadBaseUrl !== ''; + $downloadBaseUrl = rtrim( + (string) config("dewemoji.apk_release.public_base_url", ""), + "/", + ); + $androidEnabled = false; - return view('site.download', [ - 'androidEnabled' => $androidEnabled, - 'androidVersionJsonUrl' => $androidEnabled ? $downloadBaseUrl.'/version.json' : '', - 'androidLatestApkUrl' => $androidEnabled ? $downloadBaseUrl.'/dewemoji-latest.apk' : '', + return view("site.download", [ + "androidEnabled" => $androidEnabled, + "androidVersionJsonUrl" => $androidEnabled + ? $downloadBaseUrl . "/version.json" + : "", + "androidLatestApkUrl" => $androidEnabled + ? $downloadBaseUrl . "/dewemoji-latest.apk" + : "", ]); } - public function downloadVersionJson(Request $request): RedirectResponse|JsonResponse - { - $target = $this->apkReleaseTargetUrl('version_json'); - if ($target === '') { - return response()->json(['ok' => false, 'error' => 'apk_release_not_configured'], 404); + public function downloadVersionJson( + Request $request, + ): RedirectResponse|JsonResponse { + $target = $this->apkReleaseTargetUrl("version_json"); + if ($target === "") { + return response()->json( + ["ok" => false, "error" => "apk_release_not_configured"], + 404, + ); } return redirect()->away($target, 302, [ - 'Cache-Control' => 'no-store, no-cache, must-revalidate', - 'Pragma' => 'no-cache', + "Cache-Control" => "no-store, no-cache, must-revalidate", + "Pragma" => "no-cache", ]); } - public function downloadLatestApk(Request $request): RedirectResponse|JsonResponse - { - $target = $this->apkReleaseTargetUrl('latest_apk'); - if ($target === '') { - return response()->json(['ok' => false, 'error' => 'apk_release_not_configured'], 404); + public function downloadLatestApk( + Request $request, + ): RedirectResponse|JsonResponse { + $target = $this->apkReleaseTargetUrl("latest_apk"); + if ($target === "") { + return response()->json( + ["ok" => false, "error" => "apk_release_not_configured"], + 404, + ); } return redirect()->away($target, 302, [ - 'Cache-Control' => 'no-store, no-cache, must-revalidate', - 'Pragma' => 'no-cache', + "Cache-Control" => "no-store, no-cache, must-revalidate", + "Pragma" => "no-cache", ]); } public function assetLinks(): JsonResponse { - $appId = trim((string) config('dewemoji.apk_release.app_id', '')); - $rawFingerprints = (array) config('dewemoji.apk_release.assetlinks.fingerprints', []); + $appId = trim((string) config("dewemoji.apk_release.app_id", "")); + $rawFingerprints = (array) config( + "dewemoji.apk_release.assetlinks.fingerprints", + [], + ); $fingerprints = []; foreach ($rawFingerprints as $fingerprint) { - $normalized = $this->normalizeApkCertFingerprint((string) $fingerprint); - if ($normalized !== '') { + $normalized = $this->normalizeApkCertFingerprint( + (string) $fingerprint, + ); + if ($normalized !== "") { $fingerprints[] = $normalized; } } $fingerprints = array_values(array_unique($fingerprints)); - if ($appId === '' || $fingerprints === []) { + if ($appId === "" || $fingerprints === []) { return response()->json([], 200, [ - 'Cache-Control' => 'no-store, no-cache, must-revalidate', - 'Pragma' => 'no-cache', + "Cache-Control" => "no-store, no-cache, must-revalidate", + "Pragma" => "no-cache", ]); } - return response()->json([ + return response()->json( [ - 'relation' => [ - 'delegate_permission/common.handle_all_urls', - ], - 'target' => [ - 'namespace' => 'android_app', - 'package_name' => $appId, - 'sha256_cert_fingerprints' => $fingerprints, + [ + "relation" => [ + "delegate_permission/common.handle_all_urls", + ], + "target" => [ + "namespace" => "android_app", + "package_name" => $appId, + "sha256_cert_fingerprints" => $fingerprints, + ], ], ], - ], 200, [ - 'Cache-Control' => 'no-store, no-cache, must-revalidate', - 'Pragma' => 'no-cache', - ]); + 200, + [ + "Cache-Control" => "no-store, no-cache, must-revalidate", + "Pragma" => "no-cache", + ], + ); } public function privacy(): View { - return view('site.privacy'); + return view("site.privacy"); } public function terms(): View { - return view('site.terms'); + return view("site.terms"); } private function detectPricingCurrency(Request $request): string { - $country = strtoupper((string) ($request->header('CF-IPCountry') - ?? $request->header('X-Country-Code') - ?? $request->header('X-Geo-Country') - ?? $request->header('X-Appengine-Country') - ?? $request->header('CloudFront-Viewer-Country') - ?? '')); + $country = strtoupper( + (string) ($request->header("CF-IPCountry") ?? + ($request->header("X-Country-Code") ?? + ($request->header("X-Geo-Country") ?? + ($request->header("X-Appengine-Country") ?? + ($request->header("CloudFront-Viewer-Country") ?? + ""))))), + ); - return $country === 'ID' ? 'IDR' : 'USD'; + return $country === "ID" ? "IDR" : "USD"; } public function emojiDetail(string $slug): View|Response { $dataPath = $this->datasetPath(); if (!is_file($dataPath)) { - abort(500, 'Emoji dataset file not found.'); + abort(500, "Emoji dataset file not found."); } $raw = file_get_contents($dataPath); if ($raw === false) { - abort(500, 'Emoji dataset file could not be read.'); + abort(500, "Emoji dataset file could not be read."); } $decoded = json_decode($raw, true); if (!is_array($decoded)) { - abort(500, 'Emoji dataset JSON is invalid.'); + abort(500, "Emoji dataset JSON is invalid."); } - $items = $decoded['emojis'] ?? []; + $items = $decoded["emojis"] ?? []; $match = null; $byEmoji = []; foreach ($items as $item) { - $char = (string) ($item['emoji'] ?? ''); - if ($char !== '' && !isset($byEmoji[$char])) { + $char = (string) ($item["emoji"] ?? ""); + if ($char !== "" && !isset($byEmoji[$char])) { $byEmoji[$char] = $item; } - if (($item['slug'] ?? '') === $slug) { + if (($item["slug"] ?? "") === $slug) { $match = $item; } } @@ -395,98 +488,143 @@ class SiteController extends Controller } $relatedDetails = []; - foreach (array_slice($match['related'] ?? [], 0, 8) as $relatedEmoji) { + foreach (array_slice($match["related"] ?? [], 0, 8) as $relatedEmoji) { $relatedEmoji = (string) $relatedEmoji; $ref = $byEmoji[$relatedEmoji] ?? null; $relatedDetails[] = [ - 'emoji' => $relatedEmoji, - 'slug' => (string) ($ref['slug'] ?? ''), - 'name' => (string) ($ref['name'] ?? $relatedEmoji), + "emoji" => $relatedEmoji, + "slug" => (string) ($ref["slug"] ?? ""), + "name" => (string) ($ref["name"] ?? $relatedEmoji), ]; } $user = request()->user(); $canManageKeywords = (bool) $user; - $isPersonal = $user && (string) $user->tier === 'personal'; - $freeLimit = (int) config('dewemoji.pagination.free_max_limit', 20); + $isPersonal = $user && (string) $user->tier === "personal"; + $freeLimit = (int) config("dewemoji.pagination.free_max_limit", 20); $keywordLimit = $isPersonal ? null : $freeLimit; $userKeywords = []; $activeKeywordCount = 0; if ($canManageKeywords) { - $activeKeywordCount = UserKeyword::where('user_id', $user->id) - ->where('is_active', true) + $activeKeywordCount = UserKeyword::where("user_id", $user->id) + ->where("is_active", true) ->count(); - $userKeywords = UserKeyword::where('user_id', $user->id) - ->where('emoji_slug', $slug) - ->orderByDesc('id') + $userKeywords = UserKeyword::where("user_id", $user->id) + ->where("emoji_slug", $slug) + ->orderByDesc("id") ->get(); } - $limitReached = $keywordLimit !== null && $activeKeywordCount >= $keywordLimit; + $limitReached = + $keywordLimit !== null && $activeKeywordCount >= $keywordLimit; - return view('site.emoji-detail', [ - 'emoji' => $match, - 'relatedDetails' => $relatedDetails, - 'canonicalPath' => '/emoji/'.$slug, - 'userKeywords' => $userKeywords, - 'canManageKeywords' => $canManageKeywords, - 'keywordLimit' => $keywordLimit, - 'limitReached' => $limitReached, - 'activeKeywordCount' => $activeKeywordCount, - 'userTier' => $user?->tier, + return view("site.emoji-detail", [ + "emoji" => $match, + "relatedDetails" => $relatedDetails, + "canonicalPath" => "/emoji/" . $slug, + "userKeywords" => $userKeywords, + "canManageKeywords" => $canManageKeywords, + "keywordLimit" => $keywordLimit, + "limitReached" => $limitReached, + "activeKeywordCount" => $activeKeywordCount, + "userTier" => $user?->tier, ]); } public function robotsTxt(): Response { - $base = rtrim(config('app.url', request()->getSchemeAndHttpHost()), '/'); - $body = "User-agent: *\nAllow: /\n\nSitemap: ".$base."/sitemap.xml\n"; + $base = rtrim( + config("app.url", request()->getSchemeAndHttpHost()), + "/", + ); + $body = + "User-agent: *\nAllow: /\n\nSitemap: " . $base . "/sitemap.xml\n"; - return response($body, 200)->header('Content-Type', 'text/plain; charset=UTF-8'); + return response($body, 200)->header( + "Content-Type", + "text/plain; charset=UTF-8", + ); } public function sitemapXml(): Response { $data = $this->loadDataset(); - $items = is_array($data['emojis'] ?? null) ? $data['emojis'] : []; - $base = rtrim(config('app.url', request()->getSchemeAndHttpHost()), '/'); + $items = is_array($data["emojis"] ?? null) ? $data["emojis"] : []; + $base = rtrim( + config("app.url", request()->getSchemeAndHttpHost()), + "/", + ); - $lastUpdatedTs = isset($data['last_updated_ts']) ? (int) $data['last_updated_ts'] : time(); - $lastUpdated = gmdate('Y-m-d\TH:i:s\Z', $lastUpdatedTs); + $lastUpdatedTs = isset($data["last_updated_ts"]) + ? (int) $data["last_updated_ts"] + : time(); + $lastUpdated = gmdate("Y-m-d\TH:i:s\Z", $lastUpdatedTs); $urls = [ - ['loc' => $base.'/', 'priority' => '0.8', 'changefreq' => 'daily'], - ['loc' => $base.'/api-docs', 'priority' => '0.5', 'changefreq' => 'weekly'], - ['loc' => $base.'/pricing', 'priority' => '0.7', 'changefreq' => 'weekly'], - ['loc' => $base.'/privacy', 'priority' => '0.3', 'changefreq' => 'monthly'], - ['loc' => $base.'/terms', 'priority' => '0.3', 'changefreq' => 'monthly'], - ['loc' => $base.'/support', 'priority' => '0.4', 'changefreq' => 'weekly'], + [ + "loc" => $base . "/", + "priority" => "0.8", + "changefreq" => "daily", + ], + [ + "loc" => $base . "/api-docs", + "priority" => "0.5", + "changefreq" => "weekly", + ], + [ + "loc" => $base . "/pricing", + "priority" => "0.7", + "changefreq" => "weekly", + ], + [ + "loc" => $base . "/privacy", + "priority" => "0.3", + "changefreq" => "monthly", + ], + [ + "loc" => $base . "/terms", + "priority" => "0.3", + "changefreq" => "monthly", + ], + [ + "loc" => $base . "/support", + "priority" => "0.4", + "changefreq" => "weekly", + ], ]; foreach ($items as $item) { - $slug = trim((string) ($item['slug'] ?? '')); - if ($slug === '' || $this->shouldHideForSitemap($item)) { + $slug = trim((string) ($item["slug"] ?? "")); + if ($slug === "" || $this->shouldHideForSitemap($item)) { continue; } $urls[] = [ - 'loc' => $base.'/emoji/'.$slug, - 'priority' => '0.6', - 'changefreq' => 'weekly', + "loc" => $base . "/emoji/" . $slug, + "priority" => "0.6", + "changefreq" => "weekly", ]; } - $xml = ''."\n"; - $xml .= ''."\n"; + $xml = '' . "\n"; + $xml .= + '' . + "\n"; foreach ($urls as $url) { $xml .= " \n"; - $xml .= ' '.htmlspecialchars((string) $url['loc'], ENT_XML1)."\n"; - $xml .= ' '.$lastUpdated."\n"; - $xml .= ' '.$url['changefreq']."\n"; - $xml .= ' '.$url['priority']."\n"; + $xml .= + " " . + htmlspecialchars((string) $url["loc"], ENT_XML1) . + "\n"; + $xml .= " " . $lastUpdated . "\n"; + $xml .= " " . $url["changefreq"] . "\n"; + $xml .= " " . $url["priority"] . "\n"; $xml .= " \n"; } - $xml .= ''."\n"; + $xml .= "" . "\n"; - return response($xml, 200)->header('Content-Type', 'application/xml; charset=UTF-8'); + return response($xml, 200)->header( + "Content-Type", + "application/xml; charset=UTF-8", + ); } /** @@ -509,17 +647,17 @@ class SiteController extends Controller { $dataPath = $this->datasetPath(); if (!is_file($dataPath)) { - return ['emojis' => []]; + return ["emojis" => []]; } $raw = file_get_contents($dataPath); if ($raw === false) { - return ['emojis' => []]; + return ["emojis" => []]; } $decoded = json_decode($raw, true); if (!is_array($decoded)) { - return ['emojis' => []]; + return ["emojis" => []]; } return $decoded; @@ -528,45 +666,49 @@ class SiteController extends Controller private function datasetPath(): string { $settings = app(SettingsService::class); - $activePath = (string) $settings->get('emoji_dataset_active_path', ''); - if ($activePath !== '' && is_file($activePath)) { + $activePath = (string) $settings->get("emoji_dataset_active_path", ""); + if ($activePath !== "" && is_file($activePath)) { return $activePath; } - return (string) config('dewemoji.data_path'); + return (string) config("dewemoji.data_path"); } private function apkReleaseTargetUrl(string $key): string { - if (!(bool) config('dewemoji.apk_release.enabled', false)) { - return ''; + if (!(bool) config("dewemoji.apk_release.enabled", false)) { + return ""; } - $base = trim((string) config('dewemoji.apk_release.r2_public_base_url', '')); - $objectKey = trim((string) config("dewemoji.apk_release.r2_keys.{$key}", '')); - if ($base === '' || $objectKey === '') { - return ''; + $base = trim( + (string) config("dewemoji.apk_release.r2_public_base_url", ""), + ); + $objectKey = trim( + (string) config("dewemoji.apk_release.r2_keys.{$key}", ""), + ); + if ($base === "" || $objectKey === "") { + return ""; } - return rtrim($base, '/').'/'.ltrim($objectKey, '/'); + return rtrim($base, "/") . "/" . ltrim($objectKey, "/"); } private function normalizeApkCertFingerprint(string $value): string { $clean = strtoupper(trim($value)); - if ($clean === '') { - return ''; + if ($clean === "") { + return ""; } if (preg_match('/^[0-9A-F]{64}$/', $clean) === 1) { - return implode(':', str_split($clean, 2)); + return implode(":", str_split($clean, 2)); } if (preg_match('/^[0-9A-F]{2}(?::[0-9A-F]{2}){31}$/', $clean) === 1) { return $clean; } - return ''; + return ""; } /** @@ -574,39 +716,39 @@ class SiteController extends Controller */ private function shouldHideForSitemap(array $emoji): bool { - $name = strtolower(trim((string) ($emoji['name'] ?? ''))); - $category = strtolower(trim((string) ($emoji['category'] ?? ''))); - $subcategory = strtolower(trim((string) ($emoji['subcategory'] ?? ''))); + $name = strtolower(trim((string) ($emoji["name"] ?? ""))); + $category = strtolower(trim((string) ($emoji["category"] ?? ""))); + $subcategory = strtolower(trim((string) ($emoji["subcategory"] ?? ""))); - if ($subcategory === 'family' || str_starts_with($name, 'family:')) { + if ($subcategory === "family" || str_starts_with($name, "family:")) { return true; } - if (preg_match('~\bwoman: beard\b~i', $name)) { + if (preg_match("~\bwoman: beard\b~i", $name)) { return true; } - if (preg_match('~\bmen with bunny ears\b~i', $name)) { + if (preg_match("~\bmen with bunny ears\b~i", $name)) { return true; } - if (preg_match('~\bpregnant man\b~i', $name)) { + if (preg_match("~\bpregnant man\b~i", $name)) { return true; } - if ($category === 'people & body') { - if (preg_match('~\bmen holding hands\b~i', $name)) { + if ($category === "people & body") { + if (preg_match("~\bmen holding hands\b~i", $name)) { return true; } - if (preg_match('~\bwomen holding hands\b~i', $name)) { + if (preg_match("~\bwomen holding hands\b~i", $name)) { return true; } - if (preg_match('~kiss:.*\bman,\s*man\b~i', $name)) { + if (preg_match("~kiss:.*\bman,\s*man\b~i", $name)) { return true; } - if (preg_match('~kiss:.*\bwoman,\s*woman\b~i', $name)) { + if (preg_match("~kiss:.*\bwoman,\s*woman\b~i", $name)) { return true; } - if (preg_match('~couple.*\bman,\s*man\b~i', $name)) { + if (preg_match("~couple.*\bman,\s*man\b~i", $name)) { return true; } - if (preg_match('~couple.*\bwoman,\s*woman\b~i', $name)) { + if (preg_match("~couple.*\bwoman,\s*woman\b~i", $name)) { return true; } }