--wip-- [skip ci]
This commit is contained in:
parent
310f3c9727
commit
3e92a7c40a
|
@ -30,17 +30,4 @@ class FormSettings extends LocalSettings implements Storeable
|
|||
'clearCacheUrl' => 'present|string',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function viewData(): array
|
||||
{
|
||||
return [
|
||||
'data' => [
|
||||
'registerUrl' => $this->registerUrl,
|
||||
'clearCacheUrl' => $this->clearCacheUrl,
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use App\Lib\HasMeta;
|
||||
use App\User;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Storage;
|
||||
|
@ -11,6 +12,8 @@ use Storage;
|
|||
*/
|
||||
class UserResource extends JsonResource
|
||||
{
|
||||
use HasMeta;
|
||||
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
|
@ -25,9 +28,17 @@ class UserResource extends JsonResource
|
|||
'lastname' => $this->lastname,
|
||||
'avatar_url' => $this->getGravatarUrl(),
|
||||
'email' => $this->email,
|
||||
'id' => $this->id,
|
||||
'avatar' => [
|
||||
'src' => Storage::url('avatar.png'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public static function meta(): array
|
||||
{
|
||||
return [
|
||||
'links' => []
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ namespace App\Invoice;
|
|||
|
||||
use App\Setting\Contracts\Storeable;
|
||||
use App\Setting\LocalSettings;
|
||||
use Lorisleiva\Actions\ActionRequest;
|
||||
|
||||
class InvoiceSettings extends LocalSettings implements Storeable
|
||||
{
|
||||
|
@ -35,28 +34,6 @@ class InvoiceSettings extends LocalSettings implements Storeable
|
|||
return 'bill';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function viewData(): array
|
||||
{
|
||||
return [
|
||||
'data' => [
|
||||
'from_long' => $this->from_long,
|
||||
'from' => $this->from,
|
||||
'mobile' => $this->mobile,
|
||||
'email' => $this->email,
|
||||
'website' => $this->website,
|
||||
'address' => $this->address,
|
||||
'place' => $this->place,
|
||||
'zip' => $this->zip,
|
||||
'iban' => $this->iban,
|
||||
'bic' => $this->bic,
|
||||
'rememberWeeks' => $this->rememberWeeks,
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
|
|
@ -21,10 +21,16 @@ class MailgatewaySettings extends LocalSettings
|
|||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function viewData(): array
|
||||
public function meta(): array
|
||||
{
|
||||
return [
|
||||
'data' => MailgatewayResource::collection(Mailgateway::paginate(10)),
|
||||
];
|
||||
return MailgatewayResource::meta();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function data()
|
||||
{
|
||||
return MailgatewayResource::collection(Mailgateway::paginate(10));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,13 +41,11 @@ class ModuleSettings extends LocalSettings implements Storeable
|
|||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function viewData(): array
|
||||
public function meta(): array
|
||||
{
|
||||
return [
|
||||
'data' => [
|
||||
'modules' => $this->modules,
|
||||
],
|
||||
'meta' => ['modules' => Module::forSelect()],
|
||||
...parent::meta(),
|
||||
'modules' => Module::forSelect()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,16 +38,4 @@ class PreventionSettings extends LocalSettings implements Storeable
|
|||
'formmail' => EditorData::from($request->formmail),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function viewData(): array
|
||||
{
|
||||
return [
|
||||
'data' => [
|
||||
'formmail' => $this->formmail,
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ class ViewAction
|
|||
session()->put('title', $settingGroup::title());
|
||||
|
||||
return Inertia::render('setting/' . ucfirst($settingGroup::group()), [
|
||||
...$settingGroup->viewData(),
|
||||
'data' => $settingGroup->data(),
|
||||
'settingMenu' => app(SettingFactory::class)->getShare(),
|
||||
'storeUrl' => $settingGroup->storeUrl(),
|
||||
'meta' => $settingGroup->meta(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,22 @@ abstract class LocalSettings extends Settings
|
|||
return $this->url();
|
||||
}
|
||||
|
||||
public function meta(): array
|
||||
{
|
||||
return [
|
||||
'links' => [
|
||||
'store' => $this->storeUrl(),
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function viewData(): array;
|
||||
public function data()
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
public function beforeSave(ActionRequest $request): void
|
||||
{
|
||||
|
|
|
@ -4,7 +4,6 @@ namespace App\Setting;
|
|||
|
||||
use App\Group;
|
||||
use App\Initialize\Actions\NamiLoginCheckAction;
|
||||
use App\Nami\Actions\SettingSaveAction;
|
||||
use App\Setting\Contracts\Storeable;
|
||||
use Lorisleiva\Actions\ActionRequest;
|
||||
use Zoomyboy\LaravelNami\Api;
|
||||
|
@ -64,14 +63,12 @@ class NamiSettings extends LocalSettings implements Storeable
|
|||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function viewData(): array
|
||||
public function data(): array
|
||||
{
|
||||
return [
|
||||
'data' => [
|
||||
'mglnr' => $this->mglnr,
|
||||
'password' => '',
|
||||
'default_group_id' => $this->default_group_id,
|
||||
]
|
||||
'mglnr' => $this->mglnr,
|
||||
'password' => '',
|
||||
'default_group_id' => $this->default_group_id,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ use App\Module\ModuleSettings;
|
|||
use App\Prevention\PreventionSettings;
|
||||
use App\Setting\Actions\StoreAction;
|
||||
use App\Setting\Actions\ViewAction;
|
||||
use App\User\UserSettings;
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
|
@ -43,5 +44,6 @@ class SettingServiceProvider extends ServiceProvider
|
|||
app(SettingFactory::class)->register(FormSettings::class);
|
||||
app(SettingFactory::class)->register(FileshareSettings::class);
|
||||
app(SettingFactory::class)->register(PreventionSettings::class);
|
||||
app(SettingFactory::class)->register(UserSettings::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace App\User\Actions;
|
||||
|
||||
use App\Http\Resources\UserResource;
|
||||
use App\User;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class IndexAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public function handle(): AnonymousResourceCollection
|
||||
{
|
||||
return UserResource::collection(User::orderByRaw('lastname, firstname')->get());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace App\User;
|
||||
|
||||
use App\Http\Resources\UserResource;
|
||||
use App\Setting\LocalSettings;
|
||||
use App\User;
|
||||
|
||||
class UserSettings extends LocalSettings
|
||||
{
|
||||
public static function group(): string
|
||||
{
|
||||
return 'user';
|
||||
}
|
||||
|
||||
public static function title(): string
|
||||
{
|
||||
return 'Benutzer';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function meta(): array
|
||||
{
|
||||
return UserResource::meta();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function data()
|
||||
{
|
||||
return UserResource::collection(User::orderByRaw('lastname, firstname')->get())->toArray(request());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
ssh dkd 'cd $ADREMA_PATH && docker compose exec db mysqldump -q -udb -p'$ADREMA_DB_PASSWORD' db --ignore-table=db.telescope_entries --ignore-table=db.failed_jobs' > db.tmp
|
||||
sudo mysql scoutrobot < db.tmp
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/zsh
|
||||
|
||||
php artisan migrate:fresh --env=testing
|
||||
ssh dkd 'cd $ADREMA_PATH && docker compose exec db mysqldump -q -udb -p'$ADREMA_DB_PASSWORD' db --ignore-table=db.telescope_entries --ignore-table=db.failed_jobs' > dddd.sql
|
||||
sudo mysql scoutrobottest < dddd.sql
|
||||
php artisan migrate --env=testing
|
||||
|
|
@ -92,6 +92,8 @@ services:
|
|||
|
||||
socketi:
|
||||
image: quay.io/soketi/soketi:89604f268623cf799573178a7ba56b7491416bde-16-debian
|
||||
ports:
|
||||
- '6001:6001'
|
||||
environment:
|
||||
SOKETI_DEFAULT_APP_ID: adremaid
|
||||
SOKETI_DEFAULT_APP_KEY: adremakey
|
||||
|
@ -104,6 +106,8 @@ services:
|
|||
|
||||
meilisearch:
|
||||
image: getmeili/meilisearch:v1.6
|
||||
ports:
|
||||
- '7700:7700'
|
||||
volumes:
|
||||
- ./data/meilisearch:/meili_data
|
||||
env_file:
|
||||
|
|
|
@ -2,9 +2,11 @@ import {computed, ref, inject, onBeforeUnmount} from 'vue';
|
|||
import {router} from '@inertiajs/vue3';
|
||||
import useQueueEvents from './useQueueEvents.js';
|
||||
|
||||
export function useIndex(props, siteName) {
|
||||
export function useIndex(props, siteName = null) {
|
||||
const axios = inject('axios');
|
||||
const {startListener, stopListener} = useQueueEvents(siteName, () => reload(false));
|
||||
if (siteName !== null) {
|
||||
var {startListener, stopListener} = useQueueEvents(siteName, () => reload(false));
|
||||
}
|
||||
const single = ref(null);
|
||||
const rawProps = JSON.parse(JSON.stringify(props));
|
||||
const inner = {
|
||||
|
@ -86,8 +88,10 @@ export function useIndex(props, siteName) {
|
|||
reload(true);
|
||||
}
|
||||
|
||||
startListener();
|
||||
onBeforeUnmount(() => stopListener());
|
||||
if (siteName !== null) {
|
||||
startListener();
|
||||
onBeforeUnmount(() => stopListener());
|
||||
}
|
||||
|
||||
return {
|
||||
data: inner.data,
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
<template>
|
||||
<page-layout>
|
||||
<template #toolbar>
|
||||
<page-toolbar-button color="primary" icon="plus" @click.prevent="create">Neuer Benutzer</page-toolbar-button>
|
||||
</template>
|
||||
<ui-popup v-if="single !== null" :heading="single.id ? 'Benutzer bearbeiten' : 'Neuer Benutzer'" @close="cancel">
|
||||
<form @submit.prevent="submit">
|
||||
<section class="flex mt-4 space-x-2">
|
||||
<ui-button type="submit" class="btn-danger">Speichern</ui-button>
|
||||
<ui-button class="btn-primary" @click.prevent="single = null">Abbrechen</ui-button>
|
||||
</section>
|
||||
</form>
|
||||
</ui-popup>
|
||||
<setting-layout>
|
||||
<div class="w-full h-full pb-6">
|
||||
<table cellspacing="0" cellpadding="0" border="0" class="custom-table custom-table-sm hidden md:table">
|
||||
<thead>
|
||||
<th>Nachname</th>
|
||||
<th>Vorname</th>
|
||||
<th>Aktion</th>
|
||||
</thead>
|
||||
|
||||
<tr v-for="(user, index) in data" :key="index">
|
||||
<td v-text="user.lastname"></td>
|
||||
<td v-text="user.firstname"></td>
|
||||
<td>
|
||||
<a v-tooltip="`Bearbeiten`" href="#" class="inline-flex btn btn-warning btn-sm" @click.prevent="edit(user)"><ui-sprite src="pencil"></ui-sprite></a>
|
||||
<a v-tooltip="`Löschen`" href="#" class="inline-flex btn btn-danger btn-sm" @click.prevent="remove(user)"><ui-sprite src="pencil"></ui-sprite></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="px-6">
|
||||
<ui-pagination class="mt-4" :value="meta" :only="['data']"></ui-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</setting-layout>
|
||||
</page-layout>
|
||||
</template>
|
||||
|
||||
<script lang="js" setup>
|
||||
import SettingLayout from '../setting/Layout.vue';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
meta: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
import {indexProps, useIndex} from '../../composables/useInertiaApiIndex.js';
|
||||
|
||||
const {data, meta, single, create} = useIndex(props);
|
||||
</script>
|
|
@ -1,11 +1,11 @@
|
|||
import {useIndex} from '../../composables/useIndex.js';
|
||||
import {useIndex} from '../../composables/useInertiaApiIndex.js';
|
||||
import SettingLayout from './Layout.vue';
|
||||
|
||||
export function useSettings(props) {
|
||||
const {data, meta, router} = useIndex(props);
|
||||
|
||||
function submit() {
|
||||
router.post(props.storeUrl, {...data.value});
|
||||
router.post(meta.value.links.store, {...data.value});
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -22,10 +22,6 @@ const props = {
|
|||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
storeUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
settingMenu: {
|
||||
type: Object,
|
||||
required: true,
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Permission;
|
||||
|
||||
use App\User;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\TestCase;
|
||||
|
||||
class UserIndexTest extends TestCase
|
||||
{
|
||||
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function testItOpensSettingsPage(): void
|
||||
{
|
||||
$this->login()->loginNami();
|
||||
$this->get(route('setting.view', ['settingGroup' => 'user']))
|
||||
->assertOk()
|
||||
->assertComponent('setting/User');
|
||||
}
|
||||
|
||||
public function testItListsUsers(): void
|
||||
{
|
||||
$this->login()->loginNami();
|
||||
auth()->user()->update(['firstname' => 'Jane', 'lastname' => 'Doe']);
|
||||
User::factory()->create(['firstname' => 'John', 'lastname' => 'Doe']);
|
||||
$anna = User::factory()->create(['firstname' => 'Anna', 'lastname' => 'Doe']);
|
||||
$this->get(route('api.user.index'))
|
||||
->assertJsonPath('data.0.firstname', 'Anna')
|
||||
->assertJsonPath('data.0.lastname', 'Doe')
|
||||
->assertJsonPath('data.0.id', $anna->id)
|
||||
->assertJsonPath('data.1.firstname', 'Jane')
|
||||
->assertJsonPath('data.2.firstname', 'John');
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue