mirror of
https://github.com/HolgerHatGarKeineNode/einundzwanzig-nostr.git
synced 2026-01-27 06:33:18 +00:00
🧹 Migrate Yarn registry URLs to npm registry: update yarn.lock dependencies for consistency and clean up unused entries.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -23,3 +23,4 @@ yarn-error.log
|
|||||||
/.sisyphus
|
/.sisyphus
|
||||||
/.opencode
|
/.opencode
|
||||||
.switch-omo-config*
|
.switch-omo-config*
|
||||||
|
/videos
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Livewire\Forms;
|
namespace App\Livewire\Forms;
|
||||||
|
|
||||||
|
use App\Enums\AssociationStatus;
|
||||||
|
use App\Models\EinundzwanzigPleb;
|
||||||
use Livewire\Attributes\Validate;
|
use Livewire\Attributes\Validate;
|
||||||
use Livewire\Form;
|
use Livewire\Form;
|
||||||
|
|
||||||
@@ -10,6 +12,26 @@ class ApplicationForm extends Form
|
|||||||
#[Validate('nullable|string')]
|
#[Validate('nullable|string')]
|
||||||
public $reason = '';
|
public $reason = '';
|
||||||
|
|
||||||
#[Validate('boolean')]
|
#[Validate('accepted')]
|
||||||
public $check = false;
|
public $check = false;
|
||||||
|
|
||||||
|
public ?EinundzwanzigPleb $currentPleb = null;
|
||||||
|
|
||||||
|
public function setPleb(EinundzwanzigPleb $pleb): void
|
||||||
|
{
|
||||||
|
$this->currentPleb = $pleb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apply(AssociationStatus|int $status): void
|
||||||
|
{
|
||||||
|
$this->validate();
|
||||||
|
|
||||||
|
$status = $status instanceof AssociationStatus ? $status : AssociationStatus::from($status);
|
||||||
|
|
||||||
|
$this->currentPleb->update([
|
||||||
|
'association_status' => $status,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->reset('check');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
64
app/Livewire/Forms/ProfileForm.php
Normal file
64
app/Livewire/Forms/ProfileForm.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire\Forms;
|
||||||
|
|
||||||
|
use App\Models\EinundzwanzigPleb;
|
||||||
|
use Flux\Flux;
|
||||||
|
use Livewire\Attributes\Validate;
|
||||||
|
use Livewire\Form;
|
||||||
|
|
||||||
|
class ProfileForm extends Form
|
||||||
|
{
|
||||||
|
#[Validate('nullable|email')]
|
||||||
|
public ?string $email = '';
|
||||||
|
|
||||||
|
#[Validate('nullable|string|max:255|regex:/^[a-z0-9_-]+$/|unique:einundzwanzig_plebs,nip05_handle')]
|
||||||
|
public ?string $nip05Handle = '';
|
||||||
|
|
||||||
|
public ?EinundzwanzigPleb $currentPleb;
|
||||||
|
|
||||||
|
public function setEmail(EinundzwanzigPleb $currentPleb): void
|
||||||
|
{
|
||||||
|
$this->currentPleb = $currentPleb;
|
||||||
|
$this->email = $currentPleb->email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNip05Handle(EinundzwanzigPleb $currentPleb): void
|
||||||
|
{
|
||||||
|
$this->currentPleb = $currentPleb;
|
||||||
|
$this->nip05Handle = $currentPleb->nip05_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPleb(EinundzwanzigPleb $currentPleb): void
|
||||||
|
{
|
||||||
|
$this->currentPleb = $currentPleb;
|
||||||
|
$this->email = $currentPleb->email;
|
||||||
|
$this->nip05Handle = $currentPleb->nip05_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saveEmail(): void
|
||||||
|
{
|
||||||
|
$this->validateOnly('email');
|
||||||
|
|
||||||
|
$this->currentPleb->update([
|
||||||
|
'email' => $this->email,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Flux::toast('E-Mail Adresse gespeichert.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saveNip05Handle(): void
|
||||||
|
{
|
||||||
|
$this->validateOnly('nip05Handle');
|
||||||
|
|
||||||
|
$nip05Handle = $this->nip05Handle ? strtolower($this->nip05Handle) : null;
|
||||||
|
|
||||||
|
$this->currentPleb->update([
|
||||||
|
'nip05_handle' => $nip05Handle,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->nip05Handle = $nip05Handle;
|
||||||
|
|
||||||
|
Flux::toast('NIP-05 Handle gespeichert.');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Livewire\Forms\ApplicationForm;
|
use App\Livewire\Forms\ApplicationForm;
|
||||||
|
use App\Livewire\Forms\ProfileForm;
|
||||||
use App\Models\EinundzwanzigPleb;
|
use App\Models\EinundzwanzigPleb;
|
||||||
use App\Support\NostrAuth;
|
use App\Support\NostrAuth;
|
||||||
use App\Traits\NostrFetcherTrait;
|
use App\Traits\NostrFetcherTrait;
|
||||||
@@ -16,22 +17,19 @@ use swentel\nostr\Request\Request;
|
|||||||
use swentel\nostr\Sign\Sign;
|
use swentel\nostr\Sign\Sign;
|
||||||
use swentel\nostr\Subscription\Subscription;
|
use swentel\nostr\Subscription\Subscription;
|
||||||
|
|
||||||
new class extends Component
|
new class extends Component {
|
||||||
{
|
|
||||||
use NostrFetcherTrait;
|
use NostrFetcherTrait;
|
||||||
|
|
||||||
public ApplicationForm $form;
|
public ApplicationForm $form;
|
||||||
|
|
||||||
|
public ProfileForm $profileForm;
|
||||||
|
|
||||||
public bool $no = false;
|
public bool $no = false;
|
||||||
|
|
||||||
public bool $showEmail = true;
|
public bool $showEmail = true;
|
||||||
|
|
||||||
public string $fax = '';
|
public string $fax = '';
|
||||||
|
|
||||||
public ?string $email = '';
|
|
||||||
|
|
||||||
public ?string $nip05Handle = '';
|
|
||||||
|
|
||||||
public bool $nip05Verified = false;
|
public bool $nip05Verified = false;
|
||||||
|
|
||||||
public ?string $nip05VerifiedHandle = null;
|
public ?string $nip05VerifiedHandle = null;
|
||||||
@@ -67,15 +65,15 @@ new class extends Component
|
|||||||
$this->currentPubkey = NostrAuth::pubkey();
|
$this->currentPubkey = NostrAuth::pubkey();
|
||||||
$this->currentPleb = EinundzwanzigPleb::query()
|
$this->currentPleb = EinundzwanzigPleb::query()
|
||||||
->with([
|
->with([
|
||||||
'paymentEvents' => fn ($query) => $query->where('year', date('Y')),
|
'paymentEvents' => fn($query) => $query->where('year', date('Y')),
|
||||||
'profile',
|
'profile',
|
||||||
])
|
])
|
||||||
->where('pubkey', $this->currentPubkey)->first();
|
->where('pubkey', $this->currentPubkey)->first();
|
||||||
if ($this->currentPleb) {
|
if ($this->currentPleb) {
|
||||||
$this->email = $this->currentPleb->email;
|
$this->profileForm->setPleb($this->currentPleb);
|
||||||
if ($this->currentPleb->nip05_handle) {
|
$this->form->setPleb($this->currentPleb);
|
||||||
$this->nip05Handle = $this->currentPleb->nip05_handle;
|
|
||||||
|
|
||||||
|
if ($this->currentPleb->nip05_handle) {
|
||||||
// Get all NIP-05 handles for the current pubkey
|
// Get all NIP-05 handles for the current pubkey
|
||||||
$this->nip05VerifiedHandles = $this->getNip05HandlesForPubkey($this->currentPubkey);
|
$this->nip05VerifiedHandles = $this->getNip05HandlesForPubkey($this->currentPubkey);
|
||||||
|
|
||||||
@@ -84,13 +82,13 @@ new class extends Component
|
|||||||
$this->nip05VerifiedHandle = $this->nip05VerifiedHandles[0];
|
$this->nip05VerifiedHandle = $this->nip05VerifiedHandles[0];
|
||||||
|
|
||||||
// Check if verified handle differs from database handle
|
// Check if verified handle differs from database handle
|
||||||
if (! in_array($this->nip05Handle, $this->nip05VerifiedHandles, true)) {
|
if (!in_array($this->profileForm->nip05Handle, $this->nip05VerifiedHandles, true)) {
|
||||||
$this->nip05HandleMismatch = true;
|
$this->nip05HandleMismatch = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->no = $this->currentPleb->no_email;
|
$this->no = $this->currentPleb->no_email;
|
||||||
$this->showEmail = ! $this->no;
|
$this->showEmail = !$this->no;
|
||||||
$this->amountToPay = config('app.env') === 'production' ? 21000 : 1;
|
$this->amountToPay = config('app.env') === 'production' ? 21000 : 1;
|
||||||
if ($this->currentPleb->paymentEvents->count() < 1) {
|
if ($this->currentPleb->paymentEvents->count() < 1) {
|
||||||
$this->createPaymentEvent();
|
$this->createPaymentEvent();
|
||||||
@@ -104,7 +102,7 @@ new class extends Component
|
|||||||
|
|
||||||
public function updatedNo(): void
|
public function updatedNo(): void
|
||||||
{
|
{
|
||||||
$this->showEmail = ! $this->no;
|
$this->showEmail = !$this->no;
|
||||||
$this->currentPleb->update([
|
$this->currentPleb->update([
|
||||||
'no_email' => $this->no,
|
'no_email' => $this->no,
|
||||||
]);
|
]);
|
||||||
@@ -115,34 +113,59 @@ new class extends Component
|
|||||||
$this->js('alert("Markus Turm wird sich per Fax melden!")');
|
$this->js('alert("Markus Turm wird sich per Fax melden!")');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatedNip05Handle(): void
|
public function updatedProfileFormNip05Handle(): void
|
||||||
{
|
{
|
||||||
$this->nip05Handle = strtolower($this->nip05Handle);
|
$this->profileForm->nip05Handle = strtolower($this->profileForm->nip05Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleNostrLoggedIn(string $pubkey): void
|
||||||
|
{
|
||||||
|
$this->currentPubkey = $pubkey;
|
||||||
|
$this->currentPleb = EinundzwanzigPleb::query()
|
||||||
|
->with([
|
||||||
|
'paymentEvents' => fn($query) => $query->where('year', date('Y')),
|
||||||
|
'profile',
|
||||||
|
])
|
||||||
|
->where('pubkey', $pubkey)->first();
|
||||||
|
|
||||||
|
if ($this->currentPleb) {
|
||||||
|
$this->profileForm->setPleb($this->currentPleb);
|
||||||
|
$this->form->setPleb($this->currentPleb);
|
||||||
|
$this->no = $this->currentPleb->no_email;
|
||||||
|
$this->showEmail = !$this->no;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleNostrLoggedOut(): void
|
||||||
|
{
|
||||||
|
$this->currentPubkey = null;
|
||||||
|
$this->currentPleb = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveEmail(): void
|
public function saveEmail(): void
|
||||||
{
|
{
|
||||||
$this->validate([
|
$this->profileForm->saveEmail();
|
||||||
'email' => 'required|email',
|
|
||||||
]);
|
|
||||||
$this->currentPleb->update([
|
|
||||||
'email' => $this->email,
|
|
||||||
]);
|
|
||||||
Flux::toast('E-Mail Adresse gespeichert.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveNip05Handle(): void
|
public function saveNip05Handle(): void
|
||||||
{
|
{
|
||||||
$this->validate([
|
$this->profileForm->saveNip05Handle();
|
||||||
'nip05Handle' => 'required|string|max:255|regex:/^[a-z0-9_-]+$/|unique:einundzwanzig_plebs,nip05_handle',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$nip05Handle = strtolower($this->nip05Handle);
|
// Refresh NIP-05 verification status after saving
|
||||||
|
if ($this->currentPleb->nip05_handle) {
|
||||||
|
$this->nip05VerifiedHandles = $this->getNip05HandlesForPubkey($this->currentPubkey);
|
||||||
|
|
||||||
$this->currentPleb->update([
|
if (count($this->nip05VerifiedHandles) > 0) {
|
||||||
'nip05_handle' => $nip05Handle,
|
$this->nip05Verified = true;
|
||||||
]);
|
$this->nip05VerifiedHandle = $this->nip05VerifiedHandles[0];
|
||||||
Flux::toast('NIP-05 Handle gespeichert.');
|
|
||||||
|
if (!in_array($this->profileForm->nip05Handle, $this->nip05VerifiedHandles, true)) {
|
||||||
|
$this->nip05HandleMismatch = true;
|
||||||
|
} else {
|
||||||
|
$this->nip05HandleMismatch = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function pay($comment): mixed
|
public function pay($comment): mixed
|
||||||
@@ -229,17 +252,15 @@ new class extends Component
|
|||||||
|
|
||||||
public function save($type): void
|
public function save($type): void
|
||||||
{
|
{
|
||||||
$this->form->validate();
|
try {
|
||||||
if (! $this->form->check) {
|
$this->form->apply($type);
|
||||||
$this->js('alert("Du musst den Statuten zustimmen.")');
|
Flux::toast('Mitgliedschaft erfolgreich beantragt!', variant: 'success');
|
||||||
|
} catch (\Illuminate\Validation\ValidationException $e) {
|
||||||
return;
|
if (!$this->form->check) {
|
||||||
|
$this->js('alert("Du musst den Statuten zustimmen.")');
|
||||||
|
}
|
||||||
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->currentPleb
|
|
||||||
->update([
|
|
||||||
'association_status' => $type,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createPaymentEvent(): void
|
public function createPaymentEvent(): void
|
||||||
@@ -295,7 +316,7 @@ new class extends Component
|
|||||||
|
|
||||||
$this->events = collect($response[config('services.relay')])
|
$this->events = collect($response[config('services.relay')])
|
||||||
->map(function ($event) {
|
->map(function ($event) {
|
||||||
if (! isset($event->event)) {
|
if (!isset($event->event)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,12 +388,15 @@ new class extends Component
|
|||||||
@if($currentPleb && $currentPleb->association_status->value > 1 && $currentYearIsPaid)
|
@if($currentPleb && $currentPleb->association_status->value > 1 && $currentYearIsPaid)
|
||||||
<div class="mt-3 space-y-2">
|
<div class="mt-3 space-y-2">
|
||||||
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
|
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
|
||||||
Ein Outbox-Relay ist wie ein Postbote für deine Nostr-Nachrichten. Es speichert und
|
Ein Outbox-Relay ist wie ein Postbote für deine Nostr-Nachrichten. Es
|
||||||
verteilt deine Posts. Um unser Relay nutzen zu können, musst du es in deinem
|
speichert und
|
||||||
|
verteilt deine Posts. Um unser Relay nutzen zu können, musst du es in
|
||||||
|
deinem
|
||||||
Nostr-Client hinzufügen.
|
Nostr-Client hinzufügen.
|
||||||
</p>
|
</p>
|
||||||
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
|
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
|
||||||
Gehe in deinem Nostr-Client zu den Einstellungen (meistens "Settings" oder
|
Gehe in deinem Nostr-Client zu den Einstellungen (meistens "Settings"
|
||||||
|
oder
|
||||||
"Relays") und füge folgende Outbox-Relay-Adresse hinzu:
|
"Relays") und füge folgende Outbox-Relay-Adresse hinzu:
|
||||||
</p>
|
</p>
|
||||||
<div class="flex items-center gap-2 mt-2">
|
<div class="flex items-center gap-2 mt-2">
|
||||||
@@ -383,8 +407,10 @@ new class extends Component
|
|||||||
</code>
|
</code>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
|
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
|
||||||
<strong>Wichtige Hinweise:</strong> Du kannst deine Posts auf mehreren Relays gleichzeitig
|
<strong>Wichtige Hinweise:</strong> Du kannst deine Posts auf mehreren
|
||||||
veröffentlichen. So stellst du sicher, dass deine Inhalte auch über unser Relay erreichbar sind.
|
Relays gleichzeitig
|
||||||
|
veröffentlichen. So stellst du sicher, dass deine Inhalte auch über
|
||||||
|
unser Relay erreichbar sind.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@@ -419,12 +445,16 @@ new class extends Component
|
|||||||
<flux:label>Dein NIP-05 Handle</flux:label>
|
<flux:label>Dein NIP-05 Handle</flux:label>
|
||||||
<flux:input.group>
|
<flux:input.group>
|
||||||
<flux:input
|
<flux:input
|
||||||
wire:model.live.debounce="nip05Handle"
|
wire:model.live.debounce="profileForm.nip05Handle"
|
||||||
placeholder="dein-name"
|
placeholder="dein-name"
|
||||||
|
wire:dirty.class="border-amber-500 dark:border-amber-400"
|
||||||
/>
|
/>
|
||||||
<flux:input.group.suffix>@einundzwanzig.space</flux:input.group.suffix>
|
<flux:input.group.suffix>@einundzwanzig.space</flux:input.group.suffix>
|
||||||
</flux:input.group>
|
</flux:input.group>
|
||||||
<flux:error name="nip05Handle"/>
|
<flux:error name="profileForm.nip05Handle"/>
|
||||||
|
<div wire:dirty wire:target="profileForm.nip05Handle" class="text-xs text-amber-600 dark:text-amber-400 mt-1">
|
||||||
|
Nicht gespeichert...
|
||||||
|
</div>
|
||||||
</flux:field>
|
</flux:field>
|
||||||
|
|
||||||
<div class="flex gap-3">
|
<div class="flex gap-3">
|
||||||
@@ -433,7 +463,8 @@ new class extends Component
|
|||||||
wire:loading.attr="disabled"
|
wire:loading.attr="disabled"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="primary">
|
variant="primary">
|
||||||
Speichern
|
<span wire:loading.remove wire:target="saveNip05Handle">Speichern</span>
|
||||||
|
<span wire:loading wire:target="saveNip05Handle">Speichert...</span>
|
||||||
</flux:button>
|
</flux:button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -465,24 +496,30 @@ new class extends Component
|
|||||||
@if($nip05Verified)
|
@if($nip05Verified)
|
||||||
<flux:callout variant="success" icon="check-circle" class="mt-4">
|
<flux:callout variant="success" icon="check-circle" class="mt-4">
|
||||||
<p class="font-medium text-zinc-800 dark:text-zinc-100">
|
<p class="font-medium text-zinc-800 dark:text-zinc-100">
|
||||||
Du hast {{ count($nip05VerifiedHandles) }} aktive Handles für deinen Pubkey!
|
Du hast {{ count($nip05VerifiedHandles) }} aktive Handles für deinen
|
||||||
|
Pubkey!
|
||||||
</p>
|
</p>
|
||||||
@if($nip05HandleMismatch)
|
@if($nip05HandleMismatch)
|
||||||
<p class="text-sm text-zinc-600 dark:text-zinc-400 mt-1">
|
<p class="text-sm text-zinc-600 dark:text-zinc-400 mt-1">
|
||||||
Die Synchronisation zu <strong class="break-all">{{ $nip05Handle }}@einundzwanzig.space</strong> wird automatisch im Hintergrund durchgeführt.
|
Die Synchronisation zu <strong
|
||||||
|
class="break-all">{{ $profileForm->nip05Handle }}
|
||||||
|
@einundzwanzig.space</strong> wird automatisch im Hintergrund
|
||||||
|
durchgeführt.
|
||||||
</p>
|
</p>
|
||||||
@endif
|
@endif
|
||||||
</flux:callout>
|
</flux:callout>
|
||||||
|
|
||||||
<!-- List of all active handles -->
|
<!-- List of all active handles -->
|
||||||
<div class="mt-4 p-4 bg-white/50 dark:bg-zinc-800/50 rounded border border-zinc-200 dark:border-zinc-600">
|
<div
|
||||||
|
class="mt-4 p-4 bg-white/50 dark:bg-zinc-800/50 rounded border border-zinc-200 dark:border-zinc-600">
|
||||||
<p class="text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-2">
|
<p class="text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-2">
|
||||||
Deine aktivierten Handles:
|
Deine aktivierten Handles:
|
||||||
</p>
|
</p>
|
||||||
<ul class="space-y-2">
|
<ul class="space-y-2">
|
||||||
@foreach($nip05VerifiedHandles as $handle)
|
@foreach($nip05VerifiedHandles as $handle)
|
||||||
<li class="flex items-center gap-2 text-sm">
|
<li class="flex items-center gap-2 text-sm">
|
||||||
<span class="break-all text-zinc-800 dark:text-zinc-200 font-mono">
|
<span
|
||||||
|
class="break-all text-zinc-800 dark:text-zinc-200 font-mono">
|
||||||
{{ $handle }}@einundzwanzig.space
|
{{ $handle }}@einundzwanzig.space
|
||||||
</span>
|
</span>
|
||||||
<flux:badge color="green" size="xs">OK</flux:badge>
|
<flux:badge color="green" size="xs">OK</flux:badge>
|
||||||
@@ -490,13 +527,15 @@ new class extends Component
|
|||||||
@endforeach
|
@endforeach
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@elseif($nip05Handle)
|
@elseif($profileForm->nip05Handle)
|
||||||
<flux:callout variant="secondary" icon="information-circle" class="mt-4">
|
<flux:callout variant="secondary" icon="information-circle" class="mt-4">
|
||||||
<p class="font-medium text-zinc-800 dark:text-zinc-100">
|
<p class="font-medium text-zinc-800 dark:text-zinc-100">
|
||||||
Dein Handle <strong class="break-all">{{ $nip05Handle }}@einundzwanzig.space</strong> ist noch nicht aktiv.
|
Dein Handle <strong class="break-all">{{ $profileForm->nip05Handle }}
|
||||||
|
@einundzwanzig.space</strong> ist noch nicht aktiv.
|
||||||
</p>
|
</p>
|
||||||
<p class="text-sm text-zinc-600 dark:text-zinc-400 mt-1">
|
<p class="text-sm text-zinc-600 dark:text-zinc-400 mt-1">
|
||||||
Das Handle ist gespeichert, aber noch nicht in der NIP-05 Konfiguration veröffentlicht.
|
Das Handle ist gespeichert, aber noch nicht in der NIP-05 Konfiguration
|
||||||
|
veröffentlicht.
|
||||||
Der Vorstand wird dies bald aktivieren.
|
Der Vorstand wird dies bald aktivieren.
|
||||||
</p>
|
</p>
|
||||||
</flux:callout>
|
</flux:callout>
|
||||||
@@ -532,8 +571,10 @@ new class extends Component
|
|||||||
@if($currentPleb && $currentPleb->association_status->value > 1 && $currentYearIsPaid)
|
@if($currentPleb && $currentPleb->association_status->value > 1 && $currentYearIsPaid)
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
|
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
|
||||||
Ein Watchtower überwacht deine Lightning Channel und schützt sie, falls deine Node
|
Ein Watchtower überwacht deine Lightning Channel und schützt sie, falls deine
|
||||||
offline ist. Wenn du die Zahlung von Channel-Closing-Transaktionen verpasst, kümmert sich
|
Node
|
||||||
|
offline ist. Wenn du die Zahlung von Channel-Closing-Transaktionen verpasst,
|
||||||
|
kümmert sich
|
||||||
der Watchtower darum und verhindert den Verlust deiner Sats.
|
der Watchtower darum und verhindert den Verlust deiner Sats.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -556,14 +597,26 @@ new class extends Component
|
|||||||
Einrichtung für gängige Lightning Clients:
|
Einrichtung für gängige Lightning Clients:
|
||||||
</p>
|
</p>
|
||||||
<ul class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed space-y-1 list-disc list-inside">
|
<ul class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed space-y-1 list-disc list-inside">
|
||||||
<li><strong>LND:</strong> <flux:link href="https://docs.lightning.engineering/lightning-network-tools/lnd/watchtower" target="_blank">https://docs.lightning.engineering/lightning-network-tools/lnd/watchtower</flux:link></li>
|
<li><strong>LND:</strong>
|
||||||
<li><strong>Core Lightning:</strong> Nutze den <code class="bg-zinc-200 dark:bg-zinc-700 px-1 rounded">watchtower-client</code> Plugin mit der URI</li>
|
<flux:link
|
||||||
<li><strong>Eclair:</strong> Füge die URI zu den Watchtower-Einstellungen in deiner eclair.conf hinzu</li>
|
href="https://docs.lightning.engineering/lightning-network-tools/lnd/watchtower"
|
||||||
|
target="_blank">
|
||||||
|
https://docs.lightning.engineering/lightning-network-tools/lnd/watchtower
|
||||||
|
</flux:link>
|
||||||
|
</li>
|
||||||
|
<li><strong>Core Lightning:</strong> Nutze den <code
|
||||||
|
class="bg-zinc-200 dark:bg-zinc-700 px-1 rounded">watchtower-client</code>
|
||||||
|
Plugin mit der URI
|
||||||
|
</li>
|
||||||
|
<li><strong>Eclair:</strong> Füge die URI zu den Watchtower-Einstellungen in
|
||||||
|
deiner eclair.conf hinzu
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
|
<p class="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
|
||||||
<strong>Wichtig:</strong> Der Watchtower überwacht deine Channel passiv. Er hat keinen Zugriff auf
|
<strong>Wichtig:</strong> Der Watchtower überwacht deine Channel passiv. Er hat
|
||||||
|
keinen Zugriff auf
|
||||||
deine privaten Schlüssel oder dein Guthaben.
|
deine privaten Schlüssel oder dein Guthaben.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -726,12 +779,14 @@ new class extends Component
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="group block">
|
class="group block">
|
||||||
<div class="relative overflow-hidden rounded-lg border border-zinc-200 dark:border-zinc-600 bg-white dark:bg-zinc-800 shadow-sm hover:shadow-md hover:shadow-amber-500/10 transition-all duration-300">
|
<div
|
||||||
|
class="relative overflow-hidden rounded-lg border border-zinc-200 dark:border-zinc-600 bg-white dark:bg-zinc-800 shadow-sm hover:shadow-md hover:shadow-amber-500/10 transition-all duration-300">
|
||||||
<img src="{{ asset('img/1.png') }}"
|
<img src="{{ asset('img/1.png') }}"
|
||||||
alt="Amber App Screenshot 1"
|
alt="Amber App Screenshot 1"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
class="w-full h-auto object-cover aspect-9/16 md:aspect-9/18 group-hover:scale-105 transition-transform duration-300">
|
class="w-full h-auto object-cover aspect-9/16 md:aspect-9/18 group-hover:scale-105 transition-transform duration-300">
|
||||||
<div class="absolute inset-0 bg-linear-to-t from-zinc-900/60 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
<div
|
||||||
|
class="absolute inset-0 bg-linear-to-t from-zinc-900/60 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||||
<div class="absolute top-3 left-3 right-3">
|
<div class="absolute top-3 left-3 right-3">
|
||||||
<h4 class="text-black text-sm md:text-base font-semibold drop-shadow-lg">
|
<h4 class="text-black text-sm md:text-base font-semibold drop-shadow-lg">
|
||||||
Startseite
|
Startseite
|
||||||
@@ -752,12 +807,14 @@ new class extends Component
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="group block">
|
class="group block">
|
||||||
<div class="relative overflow-hidden rounded-lg border border-zinc-200 dark:border-zinc-600 bg-white dark:bg-zinc-800 shadow-sm hover:shadow-md hover:shadow-amber-500/10 transition-all duration-300">
|
<div
|
||||||
|
class="relative overflow-hidden rounded-lg border border-zinc-200 dark:border-zinc-600 bg-white dark:bg-zinc-800 shadow-sm hover:shadow-md hover:shadow-amber-500/10 transition-all duration-300">
|
||||||
<img src="{{ asset('img/2.png') }}"
|
<img src="{{ asset('img/2.png') }}"
|
||||||
alt="Amber App Screenshot 2"
|
alt="Amber App Screenshot 2"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
class="w-full h-auto object-cover aspect-9/16 md:aspect-9/18 group-hover:scale-105 transition-transform duration-300">
|
class="w-full h-auto object-cover aspect-9/16 md:aspect-9/18 group-hover:scale-105 transition-transform duration-300">
|
||||||
<div class="absolute inset-0 bg-linear-to-t from-zinc-900/60 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
<div
|
||||||
|
class="absolute inset-0 bg-linear-to-t from-zinc-900/60 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||||
<div class="absolute top-3 left-3 right-3">
|
<div class="absolute top-3 left-3 right-3">
|
||||||
<h4 class="text-black text-sm md:text-base font-semibold drop-shadow-lg">
|
<h4 class="text-black text-sm md:text-base font-semibold drop-shadow-lg">
|
||||||
Profileinstellungen
|
Profileinstellungen
|
||||||
@@ -778,12 +835,14 @@ new class extends Component
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="group block">
|
class="group block">
|
||||||
<div class="relative overflow-hidden rounded-lg border border-zinc-200 dark:border-zinc-600 bg-white dark:bg-zinc-800 shadow-sm hover:shadow-md hover:shadow-amber-500/10 transition-all duration-300">
|
<div
|
||||||
|
class="relative overflow-hidden rounded-lg border border-zinc-200 dark:border-zinc-600 bg-white dark:bg-zinc-800 shadow-sm hover:shadow-md hover:shadow-amber-500/10 transition-all duration-300">
|
||||||
<img src="{{ asset('img/3.png') }}"
|
<img src="{{ asset('img/3.png') }}"
|
||||||
alt="Amber App Screenshot 3"
|
alt="Amber App Screenshot 3"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
class="w-full h-auto object-cover aspect-9/16 md:aspect-9/18 group-hover:scale-105 transition-transform duration-300">
|
class="w-full h-auto object-cover aspect-9/16 md:aspect-9/18 group-hover:scale-105 transition-transform duration-300">
|
||||||
<div class="absolute inset-0 bg-linear-to-t from-zinc-900/60 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
<div
|
||||||
|
class="absolute inset-0 bg-linear-to-t from-zinc-900/60 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||||
<div class="absolute top-3 left-3 right-3">
|
<div class="absolute top-3 left-3 right-3">
|
||||||
<h4 class="text-black text-sm md:text-base font-semibold drop-shadow-lg">
|
<h4 class="text-black text-sm md:text-base font-semibold drop-shadow-lg">
|
||||||
Keyverwaltung
|
Keyverwaltung
|
||||||
@@ -804,12 +863,14 @@ new class extends Component
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="group block">
|
class="group block">
|
||||||
<div class="relative overflow-hidden rounded-lg border border-zinc-200 dark:border-zinc-600 bg-white dark:bg-zinc-800 shadow-sm hover:shadow-md hover:shadow-amber-500/10 transition-all duration-300">
|
<div
|
||||||
|
class="relative overflow-hidden rounded-lg border border-zinc-200 dark:border-zinc-600 bg-white dark:bg-zinc-800 shadow-sm hover:shadow-md hover:shadow-amber-500/10 transition-all duration-300">
|
||||||
<img src="{{ asset('img/4.png') }}"
|
<img src="{{ asset('img/4.png') }}"
|
||||||
alt="Amber App Screenshot 4"
|
alt="Amber App Screenshot 4"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
class="w-full h-auto object-cover aspect-9/16 md:aspect-9/18 group-hover:scale-105 transition-transform duration-300">
|
class="w-full h-auto object-cover aspect-9/16 md:aspect-9/18 group-hover:scale-105 transition-transform duration-300">
|
||||||
<div class="absolute inset-0 bg-linear-to-t from-zinc-900/60 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
<div
|
||||||
|
class="absolute inset-0 bg-linear-to-t from-zinc-900/60 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||||||
<div class="absolute top-3 left-3 right-3">
|
<div class="absolute top-3 left-3 right-3">
|
||||||
<h4 class="text-black text-sm md:text-base font-semibold drop-shadow-lg">
|
<h4 class="text-black text-sm md:text-base font-semibold drop-shadow-lg">
|
||||||
Connect/nsec-Bunker
|
Connect/nsec-Bunker
|
||||||
@@ -882,7 +943,8 @@ new class extends Component
|
|||||||
<flux:error name="form.check"/>
|
<flux:error name="form.check"/>
|
||||||
</flux:field>
|
</flux:field>
|
||||||
<div class="flex flex-col sm:flex-row gap-3">
|
<div class="flex flex-col sm:flex-row gap-3">
|
||||||
<flux:button wire:click="save({{ \App\Enums\AssociationStatus::PASSIVE() }})" variant="primary">
|
<flux:button wire:click="save({{ \App\Enums\AssociationStatus::PASSIVE() }})"
|
||||||
|
variant="primary">
|
||||||
Mit deinem aktuellen Nostr-Profil Mitglied werden
|
Mit deinem aktuellen Nostr-Profil Mitglied werden
|
||||||
</flux:button>
|
</flux:button>
|
||||||
<flux:button href="https://einundzwanzig.space/verein/" target="_blank"
|
<flux:button href="https://einundzwanzig.space/verein/" target="_blank"
|
||||||
@@ -929,15 +991,22 @@ new class extends Component
|
|||||||
|
|
||||||
<flux:field>
|
<flux:field>
|
||||||
<flux:label>E-Mail Adresse</flux:label>
|
<flux:label>E-Mail Adresse</flux:label>
|
||||||
<flux:input type="email" wire:model.live.debounce="email"
|
<flux:input
|
||||||
placeholder="E-Mail Adresse"/>
|
type="email"
|
||||||
<flux:error name="email"/>
|
wire:model.live.debounce="profileForm.email"
|
||||||
|
placeholder="E-Mail Adresse"
|
||||||
|
wire:dirty.class="border-amber-500 dark:border-amber-400"/>
|
||||||
|
<flux:error name="profileForm.email"/>
|
||||||
|
<div wire:dirty wire:target="profileForm.email" class="text-xs text-amber-600 dark:text-amber-400 mt-1">
|
||||||
|
Nicht gespeichert...
|
||||||
|
</div>
|
||||||
</flux:field>
|
</flux:field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div wire:key="showSave">
|
<div wire:key="showSave">
|
||||||
<flux:button wire:click="saveEmail" wire:loading.attr="disabled">
|
<flux:button wire:click="saveEmail" wire:loading.attr="disabled">
|
||||||
Speichern
|
<span wire:loading.remove wire:target="saveEmail">Speichern</span>
|
||||||
|
<span wire:loading wire:target="saveEmail">Speichert...</span>
|
||||||
</flux:button>
|
</flux:button>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ it('can save email address', function () {
|
|||||||
NostrAuth::login($pleb->pubkey);
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
Livewire::test('association.profile')
|
Livewire::test('association.profile')
|
||||||
->set('email', 'test@example.com')
|
->set('profileForm.email', 'test@example.com')
|
||||||
->call('saveEmail')
|
->call('saveEmail')
|
||||||
->assertHasNoErrors();
|
->assertHasNoErrors();
|
||||||
|
|
||||||
@@ -44,9 +44,9 @@ it('validates email format', function () {
|
|||||||
NostrAuth::login($pleb->pubkey);
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
Livewire::test('association.profile')
|
Livewire::test('association.profile')
|
||||||
->set('email', 'invalid-email')
|
->set('profileForm.email', 'invalid-email')
|
||||||
->call('saveEmail')
|
->call('saveEmail')
|
||||||
->assertHasErrors(['email']);
|
->assertHasErrors(['profileForm.email']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can save nip05 handle', function () {
|
it('can save nip05 handle', function () {
|
||||||
@@ -55,11 +55,11 @@ it('can save nip05 handle', function () {
|
|||||||
NostrAuth::login($pleb->pubkey);
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
Livewire::test('association.profile')
|
Livewire::test('association.profile')
|
||||||
->set('nip05Handle', 'user@example.com')
|
->set('profileForm.nip05Handle', 'test-handle')
|
||||||
->call('saveNip05Handle')
|
->call('saveNip05Handle')
|
||||||
->assertHasNoErrors();
|
->assertHasNoErrors();
|
||||||
|
|
||||||
expect($pleb->fresh()->nip05_handle)->toBe('user@example.com');
|
expect($pleb->fresh()->nip05_handle)->toBe('test-handle');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('validates nip05 handle format', function () {
|
it('validates nip05 handle format', function () {
|
||||||
@@ -68,14 +68,14 @@ it('validates nip05 handle format', function () {
|
|||||||
NostrAuth::login($pleb->pubkey);
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
Livewire::test('association.profile')
|
Livewire::test('association.profile')
|
||||||
->set('nip05Handle', 'not-an-email')
|
->set('profileForm.nip05Handle', 'invalid handle with spaces')
|
||||||
->call('saveNip05Handle')
|
->call('saveNip05Handle')
|
||||||
->assertHasErrors(['nip05Handle']);
|
->assertHasErrors(['profileForm.nip05Handle']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('validates nip05 handle uniqueness', function () {
|
it('validates nip05 handle uniqueness', function () {
|
||||||
$pleb1 = EinundzwanzigPleb::factory()->active()->create([
|
$pleb1 = EinundzwanzigPleb::factory()->active()->create([
|
||||||
'nip05_handle' => 'taken@example.com',
|
'nip05_handle' => 'taken-handle',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$pleb2 = EinundzwanzigPleb::factory()->active()->create();
|
$pleb2 = EinundzwanzigPleb::factory()->active()->create();
|
||||||
@@ -83,20 +83,20 @@ it('validates nip05 handle uniqueness', function () {
|
|||||||
NostrAuth::login($pleb2->pubkey);
|
NostrAuth::login($pleb2->pubkey);
|
||||||
|
|
||||||
Livewire::test('association.profile')
|
Livewire::test('association.profile')
|
||||||
->set('nip05Handle', 'taken@example.com')
|
->set('profileForm.nip05Handle', 'taken-handle')
|
||||||
->call('saveNip05Handle')
|
->call('saveNip05Handle')
|
||||||
->assertHasErrors(['nip05Handle']);
|
->assertHasErrors(['profileForm.nip05Handle']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can save null nip05 handle', function () {
|
it('can save null nip05 handle', function () {
|
||||||
$pleb = EinundzwanzigPleb::factory()->active()->create([
|
$pleb = EinundzwanzigPleb::factory()->active()->create([
|
||||||
'nip05_handle' => 'old@example.com',
|
'nip05_handle' => 'old-handle',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
NostrAuth::login($pleb->pubkey);
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
Livewire::test('association.profile')
|
Livewire::test('association.profile')
|
||||||
->set('nip05Handle', null)
|
->set('profileForm.nip05Handle', null)
|
||||||
->call('saveNip05Handle')
|
->call('saveNip05Handle')
|
||||||
->assertHasNoErrors();
|
->assertHasNoErrors();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user