--wip-- [skip ci]
This commit is contained in:
parent
da3197395f
commit
a74d0936a2
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace App\Maildispatcher\Actions;
|
||||
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class IndexAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public function handle()
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Maildispatcher\Actions;
|
||||
|
||||
use App\Maildispatcher\Data\MailEntry;
|
||||
use App\Maildispatcher\Models\Maildispatcher;
|
||||
use App\Member\FilterScope;
|
||||
use App\Member\Member;
|
||||
use Illuminate\Support\Collection;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class ResyncAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public function handle()
|
||||
{
|
||||
foreach (Maildispatcher::get() as $dispatcher) {
|
||||
$dispatcher->gateway->type->sync($dispatcher->name, $dispatcher->gateway->domain, $this->getResults($dispatcher));
|
||||
}
|
||||
}
|
||||
|
||||
public function getResults(Maildispatcher $dispatcher): Collection
|
||||
{
|
||||
return Member::search(data_get($dispatcher->filter, 'search', ''))->query(
|
||||
fn ($q) => $q->select('*')->withFilter(FilterScope::fromPost($dispatcher->filter))
|
||||
)->get()->filter(fn ($member) => $member->email || $member->email_parents)->map(fn ($member) => MailEntry::from(['email' => $member->email ?: $member->email_parents]));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace App\Maildispatcher\Actions;
|
||||
|
||||
use App\Maildispatcher\Models\Maildispatcher;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Lorisleiva\Actions\ActionRequest;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class StoreAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $input
|
||||
*/
|
||||
public function handle(array $input): void
|
||||
{
|
||||
Maildispatcher::create([
|
||||
...$input,
|
||||
'filter' => (object) $input['filter'],
|
||||
]);
|
||||
ResyncAction::dispatch();
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'gateway_id' => 'required|exists:mailgateways,id',
|
||||
'name' => 'required|max:50',
|
||||
'filter' => 'present|array',
|
||||
];
|
||||
}
|
||||
|
||||
public function asController(ActionRequest $request): JsonResponse
|
||||
{
|
||||
$this->handle($request->validated());
|
||||
|
||||
return response()->json('', 201);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace App\Maildispatcher\Data;
|
||||
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
class MailEntry extends Data
|
||||
{
|
||||
public function __construct(public string $email)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace App\Maildispatcher\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Localmaildispatcher extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasUuids;
|
||||
|
||||
public $guarded = [];
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
public function dispatcher(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Maildispatcher::class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Maildispatcher\Models;
|
||||
|
||||
use App\Mailgateway\Models\Mailgateway;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Maildispatcher extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasUuids;
|
||||
|
||||
public $guarded = [];
|
||||
public $timestamps = false;
|
||||
|
||||
public $casts = [
|
||||
'filter' => 'json',
|
||||
];
|
||||
|
||||
public function gateway(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Mailgateway::class);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
namespace App\Mailgateway\Types;
|
||||
|
||||
use App\Maildispatcher\Data\MailEntry;
|
||||
use App\Maildispatcher\Models\Localmaildispatcher;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class LocalType extends Type
|
||||
{
|
||||
public static function name(): string
|
||||
|
@ -23,4 +27,34 @@ class LocalType extends Type
|
|||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function list(string $name, string $domain): Collection
|
||||
{
|
||||
return Localmaildispatcher::where('from', "{$name}@{$domain}")->get()->map(fn ($mail) => MailEntry::from(['email' => $mail->to]));
|
||||
}
|
||||
|
||||
public function search(string $name, string $domain, string $email): ?MailEntry
|
||||
{
|
||||
$result = Localmaildispatcher::where('from', "{$name}@{$domain}")->where('to', $email)->first();
|
||||
|
||||
return $result ? MailEntry::from([
|
||||
'email' => $result->to,
|
||||
]) : null;
|
||||
}
|
||||
|
||||
public function add(string $name, string $domain, string $email): void
|
||||
{
|
||||
Localmaildispatcher::create([
|
||||
'from' => "{$name}@{$domain}",
|
||||
'to' => $email,
|
||||
]);
|
||||
}
|
||||
|
||||
public function remove(string $name, string $domain, string $email): void
|
||||
{
|
||||
Localmaildispatcher::where('from', "{$name}@{$domain}")->where('to', $email)->delete();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace App\Mailgateway\Types;
|
||||
|
||||
use App\Maildispatcher\Data\MailEntry;
|
||||
use App\Mailman\Support\MailmanService;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class MailmanType extends Type
|
||||
{
|
||||
|
@ -61,4 +63,26 @@ class MailmanType extends Type
|
|||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function search(string $name, string $domain, string $email): ?MailEntry
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function add(string $name, string $domain, string $email): void
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function list(string $name, string $domain): Collection
|
||||
{
|
||||
return collect([]);
|
||||
}
|
||||
|
||||
public function remove(string $name, string $domain, string $email): void
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace App\Mailgateway\Types;
|
||||
|
||||
use App\Maildispatcher\Data\MailEntry;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
abstract class Type
|
||||
{
|
||||
abstract public static function name(): string;
|
||||
|
@ -13,6 +16,17 @@ abstract class Type
|
|||
|
||||
abstract public function works(): bool;
|
||||
|
||||
abstract public function search(string $name, string $domain, string $email): ?MailEntry;
|
||||
|
||||
abstract public function add(string $name, string $domain, string $email): void;
|
||||
|
||||
abstract public function remove(string $name, string $domain, string $email): void;
|
||||
|
||||
/**
|
||||
* @return Collection<int, MailEntry>
|
||||
*/
|
||||
abstract public function list(string $name, string $domain): Collection;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $params
|
||||
*/
|
||||
|
@ -48,6 +62,24 @@ abstract class Type
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<int, MailEntry> $results
|
||||
*/
|
||||
public function sync(string $name, string $domain, Collection $results): void
|
||||
{
|
||||
foreach ($results as $result) {
|
||||
if ($this->search($name, $domain, $result->email)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->add($name, $domain, $result->email);
|
||||
}
|
||||
|
||||
$this->list($name, $domain)
|
||||
->filter(fn ($listEntry) => null === $results->first(fn ($r) => $r->email === $listEntry->email))
|
||||
->each(fn ($listEntry) => $this->remove($name, $domain, $listEntry->email));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace App\Member;
|
|||
|
||||
use App\Country;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Maildispatcher\Actions\ResyncAction;
|
||||
use App\Setting\GeneralSettings;
|
||||
use App\Setting\NamiSettings;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
|
@ -86,6 +87,7 @@ class MemberController extends Controller
|
|||
}
|
||||
|
||||
$member->delete();
|
||||
ResyncAction::dispatch();
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Member;
|
|||
use App\Activity;
|
||||
use App\Group;
|
||||
use App\Invoice\BillKind;
|
||||
use App\Maildispatcher\Actions\ResyncAction;
|
||||
use App\Member\Actions\NamiPutMemberAction;
|
||||
use App\Setting\NamiSettings;
|
||||
use App\Subactivity;
|
||||
|
@ -99,6 +100,7 @@ class MemberRequest extends FormRequest
|
|||
Subactivity::find($this->input('first_subactivity_id')),
|
||||
);
|
||||
}
|
||||
ResyncAction::dispatch();
|
||||
}
|
||||
|
||||
public function persistUpdate(Member $member): void
|
||||
|
@ -118,5 +120,6 @@ class MemberRequest extends FormRequest
|
|||
if (!$this->input('has_nami') && null !== $member->nami_id) {
|
||||
DeleteJob::dispatch($member->nami_id);
|
||||
}
|
||||
ResyncAction::dispatch();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories\Maildispatcher\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Maildispatcher\Models\Maildispatcher>
|
||||
*/
|
||||
class MaildispatcherFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class() extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('maildispatchers', function (Blueprint $table) {
|
||||
$table->uuid('id');
|
||||
$table->string('name');
|
||||
$table->uuid('gateway_id');
|
||||
$table->json('filter');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('maildispatchers');
|
||||
}
|
||||
};
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class() extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('localmaildispatchers', function (Blueprint $table) {
|
||||
$table->uuid('id');
|
||||
$table->string('from');
|
||||
$table->string('to');
|
||||
$table->unique(['from', 'to']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('localmaildispatchers');
|
||||
}
|
||||
};
|
|
@ -20,6 +20,7 @@ use App\Initialize\Actions\InitializeFormAction;
|
|||
use App\Initialize\Actions\NamiGetSearchLayerAction;
|
||||
use App\Initialize\Actions\NamiLoginCheckAction;
|
||||
use App\Initialize\Actions\NamiSearchAction;
|
||||
use App\Maildispatcher\Actions\StoreAction as MaildispatcherStoreAction;
|
||||
use App\Mailgateway\Actions\StoreAction;
|
||||
use App\Mailgateway\Actions\UpdateAction;
|
||||
use App\Member\Actions\ExportAction;
|
||||
|
@ -81,7 +82,8 @@ Route::group(['middleware' => 'auth:web'], function (): void {
|
|||
Route::get('/contribution-generate', ContributionGenerateAction::class)->name('contribution.generate');
|
||||
Route::post('/contribution-validate', ContributionValidateAction::class)->name('contribution.validate');
|
||||
|
||||
// -------------------------------- Mailgateway --------------------------------
|
||||
// ----------------------------------- mail ------------------------------------
|
||||
Route::post('/api/mailgateway', StoreAction::class)->name('mailgateway.store');
|
||||
Route::patch('/api/mailgateway/{mailgateway}', UpdateAction::class)->name('mailgateway.update');
|
||||
Route::post('/api/maildispatcher', MaildispatcherStoreAction::class)->name('maildispatcher.index');
|
||||
});
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Maildispatcher;
|
||||
|
||||
use App\Activity;
|
||||
use App\Maildispatcher\Models\Maildispatcher;
|
||||
use App\Mailgateway\Models\Mailgateway;
|
||||
use App\Mailgateway\Types\LocalType;
|
||||
use App\Member\Member;
|
||||
use App\Member\Membership;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\TestCase;
|
||||
|
||||
class StoreTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->login()->loginNami();
|
||||
}
|
||||
|
||||
public function testItCanStoreAMail(): void
|
||||
{
|
||||
$gateway = Mailgateway::factory()->type(LocalType::class, [])->domain('example.com')->create();
|
||||
Member::factory()->defaults()->create();
|
||||
Member::factory()->defaults()->has(Membership::factory()->inLocal('Leiter*in', 'Wölfling'))->create(['email' => 'jane@example.com']);
|
||||
$activityId = Activity::first()->id;
|
||||
|
||||
$response = $this->postJson('/api/maildispatcher', [
|
||||
'name' => 'test',
|
||||
'gateway_id' => $gateway->id,
|
||||
'filter' => ['activity_id' => $activityId],
|
||||
]);
|
||||
|
||||
$response->assertStatus(201);
|
||||
$this->assertDatabaseHas('maildispatchers', [
|
||||
'name' => 'test',
|
||||
'gateway_id' => $gateway->id,
|
||||
'filter' => "{\"activity_id\":{$activityId}}",
|
||||
]);
|
||||
$dispatcher = Maildispatcher::first();
|
||||
$this->assertDatabaseCount('localmaildispatchers', 1);
|
||||
$this->assertDatabaseHas('localmaildispatchers', [
|
||||
'from' => 'test@example.com',
|
||||
'to' => 'jane@example.com',
|
||||
]);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue