diff --git a/app/Http/Controllers/Api/BindleController.php b/app/Http/Controllers/Api/BindleController.php deleted file mode 100644 index a2e084f..0000000 --- a/app/Http/Controllers/Api/BindleController.php +++ /dev/null @@ -1,36 +0,0 @@ - - */ - public function __invoke(): Collection - { - return LibraryItem::query() - ->where('type', 'bindle') - ->with([ - 'media', - ]) - ->orderByDesc('id') - ->get() - ->map(fn ($item) => [ - 'id' => $item->id, - 'name' => $item->name, - 'link' => strtok($item->value, '?'), - 'image' => $item->getFirstMediaUrl('main'), - ]); - } -} diff --git a/app/Http/Controllers/Api/HighscoreController.php b/app/Http/Controllers/Api/HighscoreController.php deleted file mode 100644 index f71bd68..0000000 --- a/app/Http/Controllers/Api/HighscoreController.php +++ /dev/null @@ -1,164 +0,0 @@ -orderByDesc('satoshis') - ->orderBy('achieved_at') - ->get() - ->map(fn (Highscore $highscore) => [ - 'npub' => $highscore->npub, - 'name' => $highscore->name, - 'satoshis' => $highscore->satoshis, - 'blocks' => $highscore->blocks, - 'datetime' => $highscore->achieved_at->toIso8601String(), - ]); - - return response()->json([ - 'data' => $highscores, - ]); - } - - /** - * Highscore einreichen - * - * Reicht einen Highscore ein (idempotent pro npub und Zeitpunkt). - * Zusätzlich auf 10 Anfragen pro Minute begrenzt. - * Fehlt ein Name, versucht der Server, ihn über das Nostr-Profil zu ergänzen. - * Antwortet mit HTTP 202. - */ - #[Response(status: 429, description: 'Zu viele Anfragen (Limit: 10 pro Minute überschritten).')] - public function store(StoreHighscoreRequest $request): JsonResponse - { - $validated = $request->validated(); - $achievedAt = CarbonImmutable::parse($validated['datetime']); - - $highscore = Highscore::query()->firstOrNew([ - 'npub' => $validated['npub'], - 'achieved_at' => $achievedAt, - ]); - - $highscore->satoshis = (int) $validated['satoshis']; - $highscore->blocks = (int) $validated['blocks']; - - if (array_key_exists('name', $validated)) { - $highscore->name = $validated['name']; - } - - $highscore->save(); - - if (empty($highscore->name)) { - $fetchedName = $this->fetchNostrName($highscore->npub); - if ($fetchedName) { - $highscore->name = $fetchedName; - $highscore->save(); - } - } - - Log::info('Highscore submission received', [ - 'npub' => $highscore->npub, - 'name' => $highscore->name, - 'satoshis' => $highscore->satoshis, - 'blocks' => $highscore->blocks, - 'datetime' => $highscore->achieved_at->toIso8601String(), - ]); - - return response()->json([ - 'message' => 'Highscore received', - 'data' => [ - 'npub' => $highscore->npub, - 'name' => $highscore->name, - 'satoshis' => $highscore->satoshis, - 'blocks' => $highscore->blocks, - 'datetime' => $highscore->achieved_at->toIso8601String(), - ], - ], 202); - } - - protected function fetchNostrName(string $npub): ?string - { - $author = trim($npub); - - if (! str_starts_with($author, 'npub1')) { - return null; - } - - $subscription = new Subscription; - $filter = new Filter; - $filter->setAuthors([$author]); - $filter->setKinds([0]); - - $requestMessage = new RequestMessage($subscription->getId(), [$filter]); - $relaySet = new RelaySet; - $relaySet->setRelays([ - new Relay('wss://nos.lol'), - ]); - - $request = new Request($relaySet, $requestMessage); - - try { - $response = $request->send(); - - foreach ($response as $relayUrl => $relayResponses) { - foreach ($relayResponses as $message) { - if (! isset($message->event)) { - continue; - } - - try { - $profile = json_decode($message->event->content, true, 512, JSON_THROW_ON_ERROR); - - if (isset($profile['name']) && is_string($profile['name']) && $profile['name'] !== '') { - Log::info('Fetched nostr profile name for highscore', [ - 'npub' => $author, - 'relay' => $relayUrl, - ]); - - return $profile['name']; - } - } catch (\JsonException $e) { - Log::warning('Failed to decode nostr profile for highscore', [ - 'npub' => $author, - 'relay' => $relayUrl, - 'error' => $e->getMessage(), - ]); - } - } - } - } catch (\Throwable $e) { - Log::warning('Failed to fetch nostr profile for highscore', [ - 'npub' => $author, - 'error' => $e->getMessage(), - ]); - } - - return null; - } -} diff --git a/app/Http/Requests/StoreHighscoreRequest.php b/app/Http/Requests/StoreHighscoreRequest.php deleted file mode 100644 index cef6520..0000000 --- a/app/Http/Requests/StoreHighscoreRequest.php +++ /dev/null @@ -1,52 +0,0 @@ -|string> - */ - public function rules(): array - { - return [ - 'npub' => ['required', 'string', 'starts_with:npub1', 'max:100'], - 'name' => ['nullable', 'string', 'max:255'], - 'satoshis' => ['required', 'integer', 'min:0'], - 'blocks' => ['required', 'integer', 'min:0'], - 'datetime' => ['required', 'date'], - ]; - } - - public function messages(): array - { - return [ - 'npub.required' => 'An npub is required to record the highscore.', - 'npub.starts_with' => 'The npub must start with npub1.', - 'name.string' => 'The name must be a valid string.', - 'satoshis.required' => 'Please provide the earned satoshis amount.', - 'satoshis.integer' => 'Satoshis must be a whole number.', - 'blocks.required' => 'Please provide the number of blocks.', - 'blocks.integer' => 'Blocks must be a whole number.', - 'datetime.required' => 'Please provide when the score was achieved.', - 'datetime.date' => 'The datetime value must be a valid date.', - ]; - } -} diff --git a/app/Livewire/BooksForPlebs/BookRentalGuide.php b/app/Livewire/BooksForPlebs/BookRentalGuide.php deleted file mode 100644 index f3f18c4..0000000 --- a/app/Livewire/BooksForPlebs/BookRentalGuide.php +++ /dev/null @@ -1,23 +0,0 @@ -with( [ - 'SEOData' => new SEOData( - title: __('BooksForPlebs'), - description: __('Lokale Buchausleihe für Bitcoin-Meetups.'), - image: asset('img/book-rental.jpg') - ), - ]); - } -} diff --git a/app/Models/Highscore.php b/app/Models/Highscore.php deleted file mode 100644 index 19b6cfb..0000000 --- a/app/Models/Highscore.php +++ /dev/null @@ -1,30 +0,0 @@ - 'integer', - 'satoshis' => 'integer', - 'blocks' => 'integer', - 'achieved_at' => 'datetime', - ]; -} diff --git a/config/scramble.php b/config/scramble.php index 3caf5ed..17f4823 100644 --- a/config/scramble.php +++ b/config/scramble.php @@ -64,8 +64,7 @@ return [ ## Rate Limiting - Öffentliche Endpunkte sind auf **60 Anfragen/Minute** begrenzt, das Einreichen von - Highscores zusätzlich auf **10 Anfragen/Minute**. + Öffentliche Endpunkte sind auf **60 Anfragen/Minute** begrenzt. MARKDOWN, ], @@ -96,7 +95,7 @@ return [ 'view' => 'scramble::scalar', 'cdn' => 'https://cdn.jsdelivr.net/npm/@scalar/api-reference', 'theme' => 'laravel', - 'proxyUrl' => 'https://proxy.scalar.com', + 'proxyUrl' => '', 'darkMode' => true, 'showDeveloperTools' => 'never', 'agent' => ['disabled' => true], diff --git a/database/factories/HighscoreFactory.php b/database/factories/HighscoreFactory.php deleted file mode 100644 index 956ad6b..0000000 --- a/database/factories/HighscoreFactory.php +++ /dev/null @@ -1,26 +0,0 @@ - - */ -class HighscoreFactory extends Factory -{ - protected $model = Highscore::class; - - public function definition(): array - { - return [ - 'npub' => NostrHelper::randomNpub(), - 'name' => fake()->name(), - 'satoshis' => fake()->numberBetween(0, 100000), - 'blocks' => fake()->numberBetween(0, 1000), - 'achieved_at' => fake()->dateTimeBetween('-1 year', 'now'), - ]; - } -} diff --git a/database/migrations/2026_02_02_105837_create_highscores_table.php b/database/migrations/2026_02_02_105837_create_highscores_table.php deleted file mode 100644 index ab8ddf7..0000000 --- a/database/migrations/2026_02_02_105837_create_highscores_table.php +++ /dev/null @@ -1,35 +0,0 @@ -id(); - $table->string('npub', 100); - $table->string('name')->nullable(); - $table->unsignedBigInteger('satoshis'); - $table->unsignedInteger('blocks'); - $table->dateTime('achieved_at'); - $table->timestamps(); - - $table->unique(['npub', 'achieved_at']); - $table->index('satoshis'); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('highscores'); - } -}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index aa82402..ef8abad 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -11,7 +11,6 @@ use App\Models\CourseEvent; use App\Models\EmailCampaign; use App\Models\EmailTexts; use App\Models\Episode; -use App\Models\Highscore; use App\Models\Lecturer; use App\Models\Library; use App\Models\LibraryItem; @@ -28,7 +27,6 @@ use App\Models\TwitterAccount; use App\Models\User; use App\Models\Venue; use App\Models\Vote; -use Database\Factories\Helpers\NostrHelper; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\DB; @@ -167,7 +165,7 @@ class DatabaseSeeder extends Seeder } }); - $this->command->info('Phase 6: Voting & Highscores'); + $this->command->info('Phase 6: Voting'); $proposals->each(function (ProjectProposal $proposal) use ($users) { foreach ($users->random(min(8, $users->count())) as $voter) { Vote::create([ @@ -180,17 +178,6 @@ class DatabaseSeeder extends Seeder } }); - foreach (NostrHelper::realNpubs() as $i => $npub) { - for ($d = 0; $d < 5; $d++) { - Highscore::factory()->create([ - 'npub' => $npub, - 'achieved_at' => now()->subDays(($i * 10) + $d), - 'satoshis' => fake()->numberBetween(1000, 1_000_000), - 'blocks' => fake()->numberBetween(1, 5000), - ]); - } - } - $this->command->info('Phase 7: LoginKeys'); LoginKey::factory()->count(5)->recycle($users)->create(); diff --git a/resources/views/livewire/books-for-plebs/book-rental-guide.blade.php b/resources/views/livewire/books-for-plebs/book-rental-guide.blade.php deleted file mode 100644 index 41e087b..0000000 --- a/resources/views/livewire/books-for-plebs/book-rental-guide.blade.php +++ /dev/null @@ -1,213 +0,0 @@ -
- Vielen Dank, dass du dich dazu entschieden hast, deine
-
- ₿itcoin-Bücher
-
- zur Verfügung zu stellen. Mit dieser Anleitung kannst du eine Bezahladresse
- generieren und hast auch alle Materialien, die du benötigst. Wir haben
- darauf geachtet, dass es für jedes Meetup geeignet ist. Deshalb stellen
- wir dir die Quelldateien zur Verfügung, damit du deinen eigenen QR-Code
- einfügen und das Logo eures Meetups verwenden kannst.
-
-
- Du hast keine ₿itcoin Wallet oder kein Programm zum Bearbeiten der Dateien? - Kein Problem! Schreib uns einfach und wir helfen dir. -
-- (Zum Editieren brauchst du - - Adobe Illustrator) - -
-
- - Download .zip -
- - -- (Zum Editieren brauchst du - - Adobe Illustrator) - -
-
- - Download .zip -
- -- (Nicht editierbar) -
-
-
- - (Nicht editierbar) -
-
-
-
- Um deinen
-
- ₿itcoin
-
- QR-Code zu erstellen, kopiere einfach die Empfangsadresse aus der Wallet
- deiner Wahl und füge sie hier ein:
-
-
- www.qr-code-generator.com
-
-
- Der QR-Code-Generator akzeptiert sowohl Lightning als auch Onchain-Empfangsadressen.
- Wir empfehlen dir jedoch Lightning zu verwenden, da es schneller und zumeist deutlich günstiger als Onchain ist.
-
-
-
-
- Vorsicht: Bitte KEINE Lightning-Adressen,verwenden, da diese nach einem bestimmten Zeitraum ablaufen!
- Stattdessen nutzt Ihr bitte eine LNURL, da diese Statisch sind.
-
-
- Tipp: Der Lightning TipBot "LN.tips" erzeugt euch eine. Dazu müsst Ihr diesen nur aktivieren und mit dem Befehl
- "/advanced" eure LNURL anzeigen lassen und diese copy-pasten.
- Alternativ kann dies auch die WalletOfSatoshi, dort sehen Sie aus wie E-Mail Adessen, wie zum Beispiel:
- "BitcoinKalle@walletofsatoshi.com"
-
-
- Für die sichere Lagerung deiner Bücher empfehlen wir einen Meetup-Ort, - an dem du regelmäßig bist und die Bücher auch sicher verstaut werden können. - Falls dem nicht der Fall ist, solltet Ihr die Bücher lieber jedes mal separat mit zum Meetup - nehmen und die nicht verliehenen Bücher auch wieder mit zurück. -
- -- Du willst deine Bücher nicht nur deinem lokalen Meetup zur Verfügung stellen, - sondern online an die gesamte Community verschicken, dann komm in die Gruppe: -
- - - -- - - Vielen Dank, dass du deine Bücher zur Verfügung stellst und uns dabei - hilfst, das Wissen über ₿itcoin zu verbreiten! -
- -
-
- Happy Stacking
-
-