mirror of
https://github.com/HolgerHatGarKeineNode/einundzwanzig-nostr.git
synced 2026-01-03 04:30:16 +00:00
This commit introduces a change in the authorization mechanism for the admin sections of the association members and election pages. Instead of checking for a single allowed public key, the system now checks for an array of allowed public keys, enhancing the flexibility of the admin access control.
220 lines
7.2 KiB
PHP
220 lines
7.2 KiB
PHP
<?php
|
|
|
|
use Livewire\Volt\Component;
|
|
|
|
use swentel\nostr\Filter\Filter;
|
|
use swentel\nostr\Key\Key;
|
|
use swentel\nostr\Message\EventMessage;
|
|
use swentel\nostr\Message\RequestMessage;
|
|
use swentel\nostr\Relay\Relay;
|
|
use swentel\nostr\Relay\RelaySet;
|
|
use swentel\nostr\Request\Request;
|
|
use swentel\nostr\Subscription\Subscription;
|
|
use swentel\nostr\Event\Event as NostrEvent;
|
|
use swentel\nostr\Sign\Sign;
|
|
|
|
use function Livewire\Volt\computed;
|
|
use function Livewire\Volt\mount;
|
|
use function Livewire\Volt\state;
|
|
use function Livewire\Volt\with;
|
|
use function Livewire\Volt\updated;
|
|
use function Laravel\Folio\{middleware};
|
|
use function Laravel\Folio\name;
|
|
use function Livewire\Volt\{on};
|
|
|
|
name('association.election.admin');
|
|
|
|
state(['isAllowed' => false]);
|
|
state(['currentPubkey' => null]);
|
|
state(['votes' => null]);
|
|
state(['events' => null]);
|
|
state(['election' => fn() => $election]);
|
|
state(['signThisEvent' => '']);
|
|
state([
|
|
'plebs' => fn()
|
|
=> \App\Models\EinundzwanzigPleb::query()
|
|
->with([
|
|
'profile',
|
|
])
|
|
->whereIn('association_status', [3, 4])
|
|
->orderBy('association_status', 'desc')
|
|
->get()
|
|
->toArray(),
|
|
]);
|
|
state([
|
|
'electionConfig' => function () {
|
|
return collect(json_decode($this->election->candidates, true, 512, JSON_THROW_ON_ERROR))
|
|
->map(function ($c) {
|
|
$candidates = \App\Models\Profile::query()
|
|
->whereIn('pubkey', $c['c'])
|
|
->get()
|
|
->map(fn($p)
|
|
=> [
|
|
'pubkey' => $p->pubkey,
|
|
'name' => $p->name,
|
|
'picture' => $p->picture,
|
|
]);
|
|
|
|
return [
|
|
'type' => $c['type'],
|
|
'c' => $c['c'],
|
|
'candidates' => $candidates,
|
|
];
|
|
});
|
|
},
|
|
]);
|
|
|
|
mount(function () {
|
|
$this->loadEvents();
|
|
$this->loadVotes();
|
|
});
|
|
|
|
on([
|
|
'nostrLoggedIn' => function ($pubkey) {
|
|
$this->currentPubkey = $pubkey;
|
|
$allowedPubkeys = [
|
|
'0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033',
|
|
'430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279'
|
|
];
|
|
if (!in_array($this->currentPubkey, $allowedPubkeys, true)) {
|
|
return redirect()->route('association.profile');
|
|
}
|
|
$this->isAllowed = true;
|
|
},
|
|
]);
|
|
|
|
on([
|
|
'echo:votes,.newVote' => function () {
|
|
$this->loadEvents();
|
|
$this->loadVotes();
|
|
},
|
|
]);
|
|
|
|
$loadVotes = function () {
|
|
$votes = collect($this->events)
|
|
->map(function ($event) {
|
|
$votedFor = \App\Models\Profile::query()
|
|
->where('pubkey', str($event['content'])->before(',')->toString())
|
|
->first();
|
|
if (!$votedFor) {
|
|
Artisan::call(\App\Console\Commands\Nostr\FetchProfile::class, [
|
|
'--pubkey' => str($event['content'])->before(',')->toString(),
|
|
]);
|
|
$votedFor = \App\Models\Profile::query()
|
|
->where('pubkey', str($event['content'])->before(',')->toString())
|
|
->first();
|
|
}
|
|
$votedFor = $votedFor->toArray();
|
|
|
|
return [
|
|
'created_at' => $event['created_at'],
|
|
'pubkey' => $event['pubkey'],
|
|
'forpubkey' => $votedFor['pubkey'],
|
|
'type' => str($event['content'])->after(',')->toString(),
|
|
];
|
|
})
|
|
->sortByDesc('created_at')
|
|
->unique(fn($event) => $event['pubkey'] . $event['type'])
|
|
->values()
|
|
->toArray();
|
|
|
|
$this->votes = collect($votes)
|
|
->groupBy('type')
|
|
->map(fn($votes)
|
|
=> [
|
|
'type' => $votes[0]['type'],
|
|
'votes' => collect($votes)
|
|
->groupBy('forpubkey')
|
|
->map(fn($group) => ['count' => $group->count()])
|
|
->toArray(),
|
|
])
|
|
->values()
|
|
->toArray();
|
|
};
|
|
|
|
$loadEvents = function () {
|
|
$subscription = new Subscription();
|
|
$subscriptionId = $subscription->setId();
|
|
|
|
$filter1 = new Filter();
|
|
$filter1->setKinds([2121]); // You can add multiple kind numbers
|
|
$filters = [$filter1]; // You can add multiple filters.
|
|
|
|
$requestMessage = new RequestMessage($subscriptionId, $filters);
|
|
|
|
$relays = [
|
|
new Relay(config('services.relay')),
|
|
];
|
|
$relaySet = new RelaySet();
|
|
$relaySet->setRelays($relays);
|
|
|
|
$request = new Request($relaySet, $requestMessage);
|
|
$response = $request->send();
|
|
|
|
$this->events = collect($response[config('services.relay')])
|
|
->map(fn($event)
|
|
=> [
|
|
'id' => $event->event->id,
|
|
'kind' => $event->event->kind,
|
|
'content' => $event->event->content,
|
|
'pubkey' => $event->event->pubkey,
|
|
'tags' => $event->event->tags,
|
|
'created_at' => $event->event->created_at,
|
|
])
|
|
->toArray();
|
|
};
|
|
|
|
?>
|
|
|
|
<x-layouts.app title="{{ __('Wahl Manager') }}">
|
|
@volt
|
|
@php
|
|
$positions = [
|
|
'presidency' => ['icon' => 'fa-crown', 'title' => 'Präsidium'],
|
|
'vice_president' => ['icon' => 'fa-user-group-crown', 'title' => 'Vizepräsidium'],
|
|
'finances' => ['icon' => 'fa-bitcoin-sign', 'title' => 'Finanzen'],
|
|
'secretary' => ['icon' => 'fa-stapler', 'title' => 'Revisionsstelle'],
|
|
'press_officer' => ['icon' => 'fa-newspaper', 'title' => 'Pressewart'],
|
|
'it_manager' => ['icon' => 'fa-server', 'title' => 'Technikwart'],
|
|
];
|
|
@endphp
|
|
|
|
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto" x-data="electionAdminCharts(@this)">
|
|
|
|
<!-- Dashboard actions -->
|
|
<div class="sm:flex sm:justify-between sm:items-center mb-8">
|
|
|
|
<!-- Left: Title -->
|
|
<div class="mb-4 sm:mb-0">
|
|
<h1 class="text-2xl md:text-3xl text-gray-800 dark:text-gray-100 font-bold">
|
|
Wahl des Vorstands {{ $election->year }}
|
|
</h1>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Cards -->
|
|
<div class="grid grid-cols-12 gap-6">
|
|
@foreach($positions as $key => $position)
|
|
<div wire:key="pos_{{ $key }}" wire:ignore
|
|
class="flex flex-col col-span-full sm:col-span-6 bg-white dark:bg-gray-800 shadow-sm rounded-xl">
|
|
<header class="px-5 py-4 border-b border-gray-100 dark:border-gray-700/60">
|
|
<h2 class="font-semibold text-gray-800 dark:text-gray-100"><i
|
|
class="fa-sharp-duotone fa-solid {{ $position['icon'] }} w-5 h-5 fill-current text-white mr-4"></i>{{ $position['title'] }}
|
|
</h2>
|
|
</header>
|
|
<div class="grow">
|
|
<!-- Change the height attribute to adjust the chart height -->
|
|
<canvas x-ref="chart_{{ $key }}" width="724" height="288"
|
|
style="display: block; box-sizing: border-box; height: 288px; width: 724px;"></canvas>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
@endvolt
|
|
</x-layouts.app>
|