mirror of
https://github.com/HolgerHatGarKeineNode/einundzwanzig-nostr.git
synced 2026-01-27 06:33:18 +00:00
🗑️ Remove outdated migration files for einundzwanzig_plebs and pulse tables, restructure directory, and update testing suite with new factories and Livewire tests.
This commit is contained in:
@@ -17,6 +17,7 @@ This application is a Laravel application and its main Laravel ecosystems packag
|
|||||||
- livewire/flux (FLUXUI_FREE) - v2
|
- livewire/flux (FLUXUI_FREE) - v2
|
||||||
- livewire/flux-pro (FLUXUI_PRO) - v2
|
- livewire/flux-pro (FLUXUI_PRO) - v2
|
||||||
- livewire/livewire (LIVEWIRE) - v4
|
- livewire/livewire (LIVEWIRE) - v4
|
||||||
|
- livewire/volt (VOLT) - v1
|
||||||
- laravel/mcp (MCP) - v0
|
- laravel/mcp (MCP) - v0
|
||||||
- laravel/pint (PINT) - v1
|
- laravel/pint (PINT) - v1
|
||||||
- pestphp/pest (PEST) - v3
|
- pestphp/pest (PEST) - v3
|
||||||
@@ -267,6 +268,132 @@ accordion, autocomplete, avatar, badge, brand, breadcrumbs, button, calendar, ca
|
|||||||
->assertSeeLivewire(CreatePost::class);
|
->assertSeeLivewire(CreatePost::class);
|
||||||
</code-snippet>
|
</code-snippet>
|
||||||
|
|
||||||
|
=== volt/core rules ===
|
||||||
|
|
||||||
|
## Livewire Volt
|
||||||
|
|
||||||
|
- This project uses Livewire Volt for interactivity within its pages. New pages requiring interactivity must also use Livewire Volt.
|
||||||
|
- Make new Volt components using `vendor/bin/sail artisan make:volt [name] [--test] [--pest]`.
|
||||||
|
- Volt is a class-based and functional API for Livewire that supports single-file components, allowing a component's PHP logic and Blade templates to coexist in the same file.
|
||||||
|
- Livewire Volt allows PHP logic and Blade templates in one file. Components use the `@volt` directive.
|
||||||
|
- You must check existing Volt components to determine if they're functional or class-based. If you can't detect that, ask the user which they prefer before writing a Volt component.
|
||||||
|
|
||||||
|
### Volt Functional Component Example
|
||||||
|
|
||||||
|
<code-snippet name="Volt Functional Component Example" lang="php">
|
||||||
|
@volt
|
||||||
|
<?php
|
||||||
|
use function Livewire\Volt\{state, computed};
|
||||||
|
|
||||||
|
state(['count' => 0]);
|
||||||
|
|
||||||
|
$increment = fn () => $this->count++;
|
||||||
|
$decrement = fn () => $this->count--;
|
||||||
|
|
||||||
|
$double = computed(fn () => $this->count * 2);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>Count: {{ $count }}</h1>
|
||||||
|
<h2>Double: {{ $this->double }}</h2>
|
||||||
|
<button wire:click="increment">+</button>
|
||||||
|
<button wire:click="decrement">-</button>
|
||||||
|
</div>
|
||||||
|
@endvolt
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
### Volt Class Based Component Example
|
||||||
|
To get started, define an anonymous class that extends Livewire\Volt\Component. Within the class, you may utilize all of the features of Livewire using traditional Livewire syntax:
|
||||||
|
|
||||||
|
<code-snippet name="Volt Class-based Volt Component Example" lang="php">
|
||||||
|
use Livewire\Volt\Component;
|
||||||
|
|
||||||
|
new class extends Component {
|
||||||
|
public $count = 0;
|
||||||
|
|
||||||
|
public function increment()
|
||||||
|
{
|
||||||
|
$this->count++;
|
||||||
|
}
|
||||||
|
} ?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>{{ $count }}</h1>
|
||||||
|
<button wire:click="increment">+</button>
|
||||||
|
</div>
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
### Testing Volt & Volt Components
|
||||||
|
- Use the existing directory for tests if it already exists. Otherwise, fallback to `tests/Feature/Volt`.
|
||||||
|
|
||||||
|
<code-snippet name="Livewire Test Example" lang="php">
|
||||||
|
use Livewire\Volt\Volt;
|
||||||
|
|
||||||
|
test('counter increments', function () {
|
||||||
|
Volt::test('counter')
|
||||||
|
->assertSee('Count: 0')
|
||||||
|
->call('increment')
|
||||||
|
->assertSee('Count: 1');
|
||||||
|
});
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
<code-snippet name="Volt Component Test Using Pest" lang="php">
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use App\Models\{User, Product};
|
||||||
|
use Livewire\Volt\Volt;
|
||||||
|
|
||||||
|
test('product form creates product', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
|
||||||
|
Volt::test('pages.products.create')
|
||||||
|
->actingAs($user)
|
||||||
|
->set('form.name', 'Test Product')
|
||||||
|
->set('form.description', 'Test Description')
|
||||||
|
->set('form.price', 99.99)
|
||||||
|
->call('create')
|
||||||
|
->assertHasNoErrors();
|
||||||
|
|
||||||
|
expect(Product::where('name', 'Test Product')->exists())->toBeTrue();
|
||||||
|
});
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
### Common Patterns
|
||||||
|
|
||||||
|
<code-snippet name="CRUD With Volt" lang="php">
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Product;
|
||||||
|
use function Livewire\Volt\{state, computed};
|
||||||
|
|
||||||
|
state(['editing' => null, 'search' => '']);
|
||||||
|
|
||||||
|
$products = computed(fn() => Product::when($this->search,
|
||||||
|
fn($q) => $q->where('name', 'like', "%{$this->search}%")
|
||||||
|
)->get());
|
||||||
|
|
||||||
|
$edit = fn(Product $product) => $this->editing = $product->id;
|
||||||
|
$delete = fn(Product $product) => $product->delete();
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!-- HTML / UI Here -->
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
<code-snippet name="Real-Time Search With Volt" lang="php">
|
||||||
|
<flux:input
|
||||||
|
wire:model.live.debounce.300ms="search"
|
||||||
|
placeholder="Search..."
|
||||||
|
/>
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
<code-snippet name="Loading States With Volt" lang="php">
|
||||||
|
<flux:button wire:click="save" wire:loading.attr="disabled">
|
||||||
|
<span wire:loading.remove>Save</span>
|
||||||
|
<span wire:loading>Saving...</span>
|
||||||
|
</flux:button>
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
=== pint/core rules ===
|
=== pint/core rules ===
|
||||||
|
|
||||||
## Laravel Pint Code Formatter
|
## Laravel Pint Code Formatter
|
||||||
|
|||||||
127
AGENTS.md
127
AGENTS.md
@@ -17,6 +17,7 @@ This application is a Laravel application and its main Laravel ecosystems packag
|
|||||||
- livewire/flux (FLUXUI_FREE) - v2
|
- livewire/flux (FLUXUI_FREE) - v2
|
||||||
- livewire/flux-pro (FLUXUI_PRO) - v2
|
- livewire/flux-pro (FLUXUI_PRO) - v2
|
||||||
- livewire/livewire (LIVEWIRE) - v4
|
- livewire/livewire (LIVEWIRE) - v4
|
||||||
|
- livewire/volt (VOLT) - v1
|
||||||
- laravel/mcp (MCP) - v0
|
- laravel/mcp (MCP) - v0
|
||||||
- laravel/pint (PINT) - v1
|
- laravel/pint (PINT) - v1
|
||||||
- pestphp/pest (PEST) - v3
|
- pestphp/pest (PEST) - v3
|
||||||
@@ -267,6 +268,132 @@ accordion, autocomplete, avatar, badge, brand, breadcrumbs, button, calendar, ca
|
|||||||
->assertSeeLivewire(CreatePost::class);
|
->assertSeeLivewire(CreatePost::class);
|
||||||
</code-snippet>
|
</code-snippet>
|
||||||
|
|
||||||
|
=== volt/core rules ===
|
||||||
|
|
||||||
|
## Livewire Volt
|
||||||
|
|
||||||
|
- This project uses Livewire Volt for interactivity within its pages. New pages requiring interactivity must also use Livewire Volt.
|
||||||
|
- Make new Volt components using `vendor/bin/sail artisan make:volt [name] [--test] [--pest]`.
|
||||||
|
- Volt is a class-based and functional API for Livewire that supports single-file components, allowing a component's PHP logic and Blade templates to coexist in the same file.
|
||||||
|
- Livewire Volt allows PHP logic and Blade templates in one file. Components use the `@volt` directive.
|
||||||
|
- You must check existing Volt components to determine if they're functional or class-based. If you can't detect that, ask the user which they prefer before writing a Volt component.
|
||||||
|
|
||||||
|
### Volt Functional Component Example
|
||||||
|
|
||||||
|
<code-snippet name="Volt Functional Component Example" lang="php">
|
||||||
|
@volt
|
||||||
|
<?php
|
||||||
|
use function Livewire\Volt\{state, computed};
|
||||||
|
|
||||||
|
state(['count' => 0]);
|
||||||
|
|
||||||
|
$increment = fn () => $this->count++;
|
||||||
|
$decrement = fn () => $this->count--;
|
||||||
|
|
||||||
|
$double = computed(fn () => $this->count * 2);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>Count: {{ $count }}</h1>
|
||||||
|
<h2>Double: {{ $this->double }}</h2>
|
||||||
|
<button wire:click="increment">+</button>
|
||||||
|
<button wire:click="decrement">-</button>
|
||||||
|
</div>
|
||||||
|
@endvolt
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
### Volt Class Based Component Example
|
||||||
|
To get started, define an anonymous class that extends Livewire\Volt\Component. Within the class, you may utilize all of the features of Livewire using traditional Livewire syntax:
|
||||||
|
|
||||||
|
<code-snippet name="Volt Class-based Volt Component Example" lang="php">
|
||||||
|
use Livewire\Volt\Component;
|
||||||
|
|
||||||
|
new class extends Component {
|
||||||
|
public $count = 0;
|
||||||
|
|
||||||
|
public function increment()
|
||||||
|
{
|
||||||
|
$this->count++;
|
||||||
|
}
|
||||||
|
} ?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>{{ $count }}</h1>
|
||||||
|
<button wire:click="increment">+</button>
|
||||||
|
</div>
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
### Testing Volt & Volt Components
|
||||||
|
- Use the existing directory for tests if it already exists. Otherwise, fallback to `tests/Feature/Volt`.
|
||||||
|
|
||||||
|
<code-snippet name="Livewire Test Example" lang="php">
|
||||||
|
use Livewire\Volt\Volt;
|
||||||
|
|
||||||
|
test('counter increments', function () {
|
||||||
|
Volt::test('counter')
|
||||||
|
->assertSee('Count: 0')
|
||||||
|
->call('increment')
|
||||||
|
->assertSee('Count: 1');
|
||||||
|
});
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
<code-snippet name="Volt Component Test Using Pest" lang="php">
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use App\Models\{User, Product};
|
||||||
|
use Livewire\Volt\Volt;
|
||||||
|
|
||||||
|
test('product form creates product', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
|
||||||
|
Volt::test('pages.products.create')
|
||||||
|
->actingAs($user)
|
||||||
|
->set('form.name', 'Test Product')
|
||||||
|
->set('form.description', 'Test Description')
|
||||||
|
->set('form.price', 99.99)
|
||||||
|
->call('create')
|
||||||
|
->assertHasNoErrors();
|
||||||
|
|
||||||
|
expect(Product::where('name', 'Test Product')->exists())->toBeTrue();
|
||||||
|
});
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
### Common Patterns
|
||||||
|
|
||||||
|
<code-snippet name="CRUD With Volt" lang="php">
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Product;
|
||||||
|
use function Livewire\Volt\{state, computed};
|
||||||
|
|
||||||
|
state(['editing' => null, 'search' => '']);
|
||||||
|
|
||||||
|
$products = computed(fn() => Product::when($this->search,
|
||||||
|
fn($q) => $q->where('name', 'like', "%{$this->search}%")
|
||||||
|
)->get());
|
||||||
|
|
||||||
|
$edit = fn(Product $product) => $this->editing = $product->id;
|
||||||
|
$delete = fn(Product $product) => $product->delete();
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!-- HTML / UI Here -->
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
<code-snippet name="Real-Time Search With Volt" lang="php">
|
||||||
|
<flux:input
|
||||||
|
wire:model.live.debounce.300ms="search"
|
||||||
|
placeholder="Search..."
|
||||||
|
/>
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
<code-snippet name="Loading States With Volt" lang="php">
|
||||||
|
<flux:button wire:click="save" wire:loading.attr="disabled">
|
||||||
|
<span wire:loading.remove>Save</span>
|
||||||
|
<span wire:loading>Saving...</span>
|
||||||
|
</flux:button>
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
=== pint/core rules ===
|
=== pint/core rules ===
|
||||||
|
|
||||||
## Laravel Pint Code Formatter
|
## Laravel Pint Code Formatter
|
||||||
|
|||||||
127
CLAUDE.md
127
CLAUDE.md
@@ -17,6 +17,7 @@ This application is a Laravel application and its main Laravel ecosystems packag
|
|||||||
- livewire/flux (FLUXUI_FREE) - v2
|
- livewire/flux (FLUXUI_FREE) - v2
|
||||||
- livewire/flux-pro (FLUXUI_PRO) - v2
|
- livewire/flux-pro (FLUXUI_PRO) - v2
|
||||||
- livewire/livewire (LIVEWIRE) - v4
|
- livewire/livewire (LIVEWIRE) - v4
|
||||||
|
- livewire/volt (VOLT) - v1
|
||||||
- laravel/mcp (MCP) - v0
|
- laravel/mcp (MCP) - v0
|
||||||
- laravel/pint (PINT) - v1
|
- laravel/pint (PINT) - v1
|
||||||
- pestphp/pest (PEST) - v3
|
- pestphp/pest (PEST) - v3
|
||||||
@@ -267,6 +268,132 @@ accordion, autocomplete, avatar, badge, brand, breadcrumbs, button, calendar, ca
|
|||||||
->assertSeeLivewire(CreatePost::class);
|
->assertSeeLivewire(CreatePost::class);
|
||||||
</code-snippet>
|
</code-snippet>
|
||||||
|
|
||||||
|
=== volt/core rules ===
|
||||||
|
|
||||||
|
## Livewire Volt
|
||||||
|
|
||||||
|
- This project uses Livewire Volt for interactivity within its pages. New pages requiring interactivity must also use Livewire Volt.
|
||||||
|
- Make new Volt components using `vendor/bin/sail artisan make:volt [name] [--test] [--pest]`.
|
||||||
|
- Volt is a class-based and functional API for Livewire that supports single-file components, allowing a component's PHP logic and Blade templates to coexist in the same file.
|
||||||
|
- Livewire Volt allows PHP logic and Blade templates in one file. Components use the `@volt` directive.
|
||||||
|
- You must check existing Volt components to determine if they're functional or class-based. If you can't detect that, ask the user which they prefer before writing a Volt component.
|
||||||
|
|
||||||
|
### Volt Functional Component Example
|
||||||
|
|
||||||
|
<code-snippet name="Volt Functional Component Example" lang="php">
|
||||||
|
@volt
|
||||||
|
<?php
|
||||||
|
use function Livewire\Volt\{state, computed};
|
||||||
|
|
||||||
|
state(['count' => 0]);
|
||||||
|
|
||||||
|
$increment = fn () => $this->count++;
|
||||||
|
$decrement = fn () => $this->count--;
|
||||||
|
|
||||||
|
$double = computed(fn () => $this->count * 2);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>Count: {{ $count }}</h1>
|
||||||
|
<h2>Double: {{ $this->double }}</h2>
|
||||||
|
<button wire:click="increment">+</button>
|
||||||
|
<button wire:click="decrement">-</button>
|
||||||
|
</div>
|
||||||
|
@endvolt
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
### Volt Class Based Component Example
|
||||||
|
To get started, define an anonymous class that extends Livewire\Volt\Component. Within the class, you may utilize all of the features of Livewire using traditional Livewire syntax:
|
||||||
|
|
||||||
|
<code-snippet name="Volt Class-based Volt Component Example" lang="php">
|
||||||
|
use Livewire\Volt\Component;
|
||||||
|
|
||||||
|
new class extends Component {
|
||||||
|
public $count = 0;
|
||||||
|
|
||||||
|
public function increment()
|
||||||
|
{
|
||||||
|
$this->count++;
|
||||||
|
}
|
||||||
|
} ?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>{{ $count }}</h1>
|
||||||
|
<button wire:click="increment">+</button>
|
||||||
|
</div>
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
### Testing Volt & Volt Components
|
||||||
|
- Use the existing directory for tests if it already exists. Otherwise, fallback to `tests/Feature/Volt`.
|
||||||
|
|
||||||
|
<code-snippet name="Livewire Test Example" lang="php">
|
||||||
|
use Livewire\Volt\Volt;
|
||||||
|
|
||||||
|
test('counter increments', function () {
|
||||||
|
Volt::test('counter')
|
||||||
|
->assertSee('Count: 0')
|
||||||
|
->call('increment')
|
||||||
|
->assertSee('Count: 1');
|
||||||
|
});
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
<code-snippet name="Volt Component Test Using Pest" lang="php">
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use App\Models\{User, Product};
|
||||||
|
use Livewire\Volt\Volt;
|
||||||
|
|
||||||
|
test('product form creates product', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
|
||||||
|
Volt::test('pages.products.create')
|
||||||
|
->actingAs($user)
|
||||||
|
->set('form.name', 'Test Product')
|
||||||
|
->set('form.description', 'Test Description')
|
||||||
|
->set('form.price', 99.99)
|
||||||
|
->call('create')
|
||||||
|
->assertHasNoErrors();
|
||||||
|
|
||||||
|
expect(Product::where('name', 'Test Product')->exists())->toBeTrue();
|
||||||
|
});
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
### Common Patterns
|
||||||
|
|
||||||
|
<code-snippet name="CRUD With Volt" lang="php">
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Product;
|
||||||
|
use function Livewire\Volt\{state, computed};
|
||||||
|
|
||||||
|
state(['editing' => null, 'search' => '']);
|
||||||
|
|
||||||
|
$products = computed(fn() => Product::when($this->search,
|
||||||
|
fn($q) => $q->where('name', 'like', "%{$this->search}%")
|
||||||
|
)->get());
|
||||||
|
|
||||||
|
$edit = fn(Product $product) => $this->editing = $product->id;
|
||||||
|
$delete = fn(Product $product) => $product->delete();
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!-- HTML / UI Here -->
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
<code-snippet name="Real-Time Search With Volt" lang="php">
|
||||||
|
<flux:input
|
||||||
|
wire:model.live.debounce.300ms="search"
|
||||||
|
placeholder="Search..."
|
||||||
|
/>
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
|
<code-snippet name="Loading States With Volt" lang="php">
|
||||||
|
<flux:button wire:click="save" wire:loading.attr="disabled">
|
||||||
|
<span wire:loading.remove>Save</span>
|
||||||
|
<span wire:loading>Saving...</span>
|
||||||
|
</flux:button>
|
||||||
|
</code-snippet>
|
||||||
|
|
||||||
=== pint/core rules ===
|
=== pint/core rules ===
|
||||||
|
|
||||||
## Laravel Pint Code Formatter
|
## Laravel Pint Code Formatter
|
||||||
|
|||||||
@@ -3,14 +3,16 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\AssociationStatus;
|
use App\Enums\AssociationStatus;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use ParagonIE\CipherSweet\BlindIndex;
|
use ParagonIE\CipherSweet\BlindIndex;
|
||||||
use ParagonIE\CipherSweet\EncryptedRow;
|
use ParagonIE\CipherSweet\EncryptedRow;
|
||||||
use Spatie\LaravelCipherSweet\Concerns\UsesCipherSweet;
|
use Spatie\LaravelCipherSweet\Concerns\UsesCipherSweet;
|
||||||
use Spatie\LaravelCipherSweet\Contracts\CipherSweetEncrypted;
|
use Spatie\LaravelCipherSweet\Contracts\CipherSweetEncrypted;
|
||||||
|
|
||||||
class EinundzwanzigPleb extends Model implements CipherSweetEncrypted
|
class EinundzwanzigPleb extends Authenticatable implements CipherSweetEncrypted
|
||||||
{
|
{
|
||||||
|
use HasFactory;
|
||||||
use UsesCipherSweet;
|
use UsesCipherSweet;
|
||||||
|
|
||||||
protected $guarded = [];
|
protected $guarded = [];
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"livewire/flux": "^2.10",
|
"livewire/flux": "^2.10",
|
||||||
"livewire/flux-pro": "^2.10",
|
"livewire/flux-pro": "^2.10",
|
||||||
"livewire/livewire": "^4.0",
|
"livewire/livewire": "^4.0",
|
||||||
|
"livewire/volt": "^1.0",
|
||||||
"openspout/openspout": "^4.24",
|
"openspout/openspout": "^4.24",
|
||||||
"power-components/livewire-powergrid": "^6.7",
|
"power-components/livewire-powergrid": "^6.7",
|
||||||
"pusher/pusher-php-server": "^7.2.2",
|
"pusher/pusher-php-server": "^7.2.2",
|
||||||
|
|||||||
73
composer.lock
generated
73
composer.lock
generated
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "39a9ce519dbfeb237966b7441b59a562",
|
"content-hash": "7a60c8e828d100018e8703dd85753739",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "akuechler/laravel-geoly",
|
"name": "akuechler/laravel-geoly",
|
||||||
@@ -3240,6 +3240,77 @@
|
|||||||
],
|
],
|
||||||
"time": "2026-01-14T18:40:41+00:00"
|
"time": "2026-01-14T18:40:41+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "livewire/volt",
|
||||||
|
"version": "v1.10.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/livewire/volt.git",
|
||||||
|
"reference": "48cff133990c6261c63ee279fc091af6f6c6654e"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/livewire/volt/zipball/48cff133990c6261c63ee279fc091af6f6c6654e",
|
||||||
|
"reference": "48cff133990c6261c63ee279fc091af6f6c6654e",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"laravel/framework": "^10.38.2|^11.0|^12.0",
|
||||||
|
"livewire/livewire": "^3.6.1|^4.0",
|
||||||
|
"php": "^8.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"laravel/folio": "^1.1",
|
||||||
|
"orchestra/testbench": "^8.36|^9.15|^10.8",
|
||||||
|
"pestphp/pest": "^2.9.5|^3.0|^4.0",
|
||||||
|
"phpstan/phpstan": "^1.10"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"providers": [
|
||||||
|
"Livewire\\Volt\\VoltServiceProvider"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"functions.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Livewire\\Volt\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Taylor Otwell",
|
||||||
|
"email": "taylor@laravel.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nuno Maduro",
|
||||||
|
"email": "nuno@laravel.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "An elegantly crafted functional API for Laravel Livewire.",
|
||||||
|
"homepage": "https://github.com/livewire/volt",
|
||||||
|
"keywords": [
|
||||||
|
"laravel",
|
||||||
|
"livewire",
|
||||||
|
"volt"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/livewire/volt/issues",
|
||||||
|
"source": "https://github.com/livewire/volt"
|
||||||
|
},
|
||||||
|
"time": "2025-11-25T16:19:15+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "maennchen/zipstream-php",
|
"name": "maennchen/zipstream-php",
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
|
|||||||
26
database/factories/EinundzwanzigPlebFactory.php
Normal file
26
database/factories/EinundzwanzigPlebFactory.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\EinundzwanzigPleb>
|
||||||
|
*/
|
||||||
|
class EinundzwanzigPlebFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'pubkey' => $this->faker->sha256(),
|
||||||
|
'npub' => $this->faker->word(),
|
||||||
|
'email' => $this->faker->safeEmail(),
|
||||||
|
'association_status' => \App\Enums\AssociationStatus::DEFAULT,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
it('returns a successful response', function () {
|
use Livewire\Livewire;
|
||||||
$response = $this->get('/');
|
|
||||||
|
|
||||||
$response->assertStatus(200);
|
it('returns a successful response', function () {
|
||||||
|
Livewire::test('association.profile')
|
||||||
|
->assertStatus(200);
|
||||||
});
|
});
|
||||||
|
|||||||
145
tests/Feature/Livewire/Association/ElectionTest.php
Normal file
145
tests/Feature/Livewire/Association/ElectionTest.php
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\EinundzwanzigPleb;
|
||||||
|
use App\Models\Election;
|
||||||
|
use App\Support\NostrAuth;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
it('loads elections on mount', function () {
|
||||||
|
$election1 = Election::factory()->create(['year' => 2024]);
|
||||||
|
$election2 = Election::factory()->create(['year' => 2025]);
|
||||||
|
|
||||||
|
Livewire::test('association.election.index')
|
||||||
|
->assertSet('elections', function ($elections) {
|
||||||
|
return count($elections) >= 2;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('denies access to unauthorized users in election index', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
$election = Election::factory()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.election.index', ['election' => $election])
|
||||||
|
->assertSet('isAllowed', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('grants access to authorized users in election index', function () {
|
||||||
|
$allowedPubkey = '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033';
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create(['pubkey' => $allowedPubkey]);
|
||||||
|
$election = Election::factory()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.election.index', ['election' => $election])
|
||||||
|
->assertSet('isAllowed', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Election Admin Tests
|
||||||
|
it('renders election admin component', function () {
|
||||||
|
$election = Election::factory()->create();
|
||||||
|
|
||||||
|
Livewire::test('association.election.admin', ['election' => $election])
|
||||||
|
->assertStatus(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('denies access to unauthorized users in election admin', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
$election = Election::factory()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.election.admin', ['election' => $election])
|
||||||
|
->assertSet('isAllowed', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('grants access to authorized users in election admin', function () {
|
||||||
|
$allowedPubkey = '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033';
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create(['pubkey' => $allowedPubkey]);
|
||||||
|
$election = Election::factory()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.election.admin', ['election' => $election])
|
||||||
|
->assertSet('isAllowed', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can save election candidates', function () {
|
||||||
|
$allowedPubkey = '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033';
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create(['pubkey' => $allowedPubkey]);
|
||||||
|
$election = Election::factory()->create([
|
||||||
|
'candidates' => json_encode([['type' => 'presidency', 'c' => []]]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
$newCandidates = json_encode([['type' => 'presidency', 'c' => ['test-pubkey']]]);
|
||||||
|
|
||||||
|
Livewire::test('association.election.admin', ['election' => $election])
|
||||||
|
->set('elections.0.candidates', $newCandidates)
|
||||||
|
->call('saveElection', 0);
|
||||||
|
|
||||||
|
expect($election->fresh()->candidates)->toBe($newCandidates);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Election Show Tests
|
||||||
|
it('renders election show component', function () {
|
||||||
|
$election = Election::factory()->create();
|
||||||
|
|
||||||
|
Livewire::test('association.election.show', ['election' => $election])
|
||||||
|
->assertStatus(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('loads election data on mount in show', function () {
|
||||||
|
$election = Election::factory()->create();
|
||||||
|
|
||||||
|
Livewire::test('association.election.show', ['election' => $election])
|
||||||
|
->assertSet('election.id', $election->id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles search in election show', function () {
|
||||||
|
$election = Election::factory()->create();
|
||||||
|
$pleb1 = EinundzwanzigPleb::factory()->active()->create();
|
||||||
|
$pleb2 = EinundzwanzigPleb::factory()->boardMember()->create();
|
||||||
|
|
||||||
|
Livewire::test('association.election.show', ['election' => $election])
|
||||||
|
->set('search', $pleb1->pubkey)
|
||||||
|
->assertSet('plebs', function ($plebs) use ($pleb1) {
|
||||||
|
return collect($plebs)->contains('pubkey', $pleb1->pubkey);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can create vote event', function () {
|
||||||
|
$election = Election::factory()->create();
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->active()->create();
|
||||||
|
$candidatePubkey = 'test-candidate-pubkey';
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.election.show', ['election' => $election])
|
||||||
|
->call('vote', $candidatePubkey, 'presidency', false)
|
||||||
|
->assertSet('signThisEvent', function ($event) use ($candidatePubkey) {
|
||||||
|
return str_contains($event, $candidatePubkey);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('checks election closure status', function () {
|
||||||
|
$election = Election::factory()->create([
|
||||||
|
'end_time' => now()->subDay(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Livewire::test('association.election.show', ['election' => $election])
|
||||||
|
->call('checkElection')
|
||||||
|
->assertSet('isNotClosed', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays log for authorized users', function () {
|
||||||
|
$allowedPubkey = '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033';
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create(['pubkey' => $allowedPubkey]);
|
||||||
|
$election = Election::factory()->create();
|
||||||
|
|
||||||
|
Livewire::test('association.election.show', ['election' => $election])
|
||||||
|
->call('handleNostrLoggedIn', $allowedPubkey)
|
||||||
|
->assertSet('showLog', true);
|
||||||
|
});
|
||||||
73
tests/Feature/Livewire/Association/Members/AdminTest.php
Normal file
73
tests/Feature/Livewire/Association/Members/AdminTest.php
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\EinundzwanzigPleb;
|
||||||
|
use App\Support\NostrAuth;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
it('denies access to unauthorized users', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.members.admin')
|
||||||
|
->assertSet('isAllowed', false)
|
||||||
|
->assertSee('Du bist nicht berechtigt, Mitglieder zu bearbeiten.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('grants access to authorized pubkeys', function () {
|
||||||
|
$allowedPubkeys = [
|
||||||
|
'0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033',
|
||||||
|
'430169631f2f0682c60cebb4f902d68f0c71c498fd1711fd982f052cf1fd4279',
|
||||||
|
'7acf30cf60b85c62b8f654556cc21e4016df8f5604b3b6892794f88bb80d7a1d',
|
||||||
|
'f240be2b684f85cc81566f2081386af81d7427ea86250c8bde6b7a8500c761ba',
|
||||||
|
'19e358b8011f5f4fc653c565c6d4c2f33f32661f4f90982c9eedc292a8774ec3',
|
||||||
|
'acbcec475a1a4f9481939ecfbd1c3d111f5b5a474a39ae039bbc720fdd305bec',
|
||||||
|
];
|
||||||
|
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create([
|
||||||
|
'pubkey' => $allowedPubkeys[0],
|
||||||
|
]);
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.members.admin')
|
||||||
|
->assertSet('isAllowed', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles nostr login for authorized user', function () {
|
||||||
|
$allowedPubkey = '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033';
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create([
|
||||||
|
'pubkey' => $allowedPubkey,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Livewire::test('association.members.admin')
|
||||||
|
->call('handleNostrLoggedIn', $allowedPubkey)
|
||||||
|
->assertSet('isAllowed', true)
|
||||||
|
->assertSet('currentPubkey', $allowedPubkey);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles nostr logout', function () {
|
||||||
|
$allowedPubkey = '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033';
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create([
|
||||||
|
'pubkey' => $allowedPubkey,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Livewire::test('association.members.admin')
|
||||||
|
->call('handleNostrLoggedIn', $allowedPubkey)
|
||||||
|
->call('handleNostrLoggedOut')
|
||||||
|
->assertSet('isAllowed', false)
|
||||||
|
->assertSet('currentPubkey', null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays einundzwanzig pleb table when authorized', function () {
|
||||||
|
$allowedPubkey = '0adf67475ccc5ca456fd3022e46f5d526eb0af6284bf85494c0dd7847f3e5033';
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create([
|
||||||
|
'pubkey' => $allowedPubkey,
|
||||||
|
]);
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.members.admin')
|
||||||
|
->assertSet('isAllowed', true)
|
||||||
|
->assertSee('einundzwanzig-pleb-table');
|
||||||
|
});
|
||||||
110
tests/Feature/Livewire/Association/NewsTest.php
Normal file
110
tests/Feature/Livewire/Association/NewsTest.php
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Enums\AssociationStatus;
|
||||||
|
use App\Enums\NewsCategory;
|
||||||
|
use App\Models\EinundzwanzigPleb;
|
||||||
|
use App\Models\Notification;
|
||||||
|
use App\Support\NostrAuth;
|
||||||
|
use Illuminate\Http\UploadedFile;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
Storage::fake('public');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('denies access when pleb has insufficient association status', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create([
|
||||||
|
'association_status' => AssociationStatus::PASSIVE,
|
||||||
|
]);
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.news')
|
||||||
|
->assertSet('isAllowed', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('denies access when pleb has not paid for current year', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create([
|
||||||
|
'association_status' => AssociationStatus::ACTIVE,
|
||||||
|
]);
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.news')
|
||||||
|
->assertSet('isAllowed', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('grants access when pleb is active and has paid', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->active()->withPaidCurrentYear()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.news')
|
||||||
|
->assertSet('isAllowed', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows board member to edit news', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->boardMember()->withPaidCurrentYear()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.news')
|
||||||
|
->assertSet('canEdit', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can create news entry with pdf', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->boardMember()->withPaidCurrentYear()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
$file = UploadedFile::fake()->create('document.pdf', 100);
|
||||||
|
|
||||||
|
Livewire::test('association.news')
|
||||||
|
->set('file', $file)
|
||||||
|
->set('form.category', NewsCategory::ORGANISATION->value)
|
||||||
|
->set('form.name', 'Test News')
|
||||||
|
->set('form.description', 'Test Description')
|
||||||
|
->call('save')
|
||||||
|
->assertHasNoErrors();
|
||||||
|
|
||||||
|
expect(Notification::where('name', 'Test News')->exists())->toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('validates news entry creation', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->boardMember()->withPaidCurrentYear()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.news')
|
||||||
|
->call('save')
|
||||||
|
->assertHasErrors(['file', 'form.category', 'form.name']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can delete news entry', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->boardMember()->withPaidCurrentYear()->create();
|
||||||
|
$news = Notification::factory()->create([
|
||||||
|
'einundzwanzig_pleb_id' => $pleb->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.news')
|
||||||
|
->call('delete', $news->id)
|
||||||
|
->assertHasNoErrors();
|
||||||
|
|
||||||
|
expect(Notification::find($news->id))->toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays news list', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->active()->withPaidCurrentYear()->create();
|
||||||
|
$news1 = Notification::factory()->create();
|
||||||
|
$news2 = Notification::factory()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.news')
|
||||||
|
->assertSet('isAllowed', true)
|
||||||
|
->assertSee($news1->name)
|
||||||
|
->assertSee($news2->name);
|
||||||
|
});
|
||||||
116
tests/Feature/Livewire/Association/ProfileTest.php
Normal file
116
tests/Feature/Livewire/Association/ProfileTest.php
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Enums\AssociationStatus;
|
||||||
|
use App\Models\EinundzwanzigPleb;
|
||||||
|
use App\Support\NostrAuth;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
it('handles nostr login correctly', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
|
||||||
|
Livewire::test('association.profile')
|
||||||
|
->call('handleNostrLoggedIn', $pleb->pubkey)
|
||||||
|
->assertSet('currentPubkey', $pleb->pubkey)
|
||||||
|
->assertSet('currentPleb.pubkey', $pleb->pubkey);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles nostr logout correctly', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
|
||||||
|
Livewire::test('association.profile')
|
||||||
|
->call('handleNostrLoggedIn', $pleb->pubkey)
|
||||||
|
->call('handleNostrLoggedOut')
|
||||||
|
->assertSet('currentPubkey', null)
|
||||||
|
->assertSet('currentPleb', null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can save email address', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.profile')
|
||||||
|
->set('email', 'test@example.com')
|
||||||
|
->call('saveEmail')
|
||||||
|
->assertHasNoErrors();
|
||||||
|
|
||||||
|
expect($pleb->fresh()->email)->toBe('test@example.com');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('validates email format', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.profile')
|
||||||
|
->set('email', 'invalid-email')
|
||||||
|
->call('saveEmail')
|
||||||
|
->assertHasErrors(['email']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can update no email preference', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.profile')
|
||||||
|
->set('no', true)
|
||||||
|
->assertSet('showEmail', false);
|
||||||
|
|
||||||
|
expect($pleb->fresh()->no_email)->toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can save membership application', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create([
|
||||||
|
'association_status' => AssociationStatus::DEFAULT,
|
||||||
|
]);
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.profile')
|
||||||
|
->set('form.check', true)
|
||||||
|
->call('save', AssociationStatus::PASSIVE->value)
|
||||||
|
->assertHasNoErrors();
|
||||||
|
|
||||||
|
expect($pleb->fresh()->association_status)->toBe(AssociationStatus::PASSIVE);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates payment event when pleb becomes active', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->active()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.profile')
|
||||||
|
->assertSet('amountToPay', config('app.env') === 'production' ? 21000 : 1);
|
||||||
|
|
||||||
|
expect($pleb->paymentEvents()->count())->toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays paid status for current year', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->active()->withPaidCurrentYear()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.profile')
|
||||||
|
->call('listenForPayment')
|
||||||
|
->assertSet('currentYearIsPaid', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can initiate payment', function () {
|
||||||
|
Http::fake([
|
||||||
|
'pay.einundzwanzig.space/*' => Http::response([
|
||||||
|
'id' => 'invoice123',
|
||||||
|
'checkoutLink' => 'https://pay.einundzwanzig.space/checkout/invoice123',
|
||||||
|
], 200),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->active()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
$response = Livewire::test('association.profile')
|
||||||
|
->call('pay', 'test-comment');
|
||||||
|
|
||||||
|
$response->assertRedirect();
|
||||||
|
});
|
||||||
228
tests/Feature/Livewire/Association/ProjectSupportTest.php
Normal file
228
tests/Feature/Livewire/Association/ProjectSupportTest.php
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\EinundzwanzigPleb;
|
||||||
|
use App\Models\ProjectProposal;
|
||||||
|
use App\Support\NostrAuth;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
it('loads projects on mount', function () {
|
||||||
|
$project1 = ProjectProposal::factory()->create();
|
||||||
|
$project2 = ProjectProposal::factory()->create();
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.index')
|
||||||
|
->assertSet('projects', function ($projects) {
|
||||||
|
return $projects->count() >= 2;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can search projects', function () {
|
||||||
|
$project = ProjectProposal::factory()->create(['name' => 'Unique Project Name']);
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.index')
|
||||||
|
->set('search', 'Unique')
|
||||||
|
->assertSet('projects', function ($projects) use ($project) {
|
||||||
|
return $projects->contains('id', $project->id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can filter projects', function () {
|
||||||
|
Livewire::test('association.project-support.index')
|
||||||
|
->call('setFilter', 'new')
|
||||||
|
->assertSet('activeFilter', 'new');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can confirm delete', function () {
|
||||||
|
$project = ProjectProposal::factory()->create();
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.index')
|
||||||
|
->call('confirmDelete', $project->id)
|
||||||
|
->assertSet('confirmDeleteId', $project->id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can delete project', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->boardMember()->create();
|
||||||
|
$project = ProjectProposal::factory()->create([
|
||||||
|
'einundzwanzig_pleb_id' => $pleb->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.index')
|
||||||
|
->set('confirmDeleteId', $project->id)
|
||||||
|
->call('delete');
|
||||||
|
|
||||||
|
expect(ProjectProposal::find($project->id))->toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles nostr login', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.index')
|
||||||
|
->call('handleNostrLoggedIn', $pleb->pubkey)
|
||||||
|
->assertSet('currentPubkey', $pleb->pubkey)
|
||||||
|
->assertSet('isAllowed', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles nostr logout', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.index')
|
||||||
|
->call('handleNostrLoggedIn', $pleb->pubkey)
|
||||||
|
->call('handleNostrLoggedOut')
|
||||||
|
->assertSet('currentPubkey', null)
|
||||||
|
->assertSet('isAllowed', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('denies access to create when not authenticated', function () {
|
||||||
|
Livewire::test('association.project-support.form.create')
|
||||||
|
->assertSet('isAllowed', false)
|
||||||
|
->assertSee('Du bist nicht berechtigt, eine Projektförderung anzulegen.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('denies access to create when pleb has not paid', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->active()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.form.create')
|
||||||
|
->assertSet('isAllowed', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('grants access to create when pleb is active and paid', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->active()->withPaidCurrentYear()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.form.create')
|
||||||
|
->assertSet('isAllowed', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can create project proposal', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->active()->withPaidCurrentYear()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.form.create')
|
||||||
|
->set('form.name', 'Test Project')
|
||||||
|
->set('form.description', 'Test Description')
|
||||||
|
->call('save')
|
||||||
|
->assertHasNoErrors();
|
||||||
|
|
||||||
|
expect(ProjectProposal::where('name', 'Test Project')->exists())->toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('validates project proposal creation', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->active()->withPaidCurrentYear()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.form.create')
|
||||||
|
->call('save')
|
||||||
|
->assertHasErrors(['form.name', 'form.description']);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Project Support Edit Tests
|
||||||
|
it('renders project support edit component', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
$project = ProjectProposal::factory()->create([
|
||||||
|
'einundzwanzig_pleb_id' => $pleb->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.form.edit', ['project' => $project])
|
||||||
|
->assertStatus(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('denies access to edit when not owner', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
$project = ProjectProposal::factory()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.form.edit', ['project' => $project])
|
||||||
|
->assertSet('isAllowed', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('grants access to edit when owner', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
$project = ProjectProposal::factory()->create([
|
||||||
|
'einundzwanzig_pleb_id' => $pleb->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.form.edit', ['project' => $project])
|
||||||
|
->assertSet('isAllowed', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can update project proposal', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
$project = ProjectProposal::factory()->create([
|
||||||
|
'einundzwanzig_pleb_id' => $pleb->id,
|
||||||
|
'name' => 'Old Name',
|
||||||
|
]);
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.form.edit', ['project' => $project])
|
||||||
|
->set('form.name', 'New Name')
|
||||||
|
->set('form.description', 'Updated Description')
|
||||||
|
->call('update')
|
||||||
|
->assertHasNoErrors();
|
||||||
|
|
||||||
|
expect($project->fresh()->name)->toBe('New Name');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('validates project proposal update', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
$project = ProjectProposal::factory()->create([
|
||||||
|
'einundzwanzig_pleb_id' => $pleb->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.form.edit', ['project' => $project])
|
||||||
|
->set('form.name', '')
|
||||||
|
->call('update')
|
||||||
|
->assertHasErrors(['form.name']);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Project Support Show Tests
|
||||||
|
it('renders project support show component', function () {
|
||||||
|
$project = ProjectProposal::factory()->create();
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.show', ['project' => $project])
|
||||||
|
->assertStatus(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('denies access to show when not authenticated', function () {
|
||||||
|
$project = ProjectProposal::factory()->create();
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.show', ['project' => $project])
|
||||||
|
->assertSet('isAllowed', false)
|
||||||
|
->assertSee('Du bist nicht berechtigt, die Projektförderung einzusehen.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('grants access to show when authenticated', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
$project = ProjectProposal::factory()->create();
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.show', ['project' => $project])
|
||||||
|
->assertSet('isAllowed', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays project details', function () {
|
||||||
|
$pleb = EinundzwanzigPleb::factory()->create();
|
||||||
|
$project = ProjectProposal::factory()->create([
|
||||||
|
'name' => 'Test Project Name',
|
||||||
|
'description' => 'Test Project Description',
|
||||||
|
]);
|
||||||
|
|
||||||
|
NostrAuth::login($pleb->pubkey);
|
||||||
|
|
||||||
|
Livewire::test('association.project-support.show', ['project' => $project])
|
||||||
|
->assertSet('project.name', 'Test Project Name')
|
||||||
|
->assertSee('Test Project Name')
|
||||||
|
->assertSee('Test Project Description');
|
||||||
|
});
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
uses(
|
uses(
|
||||||
Tests\TestCase::class,
|
Tests\TestCase::class,
|
||||||
// Illuminate\Foundation\Testing\RefreshDatabase::class,
|
Illuminate\Foundation\Testing\RefreshDatabase::class,
|
||||||
)->in('Feature');
|
)->in('Feature');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user