diff --git a/DATABASE_STRUCTURE.md b/DATABASE_STRUCTURE.md index 6a7837e..0253566 100644 --- a/DATABASE_STRUCTURE.md +++ b/DATABASE_STRUCTURE.md @@ -159,3 +159,27 @@ Tlumaczenia jednostek (per jezyk). | text | Nazwa jednostki | **Używane w:** `Domain\Dictionaries\DictionariesRepository` + +## pp_users +Uzytkownicy panelu administratora. + +| Kolumna | Opis | +|---------|------| +| id | PK | +| login | Login / e-mail uzytkownika | +| password | Hash hasla (legacy: md5) | +| status | Status konta: 1 = aktywny, 0 = zablokowany | +| admin | Flaga dostepu do panelu admin | +| error_logged_count | Licznik nieudanych logowan | +| last_logged | Data ostatniego poprawnego logowania | +| last_error_logged | Data ostatniej nieudanej proby logowania | +| twofa_enabled | Czy wlaczone 2FA (0/1) | +| twofa_email | E-mail do wysylki kodu 2FA | +| twofa_code_hash | Hash aktualnego kodu 2FA | +| twofa_expires_at | Data waznosci kodu 2FA | +| twofa_sent_at | Data ostatniej wysylki kodu 2FA | +| twofa_failed_attempts | Liczba nieudanych prob 2FA | + +**Uzywane w:** `Domain\User\UserRepository`, `admin\Controllers\UsersController`, `admin\factory\Users` + +**Aktualizacja 2026-02-12:** uzycia `pp_users` sa prowadzone przez `Domain\\User\\UserRepository` (legacy `admin\\factory\\Users` usunieto). diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md index dcb303e..b6b27f7 100644 --- a/PROJECT_STRUCTURE.md +++ b/PROJECT_STRUCTURE.md @@ -199,7 +199,8 @@ autoload/ │ ├── Controllers/ # Nowe kontrolery (namespace \admin\Controllers\) │ │ ├── BannerController.php # DI, instancyjny │ │ ├── SettingsController.php # DI, instancyjny (clearCache, save, view) -│ │ └── ProductArchiveController.php # DI, instancyjny (list, unarchive) +│ │ ├── ProductArchiveController.php # DI, instancyjny (list, unarchive) +│ │ └── UsersController.php # DI, instancyjny (view_list, user_edit, user_save, user_delete, login_form, twofa) │ ├── class.Site.php # Router: nowy kontroler → fallback stary │ ├── controls/ # Stare kontrolery (niezależny fallback) │ ├── factory/ # Stare helpery (niezależny fallback) @@ -210,7 +211,8 @@ autoload/ #### Aktualny stan migracji (uzupełnienie) - Dodane repozytorium: `Domain\Dictionaries\DictionariesRepository` -- Dodane kontrolery DI: `admin\Controllers\DictionariesController`, `admin\Controllers\FilemanagerController` +- Dodane kontrolery DI: `admin\Controllers\DictionariesController`, `admin\Controllers\FilemanagerController`, `admin\Controllers\UsersController` +- Dodane repozytorium: `Domain\User\UserRepository` - `Domain\Settings\SettingsRepository` działa bezpośrednio na DB (bez delegacji do `admin\factory\Settings`) ### Routing admin (admin\Site::route()) @@ -254,8 +256,8 @@ tests/ │ └── ProductArchiveControllerTest.php # 6 testów └── Integration/ ``` -Aktualnie w suite są też testy modułów `Dictionaries` i `Articles` (repozytoria + kontrolery DI). -**Łącznie: 82 tests, 181 assertions** +Aktualnie w suite są też testy modułów `Dictionaries`, `Articles` i `Users` (repozytoria + kontrolery DI). +**Łącznie: 119 tests, 256 assertions** ## Ostatnie modyfikacje @@ -368,5 +370,24 @@ Aktualnie w suite są też testy modułów `Dictionaries` i `Articles` (repozyto - Metoda `clear_product_cache()` w klasie S --- -*Dokument aktualizowany: 2026-02-10* +*Dokument aktualizowany: 2026-02-12* + +### 2026-02-12: Migracja Users (/admin/users) (ver. 0.253) +- **NOWE:** `Domain\User\UserRepository` - repozytorium uzytkownikow (CRUD, check_login, logon, details, 2FA) +- **NOWE:** `admin\Controllers\UsersController` - kontroler DI dla akcji `view_list`, `user_edit`, `user_save`, `user_delete`, `login_form`, `twofa` +- **UPDATE:** `admin\Site` - dodany factory wpis dla modulu `Users` w mapie nowych kontrolerow +- **UPDATE:** `admin\factory\Users` - fasada deleguje logike do `Domain\User\UserRepository` +- **UPDATE:** `admin/ajax/users.php` - `check_login` korzysta bezposrednio z `UserRepository` +- **CLEANUP:** usuniety `autoload/admin/controls/class.Users.php` (brak fallback - nowy kontroler obsluguje wszystkie akcje) +- Testy: 119 tests, 256 assertions + +--- +*Dokument aktualizowany: 2026-02-12* +- **UPDATE:** widoki Users przeniesione z `grid/gridEdit` na `components/table-list` i `components/form-edit` + +## Aktualizacja 2026-02-12 (finalizacja Users) +- Modu users dziaa na `Domain\\User\\UserRepository` + `admin\\Controllers\\UsersController`. +- Usunito legacy klasy: `autoload/admin/controls/class.Users.php`, `autoload/admin/factory/class.Users.php`, `autoload/admin/view/class.Users.php`. +- Walidacja: przy wczonym 2FA pole `twofa_email` jest wymagane. +- Widoki users przeniesione na `components/table-list` i `components/form-edit`. diff --git a/REFACTORING_PLAN.md b/REFACTORING_PLAN.md index 003b647..63377ff 100644 --- a/REFACTORING_PLAN.md +++ b/REFACTORING_PLAN.md @@ -250,6 +250,16 @@ grep -r "Product::getQuantity" . - Legacy cleanup: usunięto `autoload/admin/controls/class.Filemanager.php` i `autoload/admin/view/class.FileManager.php` - Aktualizacja: ver. 0.252 +- **Users** (migracja kontrolera i repozytorium) + - ✅ UserRepository - **ZMIGROWANE** (2026-02-12) 🎉 + - Nowa klasa: `Domain\User\UserRepository` (find, getById, save, delete, checkLogin, logon, details, updateById, sendTwofaCode, verifyTwofaCode) + - Nowy kontroler: `admin\Controllers\UsersController` (DI, instancyjny: view_list, user_edit, user_save, user_delete, login_form, twofa) + - Router: `admin\Site` - factory wpis dla modulu `Users` + - Fasada: `admin\factory\Users` deleguje do repozytorium (backward compatibility dla login/2FA flow) + - AJAX: `admin/ajax/users.php` - `check_login` oparty o `UserRepository` + - Legacy cleanup: usuniety `autoload/admin/controls/class.Users.php` + - Testy: 25 testow repozytorium (CRUD, logon, 2FA, checkLogin) + 12 testow kontrolera (kontrakty + normalizeUser) + ### 📋 Do zrobienia - Order - Category @@ -275,16 +285,18 @@ tests/ │ │ ├── Cache/CacheRepositoryTest.php │ │ ├── Dictionaries/DictionariesRepositoryTest.php │ │ ├── Product/ProductRepositoryTest.php -│ │ └── Settings/SettingsRepositoryTest.php +│ │ ├── Settings/SettingsRepositoryTest.php +│ │ └── User/UserRepositoryTest.php │ └── admin/ │ └── Controllers/ │ ├── ArticlesControllerTest.php │ ├── DictionariesControllerTest.php │ ├── ProductArchiveControllerTest.php -│ └── SettingsControllerTest.php +│ ├── SettingsControllerTest.php +│ └── UsersControllerTest.php └── Integration/ ``` -**Łącznie: 82 testów, 181 asercji** +**Łącznie: 119 testów, 256 asercji** ### Przykład testu ```php @@ -368,10 +380,11 @@ vendor/bin/phpstan analyse autoload/Domain 5. **Dictionaries** ✅ (repo + kontroler + form/table, ver. 0.251) 6. **ProductArchive** ✅ (migracja kontrolera + cleanup szablonów, ver. 0.252) 7. **Filemanager** ✅ (migracja routingu + fix `Invalid Key`, ver. 0.252) -8. **Order** -9. **Category** -10. **ShopAttribute** -11. **Pages** (`browse_list` i powiązane widoki nadal legacy) +8. **Users** ✅ (repo + kontroler + 2FA + legacy cleanup, ver. 0.253) +9. **Order** +10. **Category** +11. **ShopAttribute** +12. **Pages** (`browse_list` i powiązane widoki nadal legacy) - **Form Edit System** - Nowy uniwersalny system formularzy edycji - ✅ Klasy ViewModel: `FormFieldType`, `FormField`, `FormTab`, `FormAction`, `FormEditViewModel` @@ -386,7 +399,7 @@ vendor/bin/phpstan analyse autoload/Domain --- *Rozpoczęto: 2025-02-05* -*Ostatnia aktualizacja: 2026-02-10* +*Ostatnia aktualizacja: 2026-02-12* ## Form Edit System - Dokumentacja użycia @@ -544,3 +557,20 @@ Gdy `persist = true`: 3. **Szablon** - usuń stary szablon lub zostaw jako fallback 4. **Testy** - zaktualizuj testy jeśli zmienił się format danych + +## Aktualizacja 2026-02-12 - Users + +### Users (migracja kontrolera i repozytorium) +- **NOWE:** `Domain\User\UserRepository` (delete, find, save, checkLogin, logon, details, sendTwofaCode, verifyTwofaCode) +- **NOWE:** `admin\Controllers\UsersController` (view_list, user_edit, user_save, user_delete) +- **UPDATE:** Router `admin\Site` - nowy kontroler DI dla modu�u `Users` +- **UPDATE:** `admin\factory\Users` jako fasada delegujaca do repozytorium +- **UPDATE:** `admin/ajax/users.php` - endpoint `check_login` oparty o `UserRepository` +- Testy po zmianie: 95 tests, 204 assertions +- **UPDATE:** UsersController: `view_list` + `user_edit` migrowane na nowy system list/form (table-list + form-edit) + +## Aktualizacja 2026-02-12 (finalizacja Users) +- Users: pelna migracja na nowa architekture (Domain + DI Controller), bez fallbacku do legacy kontrolera/factory/view. +- `UsersController` obsluguje: `list/view_list`, `user_edit`, `user_save`, `user_delete`, `login_form`, `twofa`. +- Dodano walidacje warunkowa: `twofa_email` wymagany gdy `twofa_enabled = 1`. +- Widoki users migrowane z `grid/gridEdit` na `table-list` i `form-edit`. diff --git a/TESTING.md b/TESTING.md index 501ceb1..0a94d8b 100644 --- a/TESTING.md +++ b/TESTING.md @@ -51,13 +51,15 @@ tests/ | | |-- Cache/CacheRepositoryTest.php | | |-- Dictionaries/DictionariesRepositoryTest.php | | |-- Product/ProductRepositoryTest.php -| | `-- Settings/SettingsRepositoryTest.php +| | |-- Settings/SettingsRepositoryTest.php +| | `-- User/UserRepositoryTest.php | `-- admin/ | `-- Controllers/ | |-- ArticlesControllerTest.php | |-- DictionariesControllerTest.php | |-- ProductArchiveControllerTest.php -| `-- SettingsControllerTest.php +| |-- SettingsControllerTest.php +| `-- UsersControllerTest.php `-- Integration/ ``` @@ -138,3 +140,27 @@ $this->assertEquals(42, $value); - Konfiguracja PHPUnit: `phpunit.xml` - Bootstrap testow: `tests/bootstrap.php` - Dodatkowy opis: `tests/README.md` + +## Aktualizacja suite + +Ostatnio zweryfikowano: 2026-02-12 + +```text +OK (119 tests, 256 assertions) +``` + +Nowe testy dodane 2026-02-12: +- `tests/Unit/Domain/User/UserRepositoryTest.php` (25 testow: CRUD, logon, 2FA verify/send, checkLogin, updateById) +- `tests/Unit/admin/Controllers/UsersControllerTest.php` (12 testow: kontrakty + normalizeUser) + +Aktualizacja po migracji widokow Users (2026-02-12): +```text +OK (120 tests, 262 assertions) +``` + +## Aktualizacja suite (finalizacja Users) +Ostatnio zweryfikowano: 2026-02-12 + +```text +OK (120 tests, 262 assertions) +``` diff --git a/admin/ajax/users.php b/admin/ajax/users.php index 7ab9339..72ed241 100644 --- a/admin/ajax/users.php +++ b/admin/ajax/users.php @@ -3,7 +3,9 @@ $a = \S::get( 'a' ); if ( $a == 'check_login' ) { - $response = \admin\factory\Users::check_login( \S::get( 'login' ), \S::get( 'user_id' ) ); + global $mdb; + $repository = new \Domain\User\UserRepository( $mdb ); + $response = $repository->checkLogin( (string)\S::get( 'login' ), (int)\S::get( 'user_id' ) ); echo json_encode( $response ); exit; -} \ No newline at end of file +} diff --git a/admin/index.php b/admin/index.php index f1c24bf..f621ef0 100644 --- a/admin/index.php +++ b/admin/index.php @@ -97,6 +97,7 @@ $cookie_name = 'admin_remember_' . str_replace( '.', '-', $domain ); if ( isset( $_COOKIE[$cookie_name] ) && !isset( $_SESSION['user'] ) ) { + $users = new \Domain\User\UserRepository($mdb); $payload = base64_decode($_COOKIE[$cookie_name]); if ($payload !== false && strpos($payload, '.') !== false) { @@ -114,7 +115,7 @@ if ( isset( $_COOKIE[$cookie_name] ) && !isset( $_SESSION['user'] ) ) $user_data = $mdb->get('pp_users', '*', ['AND' => ['login' => $data['login'], 'status' => 1]]); if ($user_data) { - \S::set_session('user', \admin\factory\Users::details($data['login'])); + \S::set_session('user', $users->details($data['login'])); $redirect = $_SERVER['REQUEST_URI'] ?: '/admin/articles/view_list/'; header('Location: ' . $redirect); exit; @@ -135,4 +136,4 @@ if ( isset( $_COOKIE[$cookie_name] ) && !isset( $_SESSION['user'] ) ) } echo \admin\view\Page::show(); -?> \ No newline at end of file +?> diff --git a/admin/templates/components/table-list.php b/admin/templates/components/table-list.php index dac32c2..ddb168b 100644 --- a/admin/templates/components/table-list.php +++ b/admin/templates/components/table-list.php @@ -18,6 +18,21 @@ $page = max(1, (int)($list->pagination['page'] ?? 1)); $totalPages = max(1, (int)($list->pagination['total_pages'] ?? 1)); $total = (int)($list->pagination['total'] ?? 0); $perPage = (int)($list->pagination['per_page'] ?? 15); + +$isCompactColumn = function(array $column): bool { + $key = strtolower(trim((string)($column['key'] ?? ''))); + $label = strtolower(trim((string)($column['label'] ?? ''))); + + if (in_array($key, ['status', 'active', 'enabled', 'is_active'], true)) { + return true; + } + + if (in_array($label, ['status', 'aktywny', 'aktywnosc', 'active'], true)) { + return true; + } + + return false; +}; ?>