listen ansichten verbessert
This commit is contained in:
19
.php-cs-fixer.dist.php
Normal file
19
.php-cs-fixer.dist.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
$finder = PhpCsFixer\Finder::create()
|
||||
->in([
|
||||
__DIR__ . '/config',
|
||||
__DIR__ . '/lib',
|
||||
__DIR__ . '/pages',
|
||||
__DIR__ . '/tests',
|
||||
])
|
||||
->name('*.php');
|
||||
|
||||
return (new PhpCsFixer\Config())
|
||||
->setRiskyAllowed(false)
|
||||
->setRules([
|
||||
'@PSR12' => true,
|
||||
'ordered_imports' => ['sort_algorithm' => 'alpha'],
|
||||
'no_unused_imports' => true,
|
||||
])
|
||||
->setFinder($finder);
|
||||
@@ -68,7 +68,11 @@ docker/ # Dockerfiles, Nginx configs, PHP configs
|
||||
|
||||
1. **App** (`lib/App/`): DI container bootstrap. Registers all service/repository factories. No business logic.
|
||||
2. **Repository** (`lib/Repository/`): All SQL lives here. No HTTP, session, or rendering.
|
||||
3. **Service** (`lib/Service/`): Business rules and validation. No HTML. Uses factory pattern (`*ServicesFactory`).
|
||||
3. **Service** (`lib/Service/`): Business rules and validation. No HTML. Four internal sub-types:
|
||||
- **Service** (`*Service.php`): Business logic + orchestration. Coordinates repositories and gateways.
|
||||
- **Gateway** (`*Gateway.php`): Adapter for a single external dependency (repository, settings, HTTP API, scope). No orchestration flow.
|
||||
- **Factory** (`*Factory.php`): Only place inside `lib/Service/` that may call `new` on services/gateways/repositories. Registers via DI container.
|
||||
- **Policy** (`*Policy.php` in `lib/Service/Access/`): Authorization decisions per resource type. Returns `AuthorizationDecision`. No HTTP, no business logic.
|
||||
4. **Action** (`pages/**/*.php`): Reads input, checks permissions + tenant scope, calls services, sets view vars.
|
||||
5. **View** (`pages/**/*.phtml`): Pure rendering. **No DB calls.** HTML escaping via `e(...)`.
|
||||
6. **Template** (`templates/`): Layouts and partials.
|
||||
|
||||
14
README.md
14
README.md
@@ -193,6 +193,20 @@ docker compose exec php vendor/bin/phpunit --bootstrap vendor/autoload.php tests
|
||||
docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress
|
||||
```
|
||||
|
||||
### Coding Style (PHP CS Fixer)
|
||||
|
||||
CI-Check (ohne Dateien zu aendern):
|
||||
|
||||
```bash
|
||||
docker compose exec php composer cs:check
|
||||
```
|
||||
|
||||
Lokal automatisch formatieren:
|
||||
|
||||
```bash
|
||||
docker compose exec php composer cs:fix
|
||||
```
|
||||
|
||||
### Frontend-JS Smoke-Check (ohne Node)
|
||||
|
||||
- Browser-DevTools öffnen (Console + Preserve log)
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
"mintyphp/debugger": "*",
|
||||
"phpunit/phpunit": "*",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"icanhazstring/composer-unused": "^0.9.6"
|
||||
"icanhazstring/composer-unused": "^0.9.6",
|
||||
"friendsofphp/php-cs-fixer": "^3.66"
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
@@ -33,5 +34,9 @@
|
||||
"psr-4": {
|
||||
"MintyPHP\\": "lib/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"cs:check": "php-cs-fixer fix --config=.php-cs-fixer.dist.php --dry-run --diff --verbose",
|
||||
"cs:fix": "php-cs-fixer fix --config=.php-cs-fixer.dist.php --verbose"
|
||||
}
|
||||
}
|
||||
|
||||
1404
composer.lock
generated
1404
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
['path' => 'login', 'target' => 'auth/login', 'public' => true],
|
||||
['path' => 'register', 'target' => 'auth/register', 'public' => true],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'app_title' => 'CoreCore',
|
||||
'app_locale' => 'de',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'light' => 'Light',
|
||||
'dark' => 'Dark',
|
||||
|
||||
@@ -13,6 +13,54 @@ Verbindliche Kurzregeln für Architekturentscheidungen.
|
||||
- Autorisierung läuft zentral über Policies.
|
||||
- Externe API-Verträge sind UUID-first.
|
||||
|
||||
## Schichtenübersicht
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Browser([Browser / API-Client])
|
||||
|
||||
subgraph APP["lib/App/ — Composition Root"]
|
||||
DI["AppContainer + Registrars"]
|
||||
end
|
||||
|
||||
subgraph SVC["lib/Service/"]
|
||||
direction LR
|
||||
FAC["Factory"]
|
||||
SERVICE["Service"]
|
||||
GW["Gateway"]
|
||||
POL["Policy"]
|
||||
end
|
||||
|
||||
subgraph REPO["lib/Repository/"]
|
||||
REP["Repository"]
|
||||
end
|
||||
|
||||
subgraph pages["pages/**"]
|
||||
ACT["Action (*.php)"]
|
||||
VIEW["View (*.phtml)"]
|
||||
end
|
||||
|
||||
subgraph TPL["templates/"]
|
||||
LAY["Layouts & Partials"]
|
||||
end
|
||||
|
||||
DB[(MariaDB)]
|
||||
|
||||
DI -->|"ruft zur Laufzeit"| FAC
|
||||
FAC -->|"erzeugt"| SERVICE
|
||||
FAC -->|"erzeugt"| GW
|
||||
|
||||
Browser --> ACT
|
||||
ACT -->|"Input · AuthZ · Response"| SERVICE
|
||||
ACT --> POL
|
||||
ACT --> VIEW
|
||||
VIEW --> LAY
|
||||
SERVICE --> GW
|
||||
GW --> REP
|
||||
SERVICE --> REP
|
||||
REP --> DB
|
||||
```
|
||||
|
||||
## Request-Flow
|
||||
|
||||
1. `web/index.php` bootstrappt Routing/Konfiguration und initialisiert den `AppContainer`.
|
||||
|
||||
@@ -95,6 +95,45 @@ Hinweise:
|
||||
- `order` nur bekannte Sort-Key-Spalten
|
||||
- Bei Search-/Filter-Änderung wird auf Seite 1 zurückgesetzt.
|
||||
|
||||
### Row Interaction (Globaler Standard)
|
||||
|
||||
Listen mit `rowDblClick.getUrl(...)` nutzen standardmäßig eine zugängliche Row-Interaktion:
|
||||
|
||||
- sichtbare Action-Spalte rechts (`Open`/`Edit`)
|
||||
- Doppelklick bleibt als Fallback aktiv
|
||||
- `Enter` auf fokussierter Zeile navigiert zur selben URL
|
||||
|
||||
Optionale Konfiguration über `createServerGrid(...)`:
|
||||
|
||||
```js
|
||||
createServerGrid({
|
||||
// ...
|
||||
rowDblClick: {
|
||||
getUrl: (rowData) => new URL(`admin/users/edit/${rowData?.cells?.[1]?.data}`, appBase).toString(),
|
||||
},
|
||||
rowInteraction: {
|
||||
enabled: true,
|
||||
showActionButton: true,
|
||||
keepDblClick: true,
|
||||
enableEnterOnRow: true,
|
||||
actionColumnLabel: 'Actions',
|
||||
resolveActionLabel: (url) => (url.includes('/edit/') ? 'Edit' : 'Open'),
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Defaults:
|
||||
|
||||
- `rowInteraction.enabled`: `true`, wenn `rowDblClick.getUrl` vorhanden ist
|
||||
- `showActionButton`: `true`
|
||||
- `keepDblClick`: `true`
|
||||
- `enableEnterOnRow`: `true`
|
||||
- `actionColumnLabel`: `language.actions.column` oder `'Actions'`
|
||||
|
||||
Hinweis:
|
||||
|
||||
- Falls eine Seite `actions.enabled: true` explizit setzt, wird keine zusätzliche automatische Row-Action-Spalte injiziert.
|
||||
|
||||
### Filter UX 2.0 (Globaler Standard)
|
||||
|
||||
Für Listen gilt standardmäßig:
|
||||
@@ -275,5 +314,5 @@ Prüfen im Browser:
|
||||
|
||||
1. DevTools öffnen (Console, optional Preserve log aktivieren).
|
||||
2. Kernseiten laden (`/admin/users`, `/address-book`, Audit-Listen).
|
||||
3. Filter setzen/zurücksetzen, Doppelklick-Navigation und Bulk-Aktionen testen.
|
||||
3. Filter setzen/zurücksetzen, Row-Action-Button + Enter + Doppelklick sowie Bulk-Aktionen testen.
|
||||
4. Erwartung: keine JavaScript-Errors und keine Unhandled Promise Rejections.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# lib-Standards
|
||||
|
||||
Letzte Aktualisierung: 2026-03-03
|
||||
Letzte Aktualisierung: 2026-03-05
|
||||
|
||||
Praktische Regeln nur für `lib/**`. Ergänzt `docs/architektur.md`.
|
||||
|
||||
@@ -9,12 +9,17 @@ Praktische Regeln nur für `lib/**`. Ergänzt `docs/architektur.md`.
|
||||
- Verantwortlich für SQL, Filter, Paging und Mapping.
|
||||
- Keine HTTP-, Session-, Redirect- oder Policy-Logik.
|
||||
|
||||
## 2) Service-Regeln
|
||||
## 2) Service-Schicht im Detail
|
||||
|
||||
`lib/Service/` enthält vier klar getrennte Typen — jeder hat eine eigene Verantwortung:
|
||||
|
||||
### 2a) Service (`*Service.php`)
|
||||
|
||||
- Verantwortlich für Fachlogik und Orchestrierung.
|
||||
- Koordiniert Repositories und Gateways; enthält Business-Regeln und Validierung.
|
||||
- Keine Superglobals (`$_POST`, `$_GET`, `$_SESSION`).
|
||||
- Keine Header- oder Redirect-Ausgabe.
|
||||
- Keine direkten `DB::...`-Aufrufe im Service.
|
||||
- Keine direkten `DB::...`-Aufrufe.
|
||||
- Abhängigkeiten per Constructor Injection.
|
||||
- DB-Locks und Transaktionen über Repository-Schicht (z. B. `DatabaseSessionRepository`).
|
||||
- Audit-Hooks für fachliche Schreibaktionen laufen in Services (`SystemAuditService`), nicht in Templates.
|
||||
@@ -22,6 +27,28 @@ Praktische Regeln nur für `lib/**`. Ergänzt `docs/architektur.md`.
|
||||
- Scheduler-Run-/Job-Ereignisse werden zentral im `SchedulerRunService` in `SystemAuditService` geschrieben.
|
||||
- CLI-System-Audit für zentrale Commands wird am Entrypoint (`bin/**`) geschrieben, mit minimaler Metadata (ohne Argumentwerte).
|
||||
|
||||
### 2b) Gateway (`*Gateway.php`)
|
||||
|
||||
- Adapter-Schicht: kapselt eine einzelne externe Abhängigkeit für Services.
|
||||
- Typische Abhängigkeiten: ein Repository, Settings-Zugriff, externe HTTP-APIs, Scope-Daten.
|
||||
- Kein Fach-Orchestrierungsfluss — ein Gateway löst genau eine Infrastruktur-Frage.
|
||||
- Beispiele: `AuthPermissionGateway` (Permission-Lookup), `UserSettingsGateway` (Settings-Zugriff), `OidcHttpGateway` (externe OIDC-API).
|
||||
- Abhängigkeiten per Constructor Injection; keine direkten `new ...Repository()` außerhalb von Factories.
|
||||
|
||||
### 2c) Factory (`*Factory.php` / `*ServicesFactory.php` / `*GatewayFactory.php`)
|
||||
|
||||
- Einzige erlaubte Stelle für `new ...Service()`, `new ...Gateway()`, `new ...Repository()` innerhalb von `lib/Service/`.
|
||||
- Erzeugt konfigurierte Service-/Gateway-Gruppen für den DI-Container.
|
||||
- Keine Fachlogik; reine Kompositions-Helfer.
|
||||
- Werden im Composition Root (`lib/App/registerContainer.php`) registriert.
|
||||
|
||||
### 2d) Policy (`*Policy.php` / `*AuthorizationPolicy.php`)
|
||||
|
||||
- Liegen in `lib/Service/Access/`.
|
||||
- Treffen Authorization-Entscheidungen (Ability-Checks) für einen bestimmten Ressourcentyp.
|
||||
- Geben `AuthorizationDecision` zurück; kein HTTP-Redirect, keine Fachlogik.
|
||||
- Werden über `AccessPolicyFactory` + `AuthorizationService` aufgelöst — nie direkt in Actions instanziiert.
|
||||
|
||||
## 3) Instanziierung
|
||||
|
||||
- Composition Root ist `web/index.php` + `lib/App/registerContainer.php`
|
||||
|
||||
@@ -198,6 +198,7 @@
|
||||
"Modified by": "Bearbeitet von",
|
||||
"Modified": "Aktualisiert",
|
||||
"No users found": "Keine Benutzer gefunden",
|
||||
"Open": "Öffnen",
|
||||
"Yes": "Ja",
|
||||
"No": "Nein",
|
||||
"User created": "Benutzer erstellt",
|
||||
@@ -345,6 +346,7 @@
|
||||
"Next": "Weiter",
|
||||
"Page %d of %d": "Seite %d von %d",
|
||||
"Page %d": "Seite %d",
|
||||
"Rows per page": "Einträge pro Seite",
|
||||
"Showing": "Zeige",
|
||||
"of": "von",
|
||||
"to": "bis",
|
||||
|
||||
@@ -198,6 +198,7 @@
|
||||
"Modified by": "Modified by",
|
||||
"Modified": "Modified",
|
||||
"No users found": "No users found",
|
||||
"Open": "Open",
|
||||
"Yes": "Yes",
|
||||
"No": "No",
|
||||
"User created": "User created",
|
||||
@@ -345,6 +346,7 @@
|
||||
"Next": "Next",
|
||||
"Page %d of %d": "Page %d of %d",
|
||||
"Page %d": "Page %d",
|
||||
"Rows per page": "Rows per page",
|
||||
"Showing": "Showing",
|
||||
"of": "of",
|
||||
"to": "to",
|
||||
|
||||
@@ -11,7 +11,6 @@ use MintyPHP\Service\Access\AccessPolicyFactory;
|
||||
use MintyPHP\Service\Access\AccessRepositoryFactory;
|
||||
use MintyPHP\Service\Access\AccessServicesFactory;
|
||||
use MintyPHP\Service\Access\PermissionGateway;
|
||||
use MintyPHP\Service\Directory\DirectoryScopeGateway;
|
||||
use MintyPHP\Service\AddressBook\AddressBookServicesFactory;
|
||||
use MintyPHP\Service\Audit\AuditRepositoryFactory;
|
||||
use MintyPHP\Service\Audit\AuditServicesFactory;
|
||||
@@ -22,6 +21,7 @@ use MintyPHP\Service\Branding\BrandingServicesFactory;
|
||||
use MintyPHP\Service\CustomField\CustomFieldServicesFactory;
|
||||
use MintyPHP\Service\Directory\DirectoryGatewayFactory;
|
||||
use MintyPHP\Service\Directory\DirectoryRepositoryFactory;
|
||||
use MintyPHP\Service\Directory\DirectoryScopeGateway;
|
||||
use MintyPHP\Service\Directory\DirectoryServicesFactory;
|
||||
use MintyPHP\Service\Import\ImportRepositoryFactory;
|
||||
use MintyPHP\Service\Import\ImportServicesFactory;
|
||||
@@ -75,7 +75,6 @@ final class ServiceFactoryRegistrar implements ContainerRegistrar
|
||||
$c->get(UserServicesFactory::class),
|
||||
$c->get(AccessServicesFactory::class),
|
||||
$c->get(SettingServicesFactory::class),
|
||||
$c->get(UserRepositoryFactory::class),
|
||||
$c->get(DirectoryServicesFactory::class),
|
||||
$c->get(ImportRepositoryFactory::class)
|
||||
));
|
||||
@@ -114,10 +113,10 @@ final class ServiceFactoryRegistrar implements ContainerRegistrar
|
||||
$c->get(DirectoryScopeGateway::class)
|
||||
));
|
||||
$container->set(UserGatewayFactory::class, static fn (AppContainer $c): UserGatewayFactory => new UserGatewayFactory(
|
||||
$c->get(UserRepositoryFactory::class),
|
||||
$c->get(AccessServicesFactory::class),
|
||||
$c->get(SettingServicesFactory::class),
|
||||
$c->get(TenantScopeService::class)
|
||||
$c->get(TenantScopeService::class),
|
||||
$c->get(DirectoryRepositoryFactory::class),
|
||||
));
|
||||
$container->set(UserServicesFactory::class, static fn (AppContainer $c): UserServicesFactory => new UserServicesFactory(
|
||||
$c->get(AuditServicesFactory::class),
|
||||
|
||||
@@ -7,6 +7,7 @@ use MintyPHP\App\Container\ContainerRegistrar;
|
||||
use MintyPHP\Repository\Auth\ApiTokenRepository;
|
||||
use MintyPHP\Repository\Auth\RememberTokenRepository;
|
||||
use MintyPHP\Service\Access\RoleService;
|
||||
use MintyPHP\Service\Audit\SystemAuditService;
|
||||
use MintyPHP\Service\Branding\BrandingFaviconService;
|
||||
use MintyPHP\Service\Branding\BrandingLogoService;
|
||||
use MintyPHP\Service\Branding\BrandingServicesFactory;
|
||||
@@ -18,7 +19,6 @@ use MintyPHP\Service\Settings\SettingService;
|
||||
use MintyPHP\Service\Settings\SettingServicesFactory;
|
||||
use MintyPHP\Service\Settings\ThemeConfigService;
|
||||
use MintyPHP\Service\Tenant\TenantService;
|
||||
use MintyPHP\Service\Audit\SystemAuditService;
|
||||
|
||||
final class SettingsRegistrar implements ContainerRegistrar
|
||||
{
|
||||
|
||||
@@ -6,14 +6,15 @@ use MintyPHP\App\AppContainer;
|
||||
use MintyPHP\App\Container\ContainerRegistrar;
|
||||
use MintyPHP\Repository\Access\UserRoleRepository;
|
||||
use MintyPHP\Repository\Org\UserDepartmentRepository;
|
||||
use MintyPHP\Repository\Tenant\UserTenantRepository;
|
||||
use MintyPHP\Repository\User\UserReadRepository;
|
||||
use MintyPHP\Repository\User\UserWriteRepository;
|
||||
use MintyPHP\Repository\Tenant\UserTenantRepository;
|
||||
use MintyPHP\Service\Auth\TenantSsoService;
|
||||
use MintyPHP\Service\Branding\BrandingLogoService;
|
||||
use MintyPHP\Service\User\UserAccessPdfService;
|
||||
use MintyPHP\Service\User\UserAccessTemplateService;
|
||||
use MintyPHP\Service\User\UserAccountService;
|
||||
use MintyPHP\Service\User\UserApiWriteInputMapper;
|
||||
use MintyPHP\Service\User\UserAssignmentService;
|
||||
use MintyPHP\Service\User\UserAvatarService;
|
||||
use MintyPHP\Service\User\UserDirectoryGateway;
|
||||
@@ -21,7 +22,6 @@ use MintyPHP\Service\User\UserLifecycleRestoreService;
|
||||
use MintyPHP\Service\User\UserLifecycleService;
|
||||
use MintyPHP\Service\User\UserPasswordPolicyService;
|
||||
use MintyPHP\Service\User\UserPasswordService;
|
||||
use MintyPHP\Service\User\UserApiWriteInputMapper;
|
||||
use MintyPHP\Service\User\UserRepositoryFactory;
|
||||
use MintyPHP\Service\User\UserSavedFilterService;
|
||||
use MintyPHP\Service\User\UserScopeGateway;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace MintyPHP\Http;
|
||||
|
||||
use MintyPHP\Http\RequestContext;
|
||||
use MintyPHP\Service\Audit\ApiAuditService;
|
||||
use MintyPHP\Service\Security\RateLimiterService;
|
||||
use MintyPHP\Service\Settings\SettingGateway;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace MintyPHP\Http;
|
||||
|
||||
use MintyPHP\Http\Input\FormErrors;
|
||||
use MintyPHP\Http\RequestContext;
|
||||
use MintyPHP\Service\Access\AuthorizationService;
|
||||
use MintyPHP\Service\Audit\ApiAuditService;
|
||||
|
||||
@@ -20,8 +19,7 @@ class ApiResponse
|
||||
callable $apiAuditServiceResolver,
|
||||
callable $authorizationServiceResolver,
|
||||
callable $apiSystemAuditReporterResolver
|
||||
): void
|
||||
{
|
||||
): void {
|
||||
self::$apiAuditServiceResolver = $apiAuditServiceResolver;
|
||||
self::$authorizationServiceResolver = $authorizationServiceResolver;
|
||||
self::$apiSystemAuditReporterResolver = $apiSystemAuditReporterResolver;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace MintyPHP\Http;
|
||||
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\I18n;
|
||||
use MintyPHP\Router;
|
||||
|
||||
class Request
|
||||
{
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace MintyPHP\Repository\Audit;
|
||||
|
||||
use MintyPHP\Domain\Taxonomy\ImportAuditStatus;
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Domain\Taxonomy\ImportAuditStatus;
|
||||
use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class ImportAuditRunRepository implements ImportAuditRunRepositoryInterface
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace MintyPHP\Repository\Audit;
|
||||
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Domain\Taxonomy\SystemAuditChannel;
|
||||
use MintyPHP\Domain\Taxonomy\SystemAuditOutcome;
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class SystemAuditLogRepository implements SystemAuditLogRepositoryInterface
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
namespace MintyPHP\Repository\Audit;
|
||||
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Domain\Taxonomy\UserLifecycleAction;
|
||||
use MintyPHP\Domain\Taxonomy\UserLifecycleStatus;
|
||||
use MintyPHP\Domain\Taxonomy\UserLifecycleTriggerType;
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class UserLifecycleAuditRepository implements UserLifecycleAuditRepositoryInterface
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace MintyPHP\Repository\Mail;
|
||||
|
||||
use MintyPHP\Domain\Taxonomy\MailLogStatus;
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Domain\Taxonomy\MailLogStatus;
|
||||
use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class MailLogRepository implements MailLogRepositoryInterface
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace MintyPHP\Repository\Scheduler;
|
||||
|
||||
use MintyPHP\Domain\Taxonomy\ScheduledJobStatus;
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Domain\Taxonomy\ScheduledJobStatus;
|
||||
use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class ScheduledJobRepository implements ScheduledJobRepositoryInterface
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace MintyPHP\Repository\Scheduler;
|
||||
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Domain\Taxonomy\ScheduledJobRunStatus;
|
||||
use MintyPHP\Domain\Taxonomy\ScheduledJobTriggerType;
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class ScheduledJobRunRepository implements ScheduledJobRunRepositoryInterface
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace MintyPHP\Repository\Scheduler;
|
||||
|
||||
use MintyPHP\Domain\Taxonomy\SchedulerRuntimeResult;
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Domain\Taxonomy\SchedulerRuntimeResult;
|
||||
|
||||
class SchedulerRuntimeRepository implements SchedulerRuntimeRepositoryInterface
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace MintyPHP\Repository\Stats;
|
||||
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Domain\Taxonomy\ImportAuditStatus;
|
||||
use MintyPHP\Domain\Taxonomy\MailLogStatus;
|
||||
use MintyPHP\Domain\Taxonomy\ScheduledJobRunStatus;
|
||||
@@ -10,7 +11,6 @@ use MintyPHP\Domain\Taxonomy\SystemAuditOutcome;
|
||||
use MintyPHP\Domain\Taxonomy\TenantStatus;
|
||||
use MintyPHP\Domain\Taxonomy\UserLifecycleAction;
|
||||
use MintyPHP\Domain\Taxonomy\UserLifecycleStatus;
|
||||
use MintyPHP\DB;
|
||||
|
||||
class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
{
|
||||
@@ -43,7 +43,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
$inactiveDepartmentCount = (int) (DB::selectValue('select count(*) from departments where active = 0') ?? 0);
|
||||
$activeRoleCount = (int) (DB::selectValue('select count(*) from roles where active = 1') ?? 0);
|
||||
$inactiveRoleCount = (int) (DB::selectValue('select count(*) from roles where active = 0') ?? 0);
|
||||
|
||||
|
||||
$rolesWithoutPermissionsCount = (int) (DB::selectValue(
|
||||
'select count(*) from roles r left join role_permissions rp on rp.role_id = r.id where r.active = 1 and rp.role_id is null'
|
||||
) ?? 0);
|
||||
@@ -56,7 +56,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
$usersWithoutTenantsCount = (int) (DB::selectValue(
|
||||
'select count(*) from users u left join user_tenants ut on ut.user_id = u.id where u.active = 1 and ut.user_id is null'
|
||||
) ?? 0);
|
||||
|
||||
|
||||
$flattenStatsRow = static function ($row): array {
|
||||
if (!is_array($row)) {
|
||||
return [];
|
||||
@@ -74,7 +74,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
}
|
||||
return $flat;
|
||||
};
|
||||
|
||||
|
||||
$ssoStatsAvailable = (int) (DB::selectValue(
|
||||
"select count(*) from information_schema.tables where table_schema = database() and table_name = 'tenant_auth_microsoft'"
|
||||
) ?? 0) === 1;
|
||||
@@ -86,7 +86,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
$ssoTenantRows = [];
|
||||
$usersMicrosoftOnlyRows = [];
|
||||
$usersMicrosoftSyncGapRows = [];
|
||||
|
||||
|
||||
if ($ssoStatsAvailable) {
|
||||
$ssoEnabledTenantCount = (int) (DB::selectValue(
|
||||
"select count(*) from tenants t " .
|
||||
@@ -103,7 +103,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
if ($activeTenantCount > 0) {
|
||||
$ssoEnabledTenantPercent = round(((float) $ssoEnabledTenantCount * 100) / (float) $activeTenantCount, 1);
|
||||
}
|
||||
|
||||
|
||||
$usersMicrosoftOnlyCount = (int) (DB::selectValue(
|
||||
"select count(*) from users u " .
|
||||
"where u.active = 1 " .
|
||||
@@ -122,7 +122,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
$tenantActiveStatus,
|
||||
$tenantActiveStatus
|
||||
) ?? 0);
|
||||
|
||||
|
||||
$usersMicrosoftSyncGapsCount = (int) (DB::selectValue(
|
||||
"select count(*) from ( " .
|
||||
" select u.id, " .
|
||||
@@ -147,7 +147,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
" or (x.need_mobile = 1 and x.mobile_value = '')",
|
||||
$tenantActiveStatus
|
||||
) ?? 0);
|
||||
|
||||
|
||||
$ssoTenantRowsRaw = DB::select(
|
||||
"select " .
|
||||
" t.uuid as tenant_uuid, " .
|
||||
@@ -182,7 +182,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
},
|
||||
$ssoTenantRowsRaw
|
||||
))) : [];
|
||||
|
||||
|
||||
$usersMicrosoftOnlyRowsRaw = DB::select(
|
||||
"select " .
|
||||
" u.uuid as user_uuid, " .
|
||||
@@ -217,7 +217,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
},
|
||||
$usersMicrosoftOnlyRowsRaw
|
||||
))) : [];
|
||||
|
||||
|
||||
$usersMicrosoftSyncGapRowsRaw = DB::select(
|
||||
"select " .
|
||||
" x.user_uuid, x.user_display_name, x.user_email, " .
|
||||
@@ -278,7 +278,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
$usersMicrosoftSyncGapRowsRaw
|
||||
))) : [];
|
||||
}
|
||||
|
||||
|
||||
$customFieldStatsAvailable = (int) (DB::selectValue(
|
||||
"select count(*) from information_schema.tables " .
|
||||
"where table_schema = database() " .
|
||||
@@ -293,7 +293,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
$customFieldsInactiveWithValuesHref = 'admin/tenants';
|
||||
$customFieldsUnusedActiveHref = 'admin/tenants';
|
||||
$customFieldIssueTenantRows = [];
|
||||
|
||||
|
||||
if ($customFieldStatsAvailable) {
|
||||
$loadCustomFieldIssueTenants = static function (string $query): array {
|
||||
$rows = DB::select($query);
|
||||
@@ -318,7 +318,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
}
|
||||
return $items;
|
||||
};
|
||||
|
||||
|
||||
$customFieldsSelectionWithoutOptionsCount = (int) (DB::selectValue(
|
||||
"select count(*) from ( " .
|
||||
"select d.id " .
|
||||
@@ -329,7 +329,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
"having count(o.id) = 0 " .
|
||||
') missing_options'
|
||||
) ?? 0);
|
||||
|
||||
|
||||
$customFieldTenantsWithSelectionWithoutOptionsCount = (int) (DB::selectValue(
|
||||
"select count(distinct missing_options.tenant_id) from ( " .
|
||||
"select d.tenant_id " .
|
||||
@@ -340,13 +340,13 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
"having count(o.id) = 0 " .
|
||||
') missing_options'
|
||||
) ?? 0);
|
||||
|
||||
|
||||
$customFieldsInactiveWithValuesCount = (int) (DB::selectValue(
|
||||
'select count(distinct d.id) from tenant_custom_field_definitions d ' .
|
||||
'inner join user_custom_field_values v on v.definition_id = d.id ' .
|
||||
'where d.active = 0'
|
||||
) ?? 0);
|
||||
|
||||
|
||||
$customFieldsUnusedActiveCount = (int) (DB::selectValue(
|
||||
"select count(*) from ( " .
|
||||
"select d.id " .
|
||||
@@ -357,7 +357,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
"having count(v.id) = 0 " .
|
||||
') unused_active'
|
||||
) ?? 0);
|
||||
|
||||
|
||||
$selectionWithoutOptionsTenantUuid = (string) (DB::selectValue(
|
||||
"select t.uuid from tenants t " .
|
||||
"inner join ( " .
|
||||
@@ -372,7 +372,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
') issue on issue.tenant_id = t.id ' .
|
||||
'limit 1'
|
||||
) ?? '');
|
||||
|
||||
|
||||
$inactiveWithValuesTenantUuid = (string) (DB::selectValue(
|
||||
"select t.uuid from tenants t " .
|
||||
"inner join ( " .
|
||||
@@ -386,7 +386,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
') issue on issue.tenant_id = t.id ' .
|
||||
'limit 1'
|
||||
) ?? '');
|
||||
|
||||
|
||||
$unusedActiveTenantUuid = (string) (DB::selectValue(
|
||||
"select t.uuid from tenants t " .
|
||||
"inner join ( " .
|
||||
@@ -401,7 +401,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
') issue on issue.tenant_id = t.id ' .
|
||||
'limit 1'
|
||||
) ?? '');
|
||||
|
||||
|
||||
if ($selectionWithoutOptionsTenantUuid !== '') {
|
||||
$customFieldsSelectionWithoutOptionsHref = 'admin/tenants/edit/' . $selectionWithoutOptionsTenantUuid . '?tab=custom_fields';
|
||||
$customFieldTenantsWithSelectionWithoutOptionsHref = $customFieldsSelectionWithoutOptionsHref;
|
||||
@@ -412,7 +412,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
if ($unusedActiveTenantUuid !== '') {
|
||||
$customFieldsUnusedActiveHref = 'admin/tenants/edit/' . $unusedActiveTenantUuid . '?tab=custom_fields';
|
||||
}
|
||||
|
||||
|
||||
$selectionIssueTenants = $loadCustomFieldIssueTenants(
|
||||
"select t.uuid, t.description, count(*) as issue_count " .
|
||||
"from tenants t " .
|
||||
@@ -436,7 +436,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
'issue_count' => $row['issue_count'],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
$inactiveIssueTenants = $loadCustomFieldIssueTenants(
|
||||
"select t.uuid, t.description, count(distinct d.id) as issue_count " .
|
||||
"from tenants t " .
|
||||
@@ -454,7 +454,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
'issue_count' => $row['issue_count'],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
$unusedIssueTenants = $loadCustomFieldIssueTenants(
|
||||
"select t.uuid, t.description, count(*) as issue_count " .
|
||||
"from tenants t " .
|
||||
@@ -479,7 +479,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$apiStatsAvailable = (int) (DB::selectValue(
|
||||
"select count(*) from information_schema.tables " .
|
||||
"where table_schema = database() and table_name in ('api_audit_log', 'user_api_tokens')"
|
||||
@@ -493,7 +493,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
$apiTokensExpiring7dCount = 0;
|
||||
$apiTopErrorRows = [];
|
||||
$apiSlowEndpointRows = [];
|
||||
|
||||
|
||||
if ($apiStatsAvailable) {
|
||||
$apiRequests24hCount = (int) (DB::selectValue(
|
||||
'select count(*) from api_audit_log where created_at >= (NOW() - INTERVAL 24 HOUR)'
|
||||
@@ -504,14 +504,14 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
if ($apiRequestsPrev24hCount > 0) {
|
||||
$apiRequestTrendPercent = round((($apiRequests24hCount - $apiRequestsPrev24hCount) * 100) / $apiRequestsPrev24hCount, 1);
|
||||
}
|
||||
|
||||
|
||||
$apiErrors4xx24hCount = (int) (DB::selectValue(
|
||||
'select count(*) from api_audit_log where created_at >= (NOW() - INTERVAL 24 HOUR) and status_code between 400 and 499'
|
||||
) ?? 0);
|
||||
$apiErrors5xx24hCount = (int) (DB::selectValue(
|
||||
'select count(*) from api_audit_log where created_at >= (NOW() - INTERVAL 24 HOUR) and status_code between 500 and 599'
|
||||
) ?? 0);
|
||||
|
||||
|
||||
$durationCount = (int) (DB::selectValue(
|
||||
'select count(*) from api_audit_log where created_at >= (NOW() - INTERVAL 24 HOUR) and status_code between 200 and 299 and duration_ms is not null'
|
||||
) ?? 0);
|
||||
@@ -523,12 +523,12 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
'order by duration_ms asc limit ' . $offset . ', 1'
|
||||
) ?? 0);
|
||||
}
|
||||
|
||||
|
||||
$apiTokensExpiring7dCount = (int) (DB::selectValue(
|
||||
'select count(*) from user_api_tokens ' .
|
||||
'where revoked_at is null and expires_at is not null and expires_at > NOW() and expires_at <= (NOW() + INTERVAL 7 DAY)'
|
||||
) ?? 0);
|
||||
|
||||
|
||||
$apiTopErrorRowsRaw = DB::select(
|
||||
"select " .
|
||||
" coalesce(nullif(error_code, ''), concat('http_', status_code)) as error_label, " .
|
||||
@@ -554,7 +554,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
},
|
||||
$apiTopErrorRowsRaw
|
||||
))) : [];
|
||||
|
||||
|
||||
$apiSlowEndpointRowsRaw = DB::select(
|
||||
"select " .
|
||||
" path, " .
|
||||
@@ -586,7 +586,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
$apiSlowEndpointRowsRaw
|
||||
))) : [];
|
||||
}
|
||||
|
||||
|
||||
$importStatsAvailable = (int) (DB::selectValue(
|
||||
"select count(*) from information_schema.tables " .
|
||||
"where table_schema = database() and table_name = 'import_audit_runs'"
|
||||
@@ -602,7 +602,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
$importRecentRunRows = [];
|
||||
$importProfileRows = [];
|
||||
$importTopErrorCodeRows = [];
|
||||
|
||||
|
||||
if ($importStatsAvailable) {
|
||||
$importRuns7dCount = (int) (DB::selectValue(
|
||||
"select count(*) from import_audit_runs where started_at >= (NOW() - INTERVAL 7 DAY)"
|
||||
@@ -613,7 +613,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
if ($importRunsPrev7dCount > 0) {
|
||||
$importRunTrendPercent = round((($importRuns7dCount - $importRunsPrev7dCount) * 100) / $importRunsPrev7dCount, 1);
|
||||
}
|
||||
|
||||
|
||||
$importRowsCreated7dCount = (int) (DB::selectValue(
|
||||
"select coalesce(sum(created_count), 0) from import_audit_runs where started_at >= (NOW() - INTERVAL 7 DAY)"
|
||||
) ?? 0);
|
||||
@@ -635,7 +635,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
if ($importRuns7dCount > 0) {
|
||||
$importSuccessRate7dPercent = round(($importSuccessRuns7dCount * 100) / $importRuns7dCount, 1);
|
||||
}
|
||||
|
||||
|
||||
$importRecentRunRowsRaw = DB::select(
|
||||
"select " .
|
||||
" import_audit_runs.id, " .
|
||||
@@ -680,7 +680,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
},
|
||||
$importRecentRunRowsRaw
|
||||
))) : [];
|
||||
|
||||
|
||||
$importProfileRowsRaw = DB::select(
|
||||
"select " .
|
||||
" profile_key, " .
|
||||
@@ -715,7 +715,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
},
|
||||
$importProfileRowsRaw
|
||||
))) : [];
|
||||
|
||||
|
||||
$importTopErrorRowsRaw = DB::select(
|
||||
"select error_codes_json from import_audit_runs " .
|
||||
"where started_at >= (NOW() - INTERVAL 7 DAY) " .
|
||||
@@ -1001,7 +1001,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
$lifecycleRecentRiskRowsRaw
|
||||
))) : [];
|
||||
}
|
||||
|
||||
|
||||
$scheduledStatsAvailable = (int) (DB::selectValue(
|
||||
"select count(*) from information_schema.tables " .
|
||||
"where table_schema = database() and table_name in ('scheduled_jobs', 'scheduled_job_runs', 'scheduler_runtime_status')"
|
||||
@@ -1014,7 +1014,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
$schedulerRunnerLastResult = '';
|
||||
$schedulerRunnerLastErrorCode = '';
|
||||
$schedulerRunnerIsActive = false;
|
||||
|
||||
|
||||
if ($scheduledStatsAvailable) {
|
||||
$scheduledEnabledJobsCount = (int) (DB::selectValue(
|
||||
"select count(*) from scheduled_jobs where enabled = 1"
|
||||
@@ -1034,12 +1034,12 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
$schedulerTriggerScheduler,
|
||||
$schedulerRunStatusFailed
|
||||
) ?? 0);
|
||||
|
||||
|
||||
$schedulerRunnerIsActive = (int) (DB::selectValue(
|
||||
"select case when last_heartbeat_at >= (NOW() - INTERVAL 3 MINUTE) then 1 else 0 end " .
|
||||
"from scheduler_runtime_status where id = 1"
|
||||
) ?? 0) === 1;
|
||||
|
||||
|
||||
$schedulerRuntimeRowRaw = DB::selectOne(
|
||||
"select last_heartbeat_at, last_result, last_error_code from scheduler_runtime_status where id = 1 limit 1"
|
||||
);
|
||||
@@ -1048,7 +1048,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
$schedulerRunnerLastResult = trim((string) ($schedulerRuntimeRow['last_result'] ?? ''));
|
||||
$schedulerRunnerLastErrorCode = trim((string) ($schedulerRuntimeRow['last_error_code'] ?? ''));
|
||||
}
|
||||
|
||||
|
||||
$usersUnverifiedCount = (int) (DB::selectValue(
|
||||
'select count(*) from users where active = 1 and email_verified_at is null'
|
||||
) ?? 0);
|
||||
@@ -1069,7 +1069,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
static fn ($row) => $row['users'] ?? $row,
|
||||
$neverLoggedUsers
|
||||
) : [];
|
||||
|
||||
|
||||
$mailLogFailedCount = (int) (DB::selectValue('select count(*) from mail_log where status = ?', $mailStatusFailed) ?? 0);
|
||||
$mailLogSentCount = (int) (DB::selectValue('select count(*) from mail_log where status = ?', $mailStatusSent) ?? 0);
|
||||
$mailLogLastSentAt = (string) (DB::selectValue('select max(sent_at) from mail_log where status = ?', $mailStatusSent) ?? '');
|
||||
@@ -1081,7 +1081,7 @@ class AdminStatsRepository implements AdminStatsRepositoryInterface
|
||||
static fn ($row) => $row['mail_log'] ?? $row,
|
||||
$mailLogRecentFailed
|
||||
) : [];
|
||||
|
||||
|
||||
|
||||
$vars = get_defined_vars();
|
||||
unset($vars['this']);
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace MintyPHP\Repository\Tenant;
|
||||
|
||||
use MintyPHP\Domain\Taxonomy\TenantStatus;
|
||||
use MintyPHP\DB;
|
||||
use MintyPHP\Domain\Taxonomy\TenantStatus;
|
||||
use MintyPHP\Repository\Support\RepoQuery;
|
||||
|
||||
class TenantRepository implements TenantRepositoryInterface
|
||||
|
||||
@@ -12,8 +12,7 @@ class AccessGatewayFactory
|
||||
public function __construct(
|
||||
private readonly AccessRepositoryFactory $accessRepositoryFactory,
|
||||
private readonly AuditServicesFactory $auditServicesFactory
|
||||
)
|
||||
{
|
||||
) {
|
||||
}
|
||||
|
||||
public function createPermissionService(): PermissionService
|
||||
|
||||
@@ -47,4 +47,3 @@ class AuthorizationDecision
|
||||
return array_key_exists($key, $this->attributes) ? $this->attributes[$key] : $default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,4 +8,3 @@ interface AuthorizationPolicyInterface
|
||||
|
||||
public function authorize(string $ability, array $context = []): AuthorizationDecision;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace MintyPHP\Service\AddressBook;
|
||||
|
||||
use MintyPHP\Service\Directory\DirectoryScopeGateway;
|
||||
use MintyPHP\Service\Access\RoleService;
|
||||
use MintyPHP\Service\Directory\DirectoryScopeGateway;
|
||||
use MintyPHP\Service\Org\DepartmentService;
|
||||
use MintyPHP\Service\Tenant\TenantService;
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ class AddressBookServicesFactory
|
||||
private readonly UserServicesFactory $userServicesFactory,
|
||||
private readonly DirectoryServicesFactory $directoryServicesFactory,
|
||||
private readonly CustomFieldServicesFactory $customFieldServicesFactory
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function createAddressBookService(): AddressBookService
|
||||
{
|
||||
|
||||
@@ -17,7 +17,8 @@ class AuditServicesFactory
|
||||
public function __construct(
|
||||
private readonly AuditRepositoryFactory $auditRepositoryFactory,
|
||||
private readonly SettingGateway $settingGateway
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function createApiAuditLogRepository(): ApiAuditLogRepositoryInterface
|
||||
{
|
||||
|
||||
@@ -4,8 +4,8 @@ namespace MintyPHP\Service\Audit;
|
||||
|
||||
use MintyPHP\Domain\Taxonomy\SystemAuditChannel;
|
||||
use MintyPHP\Domain\Taxonomy\SystemAuditOutcome;
|
||||
use MintyPHP\Http\RequestContext;
|
||||
use MintyPHP\Http\ApiAuth;
|
||||
use MintyPHP\Http\RequestContext;
|
||||
use MintyPHP\Repository\Audit\SystemAuditLogRepositoryInterface;
|
||||
use MintyPHP\Repository\Support\RepoQuery;
|
||||
use MintyPHP\Service\Settings\SettingGateway;
|
||||
@@ -27,8 +27,7 @@ class SystemAuditService
|
||||
string $eventType,
|
||||
string $outcome = SystemAuditOutcome::Success->value,
|
||||
array $context = []
|
||||
): ?int
|
||||
{
|
||||
): ?int {
|
||||
if (!$this->isEnabled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ use MintyPHP\Auth;
|
||||
use MintyPHP\Repository\User\UserReadRepositoryInterface;
|
||||
use MintyPHP\Repository\User\UserWriteRepositoryInterface;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Audit\SystemAuditService;
|
||||
use MintyPHP\Service\User\UserAccountService;
|
||||
use MintyPHP\Service\User\UserTenantContextService;
|
||||
use MintyPHP\Service\Audit\SystemAuditService;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Flash;
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ class AuthServicesFactory
|
||||
private readonly AuthRepositoryFactory $authRepositoryFactory,
|
||||
private readonly AuthGatewayFactory $authGatewayFactory,
|
||||
private readonly DatabaseSessionRepository $databaseSessionRepository
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function createApiTokenService(): ApiTokenService
|
||||
{
|
||||
|
||||
@@ -6,7 +6,6 @@ use MintyPHP\Repository\Tenant\UserTenantRepositoryInterface;
|
||||
use MintyPHP\Repository\User\UserReadRepositoryInterface;
|
||||
use MintyPHP\Repository\User\UserWriteRepositoryInterface;
|
||||
use MintyPHP\Service\User\UserAssignmentService;
|
||||
use MintyPHP\Service\User\UserAvatarService;
|
||||
|
||||
class SsoUserLinkService
|
||||
{
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace MintyPHP\Service\Content;
|
||||
|
||||
use MintyPHP\Repository\Content\PageRepository;
|
||||
use MintyPHP\Repository\Content\PageContentRepository;
|
||||
use MintyPHP\I18n;
|
||||
use MintyPHP\Repository\Content\PageContentRepository;
|
||||
use MintyPHP\Repository\Content\PageRepository;
|
||||
|
||||
class PageService
|
||||
{
|
||||
@@ -59,8 +59,7 @@ class PageService
|
||||
string $content,
|
||||
int $currentUserId = 0,
|
||||
?string $locale = null
|
||||
): array
|
||||
{
|
||||
): array {
|
||||
$slug = trim($slug);
|
||||
if ($slug === '') {
|
||||
return ['ok' => false, 'status' => 404, 'error' => 'not_found'];
|
||||
|
||||
@@ -22,7 +22,8 @@ class DirectoryServicesFactory
|
||||
private readonly AuditServicesFactory $auditServicesFactory,
|
||||
private readonly DirectoryRepositoryFactory $directoryRepositoryFactory,
|
||||
private readonly DirectoryGatewayFactory $directoryGatewayFactory
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function createTenantService(): TenantService
|
||||
{
|
||||
|
||||
@@ -143,8 +143,12 @@ trait ImageUploadTrait
|
||||
$scale = min($width / $srcWidth, $height / $srcHeight);
|
||||
$dstWidth = (int) round($srcWidth * $scale);
|
||||
$dstHeight = (int) round($srcHeight * $scale);
|
||||
if ($dstWidth < 1) $dstWidth = 1;
|
||||
if ($dstHeight < 1) $dstHeight = 1;
|
||||
if ($dstWidth < 1) {
|
||||
$dstWidth = 1;
|
||||
}
|
||||
if ($dstHeight < 1) {
|
||||
$dstHeight = 1;
|
||||
}
|
||||
|
||||
$dst = imagecreatetruecolor($dstWidth, $dstHeight);
|
||||
if ($ext === 'png' || $ext === 'webp') {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace MintyPHP\Service\Import;
|
||||
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
use MintyPHP\Service\Access\PermissionGateway;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
use MintyPHP\Service\Audit\ImportAuditService;
|
||||
use MintyPHP\Service\Import\Profile\ImportProfileInterface;
|
||||
use MintyPHP\Service\Settings\SettingGateway;
|
||||
|
||||
@@ -13,7 +13,6 @@ use MintyPHP\Service\Import\Profile\UserImportGateway;
|
||||
use MintyPHP\Service\Import\Profile\UserImportProfile;
|
||||
use MintyPHP\Service\Settings\SettingGateway;
|
||||
use MintyPHP\Service\Settings\SettingServicesFactory;
|
||||
use MintyPHP\Service\User\UserRepositoryFactory;
|
||||
use MintyPHP\Service\User\UserServicesFactory;
|
||||
|
||||
class ImportServicesFactory
|
||||
@@ -30,10 +29,10 @@ class ImportServicesFactory
|
||||
private readonly UserServicesFactory $userServicesFactory,
|
||||
private readonly AccessServicesFactory $accessServicesFactory,
|
||||
private readonly SettingServicesFactory $settingServicesFactory,
|
||||
private readonly UserRepositoryFactory $userRepositoryFactory,
|
||||
private readonly DirectoryServicesFactory $directoryServicesFactory,
|
||||
private readonly ImportRepositoryFactory $importRepositoryFactory
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function createImportService(): ImportService
|
||||
{
|
||||
@@ -45,7 +44,9 @@ class ImportServicesFactory
|
||||
'users' => new UserImportProfile(new UserImportGateway(
|
||||
$this->userServicesFactory->createUserReadRepository(),
|
||||
$this->userServicesFactory->createUserAccountService(),
|
||||
$this->userRepositoryFactory
|
||||
$this->directoryServicesFactory->createTenantRepository(),
|
||||
$this->directoryServicesFactory->createRoleRepository(),
|
||||
$this->directoryServicesFactory->createDepartmentRepository(),
|
||||
)),
|
||||
'departments' => new DepartmentImportProfile(new DepartmentImportGateway(
|
||||
$this->directoryServicesFactory->createDepartmentRepository(),
|
||||
|
||||
@@ -60,4 +60,3 @@ class ImportStateStoreService
|
||||
unset($_SESSION[self::SESSION_KEY][$token]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,14 +7,15 @@ use MintyPHP\Repository\Org\DepartmentRepositoryInterface;
|
||||
use MintyPHP\Repository\Tenant\TenantRepositoryInterface;
|
||||
use MintyPHP\Repository\User\UserReadRepositoryInterface;
|
||||
use MintyPHP\Service\User\UserAccountService;
|
||||
use MintyPHP\Service\User\UserRepositoryFactory;
|
||||
|
||||
class UserImportGateway
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserReadRepositoryInterface $userReadRepository,
|
||||
private readonly UserAccountService $userAccountService,
|
||||
private readonly UserRepositoryFactory $userRepositoryFactory
|
||||
private readonly TenantRepositoryInterface $tenantRepository,
|
||||
private readonly RoleRepositoryInterface $roleRepository,
|
||||
private readonly DepartmentRepositoryInterface $departmentRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -25,32 +26,32 @@ class UserImportGateway
|
||||
|
||||
public function findTenantByUuid(string $uuid): ?array
|
||||
{
|
||||
return $this->tenantRepository()->findByUuid($uuid);
|
||||
return $this->tenantRepository->findByUuid($uuid);
|
||||
}
|
||||
|
||||
public function findTenantById(int $id): ?array
|
||||
{
|
||||
return $this->tenantRepository()->find($id);
|
||||
return $this->tenantRepository->find($id);
|
||||
}
|
||||
|
||||
public function findRoleByUuid(string $uuid): ?array
|
||||
{
|
||||
return $this->roleRepository()->findByUuid($uuid);
|
||||
return $this->roleRepository->findByUuid($uuid);
|
||||
}
|
||||
|
||||
public function findRoleById(int $id): ?array
|
||||
{
|
||||
return $this->roleRepository()->find($id);
|
||||
return $this->roleRepository->find($id);
|
||||
}
|
||||
|
||||
public function findDepartmentByUuid(string $uuid): ?array
|
||||
{
|
||||
return $this->departmentRepository()->findByUuid($uuid);
|
||||
return $this->departmentRepository->findByUuid($uuid);
|
||||
}
|
||||
|
||||
public function findDepartmentById(int $id): ?array
|
||||
{
|
||||
return $this->departmentRepository()->find($id);
|
||||
return $this->departmentRepository->find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,19 +62,4 @@ class UserImportGateway
|
||||
{
|
||||
return $this->userAccountService->createFromAdmin($input, $currentUserId);
|
||||
}
|
||||
|
||||
private function tenantRepository(): TenantRepositoryInterface
|
||||
{
|
||||
return $this->userRepositoryFactory->createTenantRepository();
|
||||
}
|
||||
|
||||
private function roleRepository(): RoleRepositoryInterface
|
||||
{
|
||||
return $this->userRepositoryFactory->createRoleRepository();
|
||||
}
|
||||
|
||||
private function departmentRepository(): DepartmentRepositoryInterface
|
||||
{
|
||||
return $this->userRepositoryFactory->createDepartmentRepository();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ class MailServicesFactory
|
||||
public function __construct(
|
||||
private readonly MailRepositoryFactory $mailRepositoryFactory,
|
||||
private readonly SettingGateway $settingGateway
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function createMailLogRepository(): MailLogRepositoryInterface
|
||||
{
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
namespace MintyPHP\Service\Scheduler;
|
||||
|
||||
use MintyPHP\Service\Audit\SystemAuditService;
|
||||
use MintyPHP\Service\Scheduler\Handler\ScheduledJobHandlerInterface;
|
||||
use MintyPHP\Service\Scheduler\Handler\SystemAuditPurgeJobHandler;
|
||||
use MintyPHP\Service\Scheduler\Handler\UserLifecycleJobHandler;
|
||||
use MintyPHP\Service\Audit\SystemAuditService;
|
||||
use MintyPHP\Service\User\UserLifecycleService;
|
||||
|
||||
class ScheduledJobRegistry
|
||||
@@ -30,8 +30,7 @@ class ScheduledJobRegistry
|
||||
public function __construct(
|
||||
UserLifecycleService $userLifecycleService,
|
||||
SystemAuditService $systemAuditService
|
||||
)
|
||||
{
|
||||
) {
|
||||
$this->handlers = [
|
||||
self::USER_LIFECYCLE_RUN => new UserLifecycleJobHandler($userLifecycleService),
|
||||
self::SYSTEM_AUDIT_PURGE => new SystemAuditPurgeJobHandler($systemAuditService),
|
||||
|
||||
@@ -23,7 +23,8 @@ class SchedulerServicesFactory
|
||||
private readonly AuditServicesFactory $auditServicesFactory,
|
||||
private readonly DatabaseSessionRepository $databaseSessionRepository,
|
||||
private readonly SchedulerRepositoryFactory $schedulerRepositoryFactory
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function createScheduledJobService(): ScheduledJobService
|
||||
{
|
||||
|
||||
@@ -10,7 +10,8 @@ class SecurityServicesFactory
|
||||
|
||||
public function __construct(
|
||||
private readonly SecurityRepositoryFactory $securityRepositoryFactory
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function createRateLimitRepository(): RateLimitRepositoryInterface
|
||||
{
|
||||
|
||||
@@ -5,8 +5,8 @@ namespace MintyPHP\Service\Settings;
|
||||
use MintyPHP\Repository\Auth\ApiTokenRepository;
|
||||
use MintyPHP\Repository\Auth\RememberTokenRepository;
|
||||
use MintyPHP\Service\Access\RoleService;
|
||||
use MintyPHP\Service\Org\DepartmentService;
|
||||
use MintyPHP\Service\Audit\SystemAuditService;
|
||||
use MintyPHP\Service\Org\DepartmentService;
|
||||
use MintyPHP\Service\Tenant\TenantService;
|
||||
|
||||
class AdminSettingsService
|
||||
|
||||
@@ -16,7 +16,8 @@ class SettingServicesFactory
|
||||
|
||||
public function __construct(
|
||||
private readonly SettingRepositoryFactory $settingRepositoryFactory
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function createSettingRepository(): SettingRepositoryInterface
|
||||
{
|
||||
|
||||
@@ -16,7 +16,8 @@ class TenantServicesFactory
|
||||
public function __construct(
|
||||
private readonly PermissionGateway $permissionGateway,
|
||||
private readonly TenantRepositoryFactory $tenantRepositoryFactory
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function createTenantScopeService(): TenantScopeService
|
||||
{
|
||||
|
||||
@@ -565,7 +565,7 @@ class UserAccountService
|
||||
$errors[] = t('Tenant not found');
|
||||
} else {
|
||||
$userTenantIds = $this->userAssignmentService->buildAssignmentsForUser($userId)['tenants'] ?? [];
|
||||
$userTenantIds = array_map(static fn(array $t): int => (int) ($t['id'] ?? 0), $userTenantIds);
|
||||
$userTenantIds = array_map(static fn (array $t): int => (int) ($t['id'] ?? 0), $userTenantIds);
|
||||
$tenantId = (int) $tenant['id'];
|
||||
if (!in_array($tenantId, $userTenantIds, true)) {
|
||||
$errors[] = t('No access to this tenant');
|
||||
|
||||
@@ -9,72 +9,59 @@ use MintyPHP\Repository\Tenant\TenantRepositoryInterface;
|
||||
class UserDirectoryGateway
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserRepositoryFactory $userRepositoryFactory
|
||||
private readonly TenantRepositoryInterface $tenantRepository,
|
||||
private readonly RoleRepositoryInterface $roleRepository,
|
||||
private readonly DepartmentRepositoryInterface $departmentRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
public function listTenantIds(): array
|
||||
{
|
||||
return $this->tenantRepository()->listIds();
|
||||
return $this->tenantRepository->listIds();
|
||||
}
|
||||
|
||||
public function listTenantsByIds(array $tenantIds): array
|
||||
{
|
||||
return $this->tenantRepository()->listByIds($tenantIds);
|
||||
return $this->tenantRepository->listByIds($tenantIds);
|
||||
}
|
||||
|
||||
public function findTenant(int $tenantId): ?array
|
||||
{
|
||||
return $this->tenantRepository()->find($tenantId);
|
||||
return $this->tenantRepository->find($tenantId);
|
||||
}
|
||||
|
||||
public function findTenantByUuid(string $tenantUuid): ?array
|
||||
{
|
||||
return $this->tenantRepository()->findByUuid($tenantUuid);
|
||||
return $this->tenantRepository->findByUuid($tenantUuid);
|
||||
}
|
||||
|
||||
public function listActiveTenantIdsByIds(array $tenantIds): array
|
||||
{
|
||||
return $this->tenantRepository()->listActiveIdsByIds($tenantIds);
|
||||
return $this->tenantRepository->listActiveIdsByIds($tenantIds);
|
||||
}
|
||||
|
||||
public function listActiveRoleIds(): array
|
||||
{
|
||||
return $this->roleRepository()->listActiveIds();
|
||||
return $this->roleRepository->listActiveIds();
|
||||
}
|
||||
|
||||
public function listRolesByIds(array $roleIds): array
|
||||
{
|
||||
return $this->roleRepository()->listByIds($roleIds);
|
||||
return $this->roleRepository->listByIds($roleIds);
|
||||
}
|
||||
|
||||
public function listDepartmentsByIds(array $departmentIds, bool $includeInactive = true): array
|
||||
{
|
||||
return $this->departmentRepository()->listByIds($departmentIds, $includeInactive);
|
||||
return $this->departmentRepository->listByIds($departmentIds, $includeInactive);
|
||||
}
|
||||
|
||||
public function listActiveDepartmentIdsByTenantIds(array $tenantIds): array
|
||||
{
|
||||
return $this->departmentRepository()->listActiveIdsByTenantIds($tenantIds);
|
||||
return $this->departmentRepository->listActiveIdsByTenantIds($tenantIds);
|
||||
}
|
||||
|
||||
public function listDepartmentsByTenantIds(array $tenantIds): array
|
||||
{
|
||||
return $this->departmentRepository()->listByTenantIds($tenantIds);
|
||||
}
|
||||
|
||||
private function tenantRepository(): TenantRepositoryInterface
|
||||
{
|
||||
return $this->userRepositoryFactory->createTenantRepository();
|
||||
}
|
||||
|
||||
private function roleRepository(): RoleRepositoryInterface
|
||||
{
|
||||
return $this->userRepositoryFactory->createRoleRepository();
|
||||
}
|
||||
|
||||
private function departmentRepository(): DepartmentRepositoryInterface
|
||||
{
|
||||
return $this->userRepositoryFactory->createDepartmentRepository();
|
||||
return $this->departmentRepository->listByTenantIds($tenantIds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace MintyPHP\Service\User;
|
||||
|
||||
use MintyPHP\Service\Access\AccessServicesFactory;
|
||||
use MintyPHP\Service\Access\PermissionGateway;
|
||||
use MintyPHP\Service\Directory\DirectoryRepositoryFactory;
|
||||
use MintyPHP\Service\Settings\SettingGateway;
|
||||
use MintyPHP\Service\Settings\SettingServicesFactory;
|
||||
use MintyPHP\Service\Tenant\TenantScopeService;
|
||||
@@ -18,10 +19,10 @@ class UserGatewayFactory
|
||||
private ?UserPermissionGateway $userPermissionGateway = null;
|
||||
|
||||
public function __construct(
|
||||
private readonly UserRepositoryFactory $userRepositoryFactory,
|
||||
private readonly AccessServicesFactory $accessServicesFactory,
|
||||
private readonly SettingServicesFactory $settingServicesFactory,
|
||||
private readonly TenantScopeService $tenantScopeService
|
||||
private readonly TenantScopeService $tenantScopeService,
|
||||
private readonly DirectoryRepositoryFactory $directoryRepositoryFactory,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -37,7 +38,11 @@ class UserGatewayFactory
|
||||
|
||||
public function createUserDirectoryGateway(): UserDirectoryGateway
|
||||
{
|
||||
return $this->userDirectoryGateway ??= new UserDirectoryGateway($this->userRepositoryFactory);
|
||||
return $this->userDirectoryGateway ??= new UserDirectoryGateway(
|
||||
$this->directoryRepositoryFactory->createTenantRepository(),
|
||||
$this->directoryRepositoryFactory->createRoleRepository(),
|
||||
$this->directoryRepositoryFactory->createDepartmentRepository(),
|
||||
);
|
||||
}
|
||||
|
||||
public function createUserPermissionGateway(): UserPermissionGateway
|
||||
@@ -54,5 +59,4 @@ class UserGatewayFactory
|
||||
{
|
||||
return $this->settingGateway ??= $this->settingServicesFactory->createSettingGateway();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,16 +2,10 @@
|
||||
|
||||
namespace MintyPHP\Service\User;
|
||||
|
||||
use MintyPHP\Repository\Access\RoleRepository;
|
||||
use MintyPHP\Repository\Access\RoleRepositoryInterface;
|
||||
use MintyPHP\Repository\Access\UserRoleRepository;
|
||||
use MintyPHP\Repository\Access\UserRoleRepositoryInterface;
|
||||
use MintyPHP\Repository\Org\DepartmentRepository;
|
||||
use MintyPHP\Repository\Org\DepartmentRepositoryInterface;
|
||||
use MintyPHP\Repository\Org\UserDepartmentRepository;
|
||||
use MintyPHP\Repository\Org\UserDepartmentRepositoryInterface;
|
||||
use MintyPHP\Repository\Tenant\TenantRepository;
|
||||
use MintyPHP\Repository\Tenant\TenantRepositoryInterface;
|
||||
use MintyPHP\Repository\Tenant\UserTenantRepository;
|
||||
use MintyPHP\Repository\Tenant\UserTenantRepositoryInterface;
|
||||
use MintyPHP\Repository\User\UserListQueryRepository;
|
||||
@@ -29,9 +23,6 @@ class UserRepositoryFactory
|
||||
private ?UserWriteRepository $userWriteRepository = null;
|
||||
private ?UserListQueryRepository $userListQueryRepository = null;
|
||||
private ?UserSavedFilterRepository $userSavedFilterRepository = null;
|
||||
private ?TenantRepository $tenantRepository = null;
|
||||
private ?RoleRepository $roleRepository = null;
|
||||
private ?DepartmentRepository $departmentRepository = null;
|
||||
private ?UserTenantRepository $userTenantRepository = null;
|
||||
private ?UserRoleRepository $userRoleRepository = null;
|
||||
private ?UserDepartmentRepository $userDepartmentRepository = null;
|
||||
@@ -56,21 +47,6 @@ class UserRepositoryFactory
|
||||
return $this->userSavedFilterRepository ??= new UserSavedFilterRepository();
|
||||
}
|
||||
|
||||
public function createTenantRepository(): TenantRepositoryInterface
|
||||
{
|
||||
return $this->tenantRepository ??= new TenantRepository();
|
||||
}
|
||||
|
||||
public function createRoleRepository(): RoleRepositoryInterface
|
||||
{
|
||||
return $this->roleRepository ??= new RoleRepository();
|
||||
}
|
||||
|
||||
public function createDepartmentRepository(): DepartmentRepositoryInterface
|
||||
{
|
||||
return $this->departmentRepository ??= new DepartmentRepository();
|
||||
}
|
||||
|
||||
public function createUserTenantRepository(): UserTenantRepositoryInterface
|
||||
{
|
||||
return $this->userTenantRepository ??= new UserTenantRepository();
|
||||
|
||||
@@ -31,7 +31,8 @@ class UserServicesFactory
|
||||
private readonly UserRepositoryFactory $userRepositoryFactory,
|
||||
private readonly UserGatewayFactory $userGatewayFactory,
|
||||
private readonly DatabaseSessionRepository $databaseSessionRepository
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
public function createUserAccountService(): UserAccountService
|
||||
{
|
||||
|
||||
@@ -409,7 +409,9 @@ function appFaviconUrl(string $file): string
|
||||
*/
|
||||
function sortByDescription(array &$items): void
|
||||
{
|
||||
usort($items, static fn($a, $b) =>
|
||||
usort(
|
||||
$items,
|
||||
static fn ($a, $b) =>
|
||||
strcasecmp((string) ($a['description'] ?? ''), (string) ($b['description'] ?? ''))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,11 +18,17 @@ function gridLang(): array
|
||||
'next' => t('Next'),
|
||||
'navigate' => t('Page %d of %d'),
|
||||
'page' => t('Page %d'),
|
||||
'rowsPerPage' => t('Rows per page'),
|
||||
'showing' => t('Showing'),
|
||||
'of' => t('of'),
|
||||
'to' => t('to'),
|
||||
'results' => t('results'),
|
||||
],
|
||||
'actions' => [
|
||||
'column' => t('Actions'),
|
||||
'open' => t('Open'),
|
||||
'edit' => t('Edit'),
|
||||
],
|
||||
'loading' => t('Loading...'),
|
||||
'noRecordsFound' => t('No records found'),
|
||||
'error' => t('An error happened while fetching the data'),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Access\AuthorizationService;
|
||||
use MintyPHP\Service\Access\UserAuthorizationPolicy;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Service\AddressBook\AddressBookServicesFactory;
|
||||
use MintyPHP\Service\Access\OperationsAuthorizationPolicy;
|
||||
use MintyPHP\Service\AddressBook\AddressBookServicesFactory;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Service\Access\PermissionService;
|
||||
use MintyPHP\Service\AddressBook\AddressBookServicesFactory;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\AddressBook\AddressBookServicesFactory;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Service\Access\UiAccessService;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Service\Audit\ApiAuditService;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Service\Access\UiAccessService;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Service\Audit\ImportAuditService;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
Guard::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_ADMIN_MAIL_LOG_VIEW);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
|
||||
Guard::requireLogin();
|
||||
Guard::requireAbility(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_ADMIN_MAIL_LOG_VIEW);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Access\PermissionAuthorizationPolicy;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
$request = requestInput();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Service\Access\PermissionAuthorizationPolicy;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
gridRequireGetRequest();
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Access\PermissionAuthorizationPolicy;
|
||||
use MintyPHP\Service\Access\PermissionGateway;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Access\PermissionGateway;
|
||||
use MintyPHP\Service\Access\PermissionAuthorizationPolicy;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Service\Access\PermissionAuthorizationPolicy;
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Service\Access\RoleAuthorizationPolicy;
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Service\Access\UiAccessService;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Domain\Taxonomy\ScheduledJobRunStatus;
|
||||
use MintyPHP\Domain\Taxonomy\SchedulerRuntimeResult;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Service\Access\UiAccessService;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireAbilityOrForbidden(\MintyPHP\Service\Access\OperationsAuthorizationPolicy::ABILITY_ADMIN_STATS_VIEW);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Domain\Taxonomy\SystemAuditOutcome;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Access\OperationsAuthorizationPolicy;
|
||||
use MintyPHP\Service\Audit\SystemAuditService;
|
||||
use MintyPHP\Session;
|
||||
|
||||
@@ -21,13 +21,14 @@ $dir = $filters['dir'];
|
||||
$computedOrderKeys = ['theme', 'sso', 'active_users', 'inactive_users'];
|
||||
$userTenantRepository = app(\MintyPHP\Repository\Tenant\UserTenantRepository::class);
|
||||
$tenantMicrosoftAuthRepository = app(TenantMicrosoftAuthRepository::class);
|
||||
$tenantAvatarService = app(\MintyPHP\Service\Tenant\TenantAvatarService::class);
|
||||
$settingGateway = app(\MintyPHP\Service\Settings\SettingGateway::class);
|
||||
|
||||
$fetchRows = static function (
|
||||
array $tenantRows,
|
||||
array $themes,
|
||||
string $globalDefaultTheme
|
||||
) use ($userTenantRepository, $tenantMicrosoftAuthRepository, $settingGateway): array {
|
||||
) use ($userTenantRepository, $tenantMicrosoftAuthRepository, $tenantAvatarService, $settingGateway): array {
|
||||
$tenantIds = [];
|
||||
foreach ($tenantRows as $tenantRow) {
|
||||
$tenantId = (int) ($tenantRow['id'] ?? 0);
|
||||
@@ -69,10 +70,11 @@ $fetchRows = static function (
|
||||
$usersActive = (int) ($tenantActiveUserCounts[$tenantId] ?? 0);
|
||||
$usersInactive = max(0, $usersTotal - $usersActive);
|
||||
$tenantStatus = TenantStatus::normalizeOr((string) ($row['status'] ?? ''), TenantStatus::Active);
|
||||
$tenantUuid = (string) ($row['uuid'] ?? '');
|
||||
|
||||
$rows[] = [
|
||||
'id' => $row['id'] ?? null,
|
||||
'uuid' => $row['uuid'] ?? '',
|
||||
'uuid' => $tenantUuid,
|
||||
'is_default' => $tenantId > 0 && $defaultTenantId === $tenantId,
|
||||
'description' => $row['description'] ?? '',
|
||||
'status' => $tenantStatus->value,
|
||||
@@ -92,6 +94,7 @@ $fetchRows = static function (
|
||||
'inactive_users' => $usersInactive,
|
||||
'created' => dt($row['created'] ?? ''),
|
||||
'modified' => dt($row['modified'] ?? ''),
|
||||
'has_avatar' => $tenantUuid !== '' && $tenantAvatarService->hasAvatar($tenantUuid),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ use MintyPHP\Service\Access\TenantAuthorizationPolicy;
|
||||
use MintyPHP\Service\CustomField\TenantCustomFieldService;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
$request = requestInput();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Service\Access\TenantAuthorizationPolicy;
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ $pageConfig = [
|
||||
'filterChipMeta' => $filterChipMeta,
|
||||
'gridLang' => $gridLang,
|
||||
'labels' => [
|
||||
'avatar' => t('Avatar'),
|
||||
'description' => t('Description'),
|
||||
'status' => t('Status'),
|
||||
'theme' => t('Theme'),
|
||||
|
||||
@@ -4,8 +4,8 @@ use MintyPHP\Buffer;
|
||||
use MintyPHP\Domain\Taxonomy\UserLifecycleAction;
|
||||
use MintyPHP\Domain\Taxonomy\UserLifecycleStatus;
|
||||
use MintyPHP\Domain\Taxonomy\UserLifecycleTriggerType;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Service\Access\UiAccessService;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Service\Audit\UserLifecycleAuditService;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
Guard::requireAbility(\MintyPHP\Service\Access\SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_UPDATE);
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Domain\Taxonomy\UserLifecycleAction;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Service\Access\UiAccessService;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Support\Flash;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\I18n;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\I18n;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Access\UiAccessService;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Support\Guard;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
use MintyPHP\Buffer;
|
||||
use MintyPHP\Http\Request;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Service\Access\UiAccessService;
|
||||
use MintyPHP\Service\Access\UiCapabilityMap;
|
||||
use MintyPHP\Service\Access\UserAuthorizationPolicy;
|
||||
use MintyPHP\Session;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
@@ -51,28 +51,28 @@ if (!($emailResult['allowed'] ?? true)) {
|
||||
$userReadRepository = (app(UserServicesFactory::class))->createUserReadRepository();
|
||||
$user = $userReadRepository->findByEmail($email);
|
||||
if (!$user) {
|
||||
$rateLimiter->registerFailure('api.auth.login.ip', $ip, 10, 600, 300);
|
||||
$rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey, 5, 900, 900);
|
||||
$rateLimiter->registerFailure('api.auth.login.ip', $ip, 10, 600, 300);
|
||||
$rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey, 5, 900, 900);
|
||||
ApiResponse::error('invalid_credentials', 401);
|
||||
}
|
||||
|
||||
// ---- Account checks ----
|
||||
if (!(int) ($user['active'] ?? 0)) {
|
||||
$rateLimiter->registerFailure('api.auth.login.ip', $ip, 10, 600, 300);
|
||||
$rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey, 5, 900, 900);
|
||||
$rateLimiter->registerFailure('api.auth.login.ip', $ip, 10, 600, 300);
|
||||
$rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey, 5, 900, 900);
|
||||
ApiResponse::error('account_inactive', 401);
|
||||
}
|
||||
|
||||
if (empty($user['email_verified_at'])) {
|
||||
$rateLimiter->registerFailure('api.auth.login.ip', $ip, 10, 600, 300);
|
||||
$rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey, 5, 900, 900);
|
||||
$rateLimiter->registerFailure('api.auth.login.ip', $ip, 10, 600, 300);
|
||||
$rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey, 5, 900, 900);
|
||||
ApiResponse::error('invalid_credentials', 401);
|
||||
}
|
||||
|
||||
// ---- Password verification ----
|
||||
if (!password_verify($password, (string) ($user['password'] ?? ''))) {
|
||||
$rateLimiter->registerFailure('api.auth.login.ip', $ip, 10, 600, 300);
|
||||
$rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey, 5, 900, 900);
|
||||
$rateLimiter->registerFailure('api.auth.login.ip', $ip, 10, 600, 300);
|
||||
$rateLimiter->registerFailure('api.auth.login.email_ip', $emailKey, 5, 900, 900);
|
||||
ApiResponse::error('invalid_credentials', 401);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user