From 1c45642789e9da5199bfc4c974c67372cbf6372e Mon Sep 17 00:00:00 2001 From: panabonic Date: Wed, 30 Aug 2023 15:57:32 +0300 Subject: [PATCH] fixes and updates by list from 29.08.2023 --- .../Controllers/Api/Pages/PagesController.php | 8 ++ app/Models/Pages/Page.php | 35 +++++++ app/Models/Registries/RegistryType.php | 1 + app/Models/User.php | 4 + app/Services/Forms/Pages/PageForms.php | 97 +++++++++++++++++++ .../Forms/Pages/PageFormsServices.php | 1 + app/Services/Forms/Registries/EntryForms.php | 2 +- .../Registries/RegistryImportService.php | 5 + .../TechnicalCertificatesImportService.php | 40 ++++++++ ...1_195350_create_registry_entries_table.php | 2 +- database/seeders/Pages/PagesTableSeeder.php | 21 ++-- database/seeders/Users/UsersTableSeeder.php | 6 +- routes/api.php | 4 + routes/console.php | 14 ++- 14 files changed, 222 insertions(+), 18 deletions(-) create mode 100644 app/Services/Forms/Pages/PageForms.php create mode 100644 app/Services/Registries/TechnicalCertificatesImportService.php diff --git a/app/Http/Controllers/Api/Pages/PagesController.php b/app/Http/Controllers/Api/Pages/PagesController.php index b21b466..a410139 100644 --- a/app/Http/Controllers/Api/Pages/PagesController.php +++ b/app/Http/Controllers/Api/Pages/PagesController.php @@ -45,6 +45,14 @@ class PagesController extends Controller { return fractal($model, new PageTransformer())->respond(); } + public function move(Request $request, $id): JsonResponse { + $model = $this->model->byUuid($id)->firstOrFail(); + $parent = Page::byUuid($request->get('parent'))->first(); + $model->move($request->get('ord'), $parent); + return fractal($model, new PageTransformer())->respond(); + } + + public function store(Request $request): void { } diff --git a/app/Models/Pages/Page.php b/app/Models/Pages/Page.php index c3c86e5..f698192 100644 --- a/app/Models/Pages/Page.php +++ b/app/Models/Pages/Page.php @@ -47,6 +47,10 @@ class Page extends Model { return $this->hasMany(Page::class, 'parent_id')->orderBy('ord'); } + public function siblings(): HasMany { + return $this->hasMany(Page::class, 'parent_id', 'parent_id'); + } + public function sections(): MorphToMany { return $this->objects()->wherePivot('group', '=', 'sections'); } @@ -124,6 +128,37 @@ class Page extends Model { return null; } + + public function move($ord, ?Page $parent = null) { + $prevParent = $this->parent; + if (($parent->id ?? 0) === ($prevParent->id ?? 0)) { + ($ord > $this->ord) ? $this->moveSet('backward', $this->ord, $ord, $parent) : $this->moveSet('forward', $ord, $this->ord, $parent); + } else $this->moveSet('forward', $ord, null, $parent); + $this->update(['parent_id' => $parent->id ?? 0, 'ord' => $ord]); + $this->trimIndexes([$prevParent->id ?? 0, $parent->id ?? 0]); + } + public function moveSet($dir = 'forward', $ordFrom = null, $ordTo = null, ?Page $parent = null) { + $query = Page::query()->where(['parent_id' => $parent->id ?? 0])->orderBy('ord'); + if ($ordFrom !== null) $query->where('ord', '>=', $ordFrom); + if ($ordTo !== null) $query->where('ord', '<=', $ordTo); + $query->get()->each(function($page) use($dir) { + $page->update(['ord' => ($dir === 'forward') ? ($page->ord + 1) : ($page->ord - 1)]); + }); + } + public function trimIndexes($parentIds) { + collect(is_array($parentIds) ? $parentIds : [$parentIds])->unique()->each(function($parentId) { + Page::query()->where(['parent_id' => $parentId])->orderBy('ord')->orderBy('id')->get()->each(function($page, $index) { + if ($page->ord !== $index) $page->update(['ord' => $index]); + }); + }); + } + + public function getMaxOrd(): int { + $res = $this->siblings()->max('ord'); + return ($res !== null) ? ($res + 1) : 0; + } + + public static function root() { return self::query()->where(['parent_id' => 0])->orderBy('ord')->get(); } diff --git a/app/Models/Registries/RegistryType.php b/app/Models/Registries/RegistryType.php index 6478a78..d187ba7 100644 --- a/app/Models/Registries/RegistryType.php +++ b/app/Models/Registries/RegistryType.php @@ -19,6 +19,7 @@ class RegistryType { public const TITLES = [ self::SIMPLE => 'Простой реестр', + self::CATEGORIZED => 'Простой категоризированный реестр', self::RULESET => 'Реестр сводов правил', self::LABORATORIES => 'Реестр испытательных лабораторий', self::CERTIFIERS => 'Реестр органов по сертификации', diff --git a/app/Models/User.php b/app/Models/User.php index 42207a8..2c10290 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -95,6 +95,9 @@ class User extends Authenticatable { public function getIsAdminAttribute(): bool { return $this->hasRole('Administrator') || $this->isMainCompanyAdmin; } + public function getIsSuperAdminAttribute(): bool { + return $this->hasRole('Administrator'); + } public function getIsModeratorAttribute(): bool { return $this->membership()->where(['role' => CompanyMemberRole::MODERATOR])->mainCompany()->exists(); } @@ -112,6 +115,7 @@ class User extends Authenticatable { public function getPrivilegesAttribute(): array { return [ + 'super_admin' => $this->isSuperAdmin, 'admin' => $this->isAdmin, 'expert' => $this->isExpert, 'main_company_member' => $this->isMainCompanyMember diff --git a/app/Services/Forms/Pages/PageForms.php b/app/Services/Forms/Pages/PageForms.php new file mode 100644 index 0000000..dfdc6fe --- /dev/null +++ b/app/Services/Forms/Pages/PageForms.php @@ -0,0 +1,97 @@ + 'Создание страницы', 'update' => 'Редактирование страницы']; + + public function form(?string $id = null, array $data = []): array { + $model = Page::byUuid($id)->first(); + $groups = [ + [ + 'name' => 'common', 'fields' => $this->commonGroupFields($model), + 'dynamic' => [ + ['field' => 'type', 'hide' => ['registry_type', 'subtype']], + ['field' => 'type', 'value' => PageType::REGISTRY, 'show' => ['registry_type']], + ['field' => 'type', 'value' => PageType::PUBLICATIONS, 'show' => ['subtype']] + ] + + ] + ]; + return ['title' => $this->formTitle($model), 'data' => $groups]; + } + + public function commonGroupFields(?Page $model): array { + $fields = [ + [ + 'name' => 'name', + 'title' => 'Название', + 'type' => FieldType::STRING, + 'required' => true, + 'value' => $model->name ?? null + ], + [ + 'name' => 'slug', + 'title' => 'Адрес', + 'type' => FieldType::STRING, + 'hidden' => !$model, + 'value' => $model->slug ?? null + ], + [ + 'name' => 'type', + 'title' => 'Вид', + 'type' => FieldType::RELATION, + 'required' => true, + 'options' => $this->getRelationItems(PageType::TITLES), + 'value' => $this->getRelationValue(PageType::TITLES, $model->type ?? null) + ], + [ + 'name' => 'registry_type', + 'title' => 'Вид реестра', + 'type' => FieldType::RELATION, + 'required' => true, + 'options' => $this->getRelationItems(RegistryType::TITLES), + 'value' => $this->getRelationValue(RegistryType::TITLES, $model->registry->type ?? null) + ], + [ + 'name' => 'subtype', + 'title' => 'Вид публикации', + 'type' => FieldType::RELATION, + 'required' => true, + 'options' => $this->getRelationItems(PageSubType::TITLES), + 'value' => $this->getRelationValue(PageSubType::TITLES, $model->sub_type ?? null) + ] + ]; + return ['data' => $fields]; + } + + + + public function store(array $data): ?JsonResponse { + $parent = Page::byUuid($data['parent'] ?? null)->first(); + $data['parent_id'] = $parent->id ?? 0; + $data['slug'] = $data['slug'] ?? Str::slug(Str::transliterate($data['name'] ?? null)); + $model = Page::create($data); + $model->update(['ord' => $model->getMaxOrd()]); + if ($model->type === PageType::REGISTRY) $model->registry->update(['type' => $data['registry_type'] ?? RegistryType::SIMPLE]); + return fractal($model, new PageTransformer())->respond(); + } + + public function update(string $id, array $data): ?JsonResponse { + $model = Page::byUuid($id)->firstOrFail(); + $data['slug'] = $data['slug'] ?? Str::slug(Str::transliterate($data['name'] ?? null)); + $model->update($data); + if ($model->type === PageType::REGISTRY) $model->registry->update(['type' => $data['registry_type'] ?? RegistryType::SIMPLE]); + return fractal($model->fresh(), new PageTransformer())->respond(); + } +} diff --git a/app/Services/Forms/Pages/PageFormsServices.php b/app/Services/Forms/Pages/PageFormsServices.php index 74cb4b0..548869d 100644 --- a/app/Services/Forms/Pages/PageFormsServices.php +++ b/app/Services/Forms/Pages/PageFormsServices.php @@ -4,5 +4,6 @@ namespace App\Services\Forms\Pages; class PageFormsServices { public static array $services = [ + 'page' => PageForms::class ]; } diff --git a/app/Services/Forms/Registries/EntryForms.php b/app/Services/Forms/Registries/EntryForms.php index eb1a0dc..c5d7e75 100644 --- a/app/Services/Forms/Registries/EntryForms.php +++ b/app/Services/Forms/Registries/EntryForms.php @@ -42,7 +42,7 @@ class EntryForms extends FormsService { ], [ 'name' => 'number', - 'title' => 'Номер записи', + 'title' => 'Номер документа', 'type' => FieldType::STRING, 'value' => $model->number ?? null ], diff --git a/app/Services/Registries/RegistryImportService.php b/app/Services/Registries/RegistryImportService.php index c5812c1..c1d0019 100644 --- a/app/Services/Registries/RegistryImportService.php +++ b/app/Services/Registries/RegistryImportService.php @@ -5,6 +5,7 @@ namespace App\Services\Registries; use App\Models\Asset; use App\Models\Registries\Registry; use App\Services\Documents\DocumentDownloadService; +use Illuminate\Support\Str; use PHPHtmlParser\Dom; class RegistryImportService { @@ -28,6 +29,10 @@ class RegistryImportService { public function download($url, $dir = null, $filename = null): ?Asset { + $info = parse_url($url); + if (empty($info['host'])) { + $url = 'https://' . Str::replace('//', '/', "www.faufcc.ru/{$url}"); + } return (new DocumentDownloadService())->download($url, $dir, $filename); } diff --git a/app/Services/Registries/TechnicalCertificatesImportService.php b/app/Services/Registries/TechnicalCertificatesImportService.php new file mode 100644 index 0000000..38b3c77 --- /dev/null +++ b/app/Services/Registries/TechnicalCertificatesImportService.php @@ -0,0 +1,40 @@ +registry); + } + + public function import() { + $nodes = $this->dom->find('table tbody tr')->toArray(); + foreach ($nodes as $node) { + list($product_name, $product_purpose, $producer, $links, $active_since, $active_till) = $node->find('td')->toArray(); + $number = null; + $asset = null; + $conclusionAsset = null; + $active_since = $active_since->text ? Date::create($active_since->text) : null; + $active_till = $active_till->text ? Date::create($active_till->text) : null; + foreach ($links->find('a')->toArray() as $link) { + if (trim($link->text) === 'Техническое заключение') { + $conclusionAsset = $this->download($link->href, 'registries/ts/conclusions'); + } else { + $number = $link->text; + $asset = $this->download($link->href, 'registries/ts/certificates'); + } + } + if (!$number) $number = trim($links->text); + $entry = $this->registry->entries()->firstOrCreate(['name' => trim($product_name->text), 'category_id' => 0]); + $entry->update(['number' => $number, 'asset_id' => $asset->id ?? null, 'active_since' => $active_since, 'active_till' => $active_till]); + $data = ['developer-name' => Str::limit(Str::replace('"', '"', trim($producer->text)), 495), 'product-purpose' => trim($product_purpose->text), 'technical-conclusion' => $conclusionAsset]; + $entry->properties->setValues($data); + } + } + + +} \ No newline at end of file diff --git a/database/migrations/2023_06_21_195350_create_registry_entries_table.php b/database/migrations/2023_06_21_195350_create_registry_entries_table.php index f3934ec..87dd49b 100644 --- a/database/migrations/2023_06_21_195350_create_registry_entries_table.php +++ b/database/migrations/2023_06_21_195350_create_registry_entries_table.php @@ -17,7 +17,7 @@ class CreateRegistryEntriesTable extends Migration $table->id(); $table->char('uuid', 36)->index()->unique(); $table->integer('registry_id')->index()->nullable(); - $table->integer('category_id')->index()->nullable(); + $table->integer('category_id')->index()->default(0); $table->integer('asset_id')->index()->nullable(); $table->string('number')->index()->nullable(); $table->string('name', 750)->index()->nullable(); diff --git a/database/seeders/Pages/PagesTableSeeder.php b/database/seeders/Pages/PagesTableSeeder.php index bffefb8..48db869 100644 --- a/database/seeders/Pages/PagesTableSeeder.php +++ b/database/seeders/Pages/PagesTableSeeder.php @@ -9,8 +9,7 @@ use App\Models\Registries\RegistryType; use Illuminate\Database\Seeder; use Illuminate\Support\Str; -class PagesTableSeeder extends Seeder -{ +class PagesTableSeeder extends Seeder { public array $pages = [ 'О центре' => [ 'children' => [ @@ -143,17 +142,17 @@ class PagesTableSeeder extends Seeder ] ]; - public function run() - { - $ord = 0; - collect($this->pages)->each(function ($data, $name) use (&$ord) { - $data['ord'] = $ord++; - $this->importPage($name, $data); - }); + public function run() { + if (!Page::query()->count()) { + $ord = 0; + collect($this->pages)->each(function ($data, $name) use (&$ord) { + $data['ord'] = $ord++; + $this->importPage($name, $data); + }); + } } - public function importPage($name, $data, ?Page $parent = null) - { + public function importPage($name, $data, ?Page $parent = null) { $slug = Str::slug(Str::transliterate($name)); $data += ['type' => $data['type'] ?? PageType::CONTENT, 'name' => $name]; $page = Page::firstOrCreate(['parent_id' => $parent->id ?? 0, 'slug' => $slug]); diff --git a/database/seeders/Users/UsersTableSeeder.php b/database/seeders/Users/UsersTableSeeder.php index 141a6d5..c50cebc 100644 --- a/database/seeders/Users/UsersTableSeeder.php +++ b/database/seeders/Users/UsersTableSeeder.php @@ -11,10 +11,7 @@ class UsersTableSeeder extends Seeder { ]; public array $admins = [ - ['email' => 'shyctpuk@mail.ru', 'name' => 'Константин Митрофанов'], - ['email' => 'n.astashkevich@gmail.com', 'name' => 'Николай Асташкевич'], - ['email' => 'sergey@bodin.ru', 'name' => 'Сергей Бодин'], - ['email' => 'test@test.ru', 'name' => 'Иван Иванов'] + ['email' => 'admin@test.ru', 'name' => 'Админ Админович Админов', 'password' => 'DybgEs'] ]; @@ -34,6 +31,7 @@ class UsersTableSeeder extends Seeder { if ($user = User::where(['email' => $email])->first()) $user->update($data); else $user = User::factory()->create($data); $user->assignRole($role); + if ($password = $data['password'] ?? null) $user->setPassword($password); } }); } diff --git a/routes/api.php b/routes/api.php index e263bda..feb48d5 100644 --- a/routes/api.php +++ b/routes/api.php @@ -23,6 +23,10 @@ Route::group(['prefix' => 'pages'], function() { Route::get('/root', 'Api\Pages\PagesController@root'); Route::get('/find', 'Api\Pages\PagesController@find'); Route::get('/{id}', 'Api\Pages\PagesController@show'); + Route::group(['middleware' => ['auth:api']], function() { + Route::put('/{id}', 'Api\Pages\PagesController@move'); + Route::delete('/{id}', 'Api\Pages\PagesController@destroy'); + }); }); Route::group(['prefix' => 'publications'], function() { diff --git a/routes/console.php b/routes/console.php index c173a09..05c5c16 100644 --- a/routes/console.php +++ b/routes/console.php @@ -1,6 +1,5 @@ where(['type' => RegistryType::TECHNICAL_CERTIFICATES])->first(); + $url = 'https://www.faufcc.ru/_deyatelnost/_otsenka-prigodnosti/_reestr-tekhnicheskikh-svidetelstv/?PAGEN_1='; + + for ($i = 1; $i <= 44; $i++) { + echo "Parsing page {$i}\n"; + $service = new \App\Services\Registries\TechnicalCertificatesImportService($registry, "{$url}{$i}"); + $service->import(); + } + + +}); +