From: Vincent Vanwaelscappel Date: Mon, 5 Dec 2022 14:35:14 +0000 (+0100) Subject: wip #5625 @2 X-Git-Url: http://git.cubedesigners.com/?a=commitdiff_plain;h=497cd7adee7a43da4e4c5b5a06930cbcc43e2fd1;p=fluidbook-toolbox.git wip #5625 @2 --- diff --git a/app/Fields/CubedesignersTeamMember.php b/app/Fields/CubedesignersTeamMember.php new file mode 100644 index 000000000..0e4a5e616 --- /dev/null +++ b/app/Fields/CubedesignersTeamMember.php @@ -0,0 +1,8 @@ +hasPermissionTo(static::$_permissionBase . ':admin')) { + return; + } + if (null === static::$_ownerAttribute) { + return; + } + $builder->where(static::$_ownerAttribute, backpack_user()->id); + } +} diff --git a/app/Models/Base/ToolboxModel.php b/app/Models/Base/ToolboxModel.php index 2da7996da..e14fc23b8 100644 --- a/app/Models/Base/ToolboxModel.php +++ b/app/Models/Base/ToolboxModel.php @@ -53,7 +53,7 @@ class ToolboxModel extends CubistMagicAbstractModel return true; } - public function addOwnerField($tab = null) + public function addOwnerField($options = []) { $fieldSettings = [ 'name' => static::$_ownerAttribute, @@ -67,10 +67,8 @@ class ToolboxModel extends CubistMagicAbstractModel 'default' => Auth::id(), 'non_default_tracking' => false, ]; - if (null !== $tab) { - $fieldSettings['tab'] = $tab; - } - $this->addField($fieldSettings); + + $this->addField(array_merge($fieldSettings, $options)); } public function addColumnDateFields($tab = null, $type = HiddenDatetime::class) diff --git a/app/Models/CubedesignersEmails.php b/app/Models/CubedesignersEmails.php deleted file mode 100644 index 6b0726bf9..000000000 --- a/app/Models/CubedesignersEmails.php +++ /dev/null @@ -1,175 +0,0 @@ - 'cubemails', - 'singular' => 'paramètre', - 'plural' => 'paramètres', - 'oneinstance' => true]; - - - public function setFields() - { - parent::setFields(); - - $this->addField('domains', Table::class, __('Domaines'), ['entity_singular' => __('un domaine'), 'columns' => ['domaine' => __('Domaine')], 'translatable' => false, 'tab' => __('Comptes et redirections')]); - $this->addField('mailboxes', Table::class, __('Boîtes mail'), ['entity_singular' => __('une boîte mail'), 'columns' => ['mailbox' => __('E-mail'), 'password' => __('Mot de passe')], 'translatable' => false, 'hint' => __('Laisser le mot de passe vide pour utiliser celui du compte "Toolbox"'), 'tab' => __('Comptes et redirections')]); - $this->addField('aliases', Table::class, __('Redirections'), ['entity_singular' => __('une redirection'), 'columns' => ['from' => __('Alias'), 'dest' => __('Destinations')], 'translatable' => false, 'tab' => __('Comptes et redirections')]); - $this->addField('ip_whitelist', Table::class, __('Liste blanche IP'), ['tab' => __('Listes blanches et noires'), 'entity_singular' => __('une IP'), 'columns' => ['ip' => __('IP ou nom d\'hôte')], 'translatable' => false, 'hint' => __('IP qui sont sur la liste blanche (fail2ban, my_networks)')]); - $this->addField('postgrey_whitelist', Code::class, __('Liste blanche postgrey'), ['translatable' => false, 'tab' => __('Listes blanches et noires'), 'language' => 'properties', 'hint' => __('Serveurs ignorés par le Grey listing')]); - $this->addField('spam_whitelist', Table::class, __('Liste blanche SPAM'), ['tab' => __('Listes blanches et noires'), 'entity_singular' => __('un e-mail'), 'columns' => ['email' => __('E-mail')], 'translatable' => false, 'hint' => __('Les e-mails provenant de ces expéditeurs ne sont jamais considérés comme des spam (expressions régulières possibles)')]); - $this->addField('spam_blacklist', Table::class, __('Liste noire SPAM'), ['tab' => __('Listes blanches et noires'), 'entity_singular' => __('un e-mail'), 'columns' => ['email' => __('E-mail')], 'translatable' => false, 'hint' => __('Ces e-mails sont toujours considérés comme des spam (expressions régulières possibles)')]); - - } - - public function preSave() - { - - $maindomain = 'cubedesigners.com'; - - $mailboxes = json_decode($this->mailboxes, true); - $domains = json_decode($this->domains, true); - $a = json_decode($this->aliases, true); - $ip = json_decode($this->ip_whitelist, true); - $spam_whitelist = json_decode($this->spam_whitelist, true); - $spam_blacklist = json_decode($this->spam_blacklist, true); - - $spam_bl = []; - foreach ($spam_blacklist as $item) { - $spam_bl[] = 'blacklist_from ' . $item['email']; - } - $spam_wl = []; - foreach ($spam_whitelist as $item) { - $spam_wl[] = 'whitelist_from ' . $item['email']; - } - - $accounts = []; - foreach ($mailboxes as $k => $m) { - if (!isset($m['password'])) { - $m['password'] = ''; - } - - $email = $m['mailbox'] . '@' . $maindomain; - $password = $m['password'] = trim($m['password']); - if ($m['password'] === '') { - $user = User::where('email', $email)->first(); - if (null === $user) { - $m['password'] = Str::random(12); - } else { - $password = '{BLF-CRYPT}' . $user->password; - } - } - if ($m['password'] !== '' && !preg_match('/^\{([A-Z0-9-]+)\}\$\d/', $m['password'])) { - $p = $m['password']; - $cmd = "export PATH=\$PATH:/usr/bin;echo $(doveadm pw -s SHA512-CRYPT -u $email -p $p 2>/dev/null)"; - $password = $m['password'] = trim(`$cmd`); - if (!$password) { - dd($cmd, $m['password']); - } - } - $accounts[$m['mailbox']] = $password; - $mailboxes[$k] = $m; - } - usort($mailboxes, function ($a, $b) { - return strcmp($a['mailbox'], $b['mailbox']); - }); - - $this->mailboxes = json_encode($mailboxes); - - $accountFile = []; - foreach ($accounts as $account => $password) { - $accountFile[] = $account . '@' . $maindomain . '|' . $password; - } - Files::mkdir(storage_path('emailconfig')); - file_put_contents(storage_path('emailconfig/postfix-accounts.cf'), implode("\n", $accountFile)); - - - $aliases = []; - foreach ($a as $item) { - $from = trim($item['from']); - if (!isset($aliases[$from])) { - $aliases[$from] = []; - } - $aliases[$from] = array_merge($aliases[$from], explode(',', str_replace('@' . $maindomain, '', $item['dest']))); - } - ksort($aliases); - $savedAliases = []; - foreach ($aliases as $from => $dest) { - $savedAliases[] = ['from' => $from, 'dest' => $dest]; - } - $this->aliases = json_encode($savedAliases); - - $allAliases = []; - foreach ($domains as $d) { - $domain = $d['domaine']; - foreach ($accounts as $account => $password) { - if (!isset($allAliases[$account . '@' . $domain])) { - $allAliases[$account . '@' . $domain] = []; - } - $allAliases[$account . '@' . $domain][] = $account . '@' . $maindomain; - } - foreach ($aliases as $from => $dest) { - if (!isset($allAliases[$from . '@' . $domain])) { - $allAliases[$from . '@' . $domain] = []; - } - $allAliases[$from . '@' . $domain] = array_merge($allAliases[$from . '@' . $domain], $dest); - } - $allAliases['@' . $domain] = ['spam@' . $maindomain]; - } - $aliasesFile = []; - foreach ($allAliases as $from => $dest) { - $domaineDest = []; - foreach ($dest as $d) { - if (stristr($d, '@')) { - $domaineDest[] = $d; - } else { - $domaineDest[] = $d . '@' . $maindomain; - } - } - $domaineDest = array_unique($domaineDest); - $aliasesFile[] = $from . ' ' . implode(',', $domaineDest); - } - - file_put_contents(storage_path('emailconfig/postfix-virtual.cf'), implode("\n", $aliasesFile)); - - // Postgrey whitelist - file_put_contents(storage_path('emailconfig/whitelist_clients.local'), str_replace("\r\n", "\n", $this->postgrey_whitelist)); - - // IP Whitelist - $my_networks = []; - foreach ($ip as $item) { - $resolved = Util::resolve($item['ip']); - if ($resolved) { - $my_networks[] = $resolved; - } - } - $my_networks = array_unique($my_networks); - - $this->_replaceInFile('postfix-main.cf', ['my_networks' => implode(', ', $my_networks)]); - $this->_replaceInFile('fail2ban-jail.cf', ['ignoreip' => implode(',', $my_networks)]); - $this->_replaceInFile('spamassassin-rules.cf', ['spam_whitelist' => implode("\n", $spam_wl), 'spam_blacklist' => implode("\n", $spam_bl)]); - - touch(storage_path('emailconfig/__UPDATED__')); - } - - protected function _replaceInFile($filename, $variables) - { - $content = file_get_contents(resource_path('emailconfig/' . $filename)); - foreach ($variables as $k => $v) { - $content = str_replace('$' . $k, $v, $content); - } - $content = str_replace("\r\n", "\n", $content); - file_put_contents(storage_path('emailconfig/' . $filename), $content); - } -} diff --git a/app/Models/CubedesignersTeamMember.php b/app/Models/CubedesignersTeamMember.php new file mode 100644 index 000000000..fdf20b9e6 --- /dev/null +++ b/app/Models/CubedesignersTeamMember.php @@ -0,0 +1,24 @@ +where('company', 7); +// $builder->orderBy('enabled', 'ASC'); +// $builder->orderBy('id', 'ASC'); +// +// }); + + static::observe(new MagicObserver); + } + +} diff --git a/app/Models/Quiz.php b/app/Models/Quiz.php index 25e6f65f9..f67f4673a 100644 --- a/app/Models/Quiz.php +++ b/app/Models/Quiz.php @@ -103,7 +103,7 @@ class Quiz extends ToolboxModel 'tab' => __('Projet')]); $this->addColumnDateFields(__('Projet')); - $this->addOwnerField(__('Projet')); + $this->addOwnerField(['tab' => __('Projet')]); $this->addField(['name' => 'title', 'label' => __('Titre du quiz'), diff --git a/app/Models/TeamEmails.php b/app/Models/TeamEmails.php new file mode 100644 index 000000000..c07906312 --- /dev/null +++ b/app/Models/TeamEmails.php @@ -0,0 +1,171 @@ + 'team-emails', + 'singular' => 'paramètre', + 'plural' => 'paramètres', + 'oneinstance' => true]; + + + public function setFields() + { + parent::setFields(); + + $this->addField('domains', Table::class, __('Domaines'), ['entity_singular' => __('un domaine'), 'columns' => ['domaine' => __('Domaine')], 'translatable' => false, 'tab' => __('Comptes et redirections')]); + $this->addField('mailboxes', Table::class, __('Boîtes mail'), ['entity_singular' => __('une boîte mail'), 'columns' => ['mailbox' => __('E-mail'), 'password' => __('Mot de passe')], 'translatable' => false, 'hint' => __('Laisser le mot de passe vide pour utiliser celui du compte "Toolbox"'), 'tab' => __('Comptes et redirections')]); + $this->addField('aliases', Table::class, __('Redirections'), ['entity_singular' => __('une redirection'), 'columns' => ['from' => __('Alias'), 'dest' => __('Destinations')], 'translatable' => false, 'tab' => __('Comptes et redirections')]); + $this->addField('ip_whitelist', Table::class, __('Liste blanche IP'), ['tab' => __('Listes blanches et noires'), 'entity_singular' => __('une IP'), 'columns' => ['ip' => __('IP ou nom d\'hôte')], 'translatable' => false, 'hint' => __('IP qui sont sur la liste blanche (fail2ban, my_networks)')]); + $this->addField('postgrey_whitelist', Code::class, __('Liste blanche postgrey'), ['translatable' => false, 'tab' => __('Listes blanches et noires'), 'language' => 'properties', 'hint' => __('Serveurs ignorés par le Grey listing')]); + $this->addField('spam_whitelist', Table::class, __('Liste blanche SPAM'), ['tab' => __('Listes blanches et noires'), 'entity_singular' => __('un e-mail'), 'columns' => ['email' => __('E-mail')], 'translatable' => false, 'hint' => __('Les e-mails provenant de ces expéditeurs ne sont jamais considérés comme des spam (expressions régulières possibles)')]); + $this->addField('spam_blacklist', Table::class, __('Liste noire SPAM'), ['tab' => __('Listes blanches et noires'), 'entity_singular' => __('un e-mail'), 'columns' => ['email' => __('E-mail')], 'translatable' => false, 'hint' => __('Ces e-mails sont toujours considérés comme des spam (expressions régulières possibles)')]); + + } + + public function preSave() + { + + $maindomain = 'cubedesigners.com'; + + $mailboxes = json_decode($this->mailboxes, true); + $domains = json_decode($this->domains, true); + $a = json_decode($this->aliases, true); + $ip = json_decode($this->ip_whitelist, true); + $spam_whitelist = json_decode($this->spam_whitelist, true); + $spam_blacklist = json_decode($this->spam_blacklist, true); + + $spam_bl = []; + foreach ($spam_blacklist as $item) { + $spam_bl[] = 'blacklist_from ' . $item['email']; + } + $spam_wl = []; + foreach ($spam_whitelist as $item) { + $spam_wl[] = 'whitelist_from ' . $item['email']; + } + + $accounts = []; + foreach ($mailboxes as $k => $m) { + if (!isset($m['password'])) { + $m['password'] = ''; + } + + $email = $m['mailbox'] . '@' . $maindomain; + $password = $m['password'] = trim($m['password']); + if ($m['password'] === '') { + $user = User::where('email', $email)->first(); + if (null === $user) { + $m['password'] = Str::random(12); + } else { + $password = '{BLF-CRYPT}' . $user->password; + } + } + if ($m['password'] !== '' && !preg_match('/^\{([A-Z0-9-]+)\}\$\d/', $m['password'])) { + $p = $m['password']; + $m['password'] = $password = "{SHA512-CRYPT}" . crypt($p, "$6$" . substr(sha1(rand()), 0, 16)); + } + $accounts[$m['mailbox']] = $password; + $mailboxes[$k] = $m; + } + usort($mailboxes, function ($a, $b) { + return strcmp($a['mailbox'], $b['mailbox']); + }); + + $this->mailboxes = json_encode($mailboxes); + + $accountFile = []; + foreach ($accounts as $account => $password) { + $accountFile[] = $account . '@' . $maindomain . '|' . $password; + } + Files::mkdir(storage_path('emailconfig')); + file_put_contents(storage_path('emailconfig/postfix-accounts.cf'), implode("\n", $accountFile)); + + + $aliases = []; + foreach ($a as $item) { + $from = trim($item['from']); + if (!isset($aliases[$from])) { + $aliases[$from] = []; + } + $aliases[$from] = array_merge($aliases[$from], explode(',', str_replace('@' . $maindomain, '', $item['dest']))); + } + ksort($aliases); + $savedAliases = []; + foreach ($aliases as $from => $dest) { + $savedAliases[] = ['from' => $from, 'dest' => $dest]; + } + $this->aliases = json_encode($savedAliases); + + $allAliases = []; + foreach ($domains as $d) { + $domain = $d['domaine']; + foreach ($accounts as $account => $password) { + if (!isset($allAliases[$account . '@' . $domain])) { + $allAliases[$account . '@' . $domain] = []; + } + $allAliases[$account . '@' . $domain][] = $account . '@' . $maindomain; + } + foreach ($aliases as $from => $dest) { + if (!isset($allAliases[$from . '@' . $domain])) { + $allAliases[$from . '@' . $domain] = []; + } + $allAliases[$from . '@' . $domain] = array_merge($allAliases[$from . '@' . $domain], $dest); + } + $allAliases['@' . $domain] = ['spam@' . $maindomain]; + } + $aliasesFile = []; + foreach ($allAliases as $from => $dest) { + $domaineDest = []; + foreach ($dest as $d) { + if (stristr($d, '@')) { + $domaineDest[] = $d; + } else { + $domaineDest[] = $d . '@' . $maindomain; + } + } + $domaineDest = array_unique($domaineDest); + $aliasesFile[] = $from . ' ' . implode(',', $domaineDest); + } + + file_put_contents(storage_path('emailconfig/postfix-virtual.cf'), implode("\n", $aliasesFile)); + + // Postgrey whitelist + file_put_contents(storage_path('emailconfig/whitelist_clients.local'), str_replace("\r\n", "\n", $this->postgrey_whitelist)); + + // IP Whitelist + $my_networks = []; + foreach ($ip as $item) { + $resolved = Util::resolve($item['ip']); + if ($resolved) { + $my_networks[] = $resolved; + } + } + $my_networks = array_unique($my_networks); + + $this->_replaceInFile('postfix-main.cf', ['my_networks' => implode(', ', $my_networks)]); + $this->_replaceInFile('fail2ban-jail.cf', ['ignoreip' => implode(',', $my_networks)]); + $this->_replaceInFile('spamassassin-rules.cf', ['spam_whitelist' => implode("\n", $spam_wl), 'spam_blacklist' => implode("\n", $spam_bl)]); + + touch(storage_path('emailconfig/__UPDATED__')); + } + + protected function _replaceInFile($filename, $variables) + { + $content = file_get_contents(resource_path('emailconfig/' . $filename)); + foreach ($variables as $k => $v) { + $content = str_replace('$' . $k, $v, $content); + } + $content = str_replace("\r\n", "\n", $content); + file_put_contents(storage_path('emailconfig/' . $filename), $content); + } +} diff --git a/app/Models/TeamLeave.php b/app/Models/TeamLeave.php new file mode 100644 index 000000000..3ed6e8641 --- /dev/null +++ b/app/Models/TeamLeave.php @@ -0,0 +1,59 @@ + 'team-leave', + 'singular' => 'absence', + 'plural' => 'congés et absence', + 'oneinstance' => false]; + + static $_permissionBase = 'team-leave'; + + protected $_enableClone = false; + protected $_enableDeletion = true; + + + public function setFields() + { + parent::setFields(); + + try { + $bid = backpack_user()->id; + } catch (\Exception $e) { + $bid = null; + } + $this->addField('worker', \App\Fields\CubedesignersTeamMember::class, __('Nom'), ['column' => true, 'default' => $bid, 'can_hidden' => self::$_permissionBase . ':admin']); + $this->addField('type', SelectFromArray::class, __('Type'), ['options' => + [ + 'paid_leave' => __('Congé payé'), + 'manager_leave' => __('Congé gérant'), + 'sick_leave' => __('Arrêt maladie'), + 'unpaid_leave' => __('Congé sans solde'), + 'parenthood_leave' => __('Congé parental'), + 'family_event_leave' => __('Congé pour événement familial'), + 'sick_child_leave' => __('Congé pour enfant malade'), + 'recovery_day' => __('Jour de récupération'), + 'partial_activity' => __('Activité partielle'), + ] + , 'column' => true, 'default' => 'paid_leave', 'allows_null' => false]); + $this->addOwnerField(['label' => __('Ajouté par'), 'column' => false, 'column_attribute' => 'name',]); + $this->addField('start_day', Date::class, __('Début'), ['column' => true]); + $this->addField('end_day', Date::class, __('Fin'), ['column' => true, 'hint' => __('Inclus')]); + $this->addField('nb_days', Number::class, __('Durée'), ['column' => true, 'suffix' => __('jours')]); + $this->addField('accepted', Checkbox::class, __('Accepté'), ['column' => true, 'default' => true, 'can' => self::$_permissionBase . ':admin']); + $this->addField('public', Checkbox::class, __('Public'), ['column' => true, 'default' => true, 'hint' => __('Si activé, apparaît dans le planning des vacances'), 'can' => self::$_permissionBase . ':admin']); + $this->addField('recorded_month', Date::class, __('Comptabilisé'), ['column' => true, 'column_format' => 'YYYY-MM', 'can' => self::$_permissionBase . ':admin']); + $this->addField('comment', Text::class, __('Commentaire'), ['column' => true, 'can' => self::$_permissionBase . ':admin']); + } +} diff --git a/app/Models/TeamOvertime.php b/app/Models/TeamOvertime.php new file mode 100644 index 000000000..efe463436 --- /dev/null +++ b/app/Models/TeamOvertime.php @@ -0,0 +1,50 @@ + 'team-overtime', + 'singular' => 'heures supplémentaires', + 'plural' => 'heures supplémentaires', + 'oneinstance' => false]; + + static $_permissionBase = 'team-overtime'; + + protected $_enableClone = false; + protected $_enableDeletion = true; + + + public function setFields() + { + parent::setFields(); + + try { + $bid = backpack_user()->id; + } catch (\Exception $e) { + $bid = null; + } + $this->addField('worker', \App\Fields\CubedesignersTeamMember::class, __('Nom'), ['column' => true, 'default' => $bid, 'can_hidden' => self::$_permissionBase . ':admin']); + $this->addField('type', SelectFromArray::class, __('Type'), ['options' => + [ + 'supplementary_hours' => __('Heures supplémentaires'), + 'complementary_hours' => __('Heures complémentaires'), + ] + , 'column' => true, 'default' => 'supplementary_hours', 'allows_null' => false]); + $this->addOwnerField(['label' => __('Ajouté par'), 'column' => false, 'column_attribute' => 'name']); + $this->addField('day', Date::class, __('Semaine'), ['column' => true]); + $this->addField('nb_hours', Number::class, __('Nombre'), ['column' => true, 'suffix' => __('heures')]); + $this->addField('accepted', Checkbox::class, __('Accepté'), ['column' => true, 'default' => true, 'can' => self::$_permissionBase . ':admin']); + $this->addField('recorded_month', Date::class, __('Comptabilisé'), ['column' => true, 'column_format' => 'YYYY-MM', 'can' => self::$_permissionBase . ':admin']); + $this->addField('comment', Text::class, __('Commentaire'), ['column' => true, 'can' => self::$_permissionBase . ':admin']); + } +} diff --git a/resources/views/vendor/backpack/base/inc/sidebar_content.blade.php b/resources/views/vendor/backpack/base/inc/sidebar_content.blade.php index 89535bd57..c8e1be1ec 100644 --- a/resources/views/vendor/backpack/base/inc/sidebar_content.blade.php +++ b/resources/views/vendor/backpack/base/inc/sidebar_content.blade.php @@ -123,17 +123,30 @@ @endcan -@canany(['extranet:manage_team','extranet:manage_emails']) +@canany(['team-leave:read','team-overtime:read','extranet:manage_emails'])
  • {{__('Équipe')}}
  • @endcan diff --git a/routes/backpack/custom.php b/routes/backpack/custom.php index a6de6bff7..651ddff66 100644 --- a/routes/backpack/custom.php +++ b/routes/backpack/custom.php @@ -1,23 +1,34 @@ config('backpack.base.route_prefix', 'admin'), + 'prefix' => config('backpack.base.route_prefix', 'admin'), 'middleware' => ['web', config('backpack.base.middleware_key', 'admin')], - 'namespace' => 'App\Http\Controllers\Admin', + 'namespace' => 'App\Http\Controllers\Admin', ], function () { // custom admin routes try { - Route::crud('company', 'CompanyCrudController'); - Route::crud('fluidbook-publication', 'FluidbookPublicationCrudController'); - Route::crud('fluidbook-quote', 'FluidbookQuoteCrudController'); - Route::crud('fluidbook-theme', 'FluidbookThemeCrudController'); - Route::crud('locale', 'LocaleCrudController'); - Route::crud('settings', 'SettingsCrudController'); - Route::crud('signature', 'SignatureCrudController'); - Route::crud('toolbox-translate', 'ToolboxTranslateCrudController'); - Route::crud('quiz', 'QuizCrudController'); - Route::crud('quizatttempt', 'QuizatttemptCrudController'); - Route::crud('quiztranslation', 'QuiztranslationCrudController'); - Route::crud('users', 'UsersCrudController'); - } catch (\Throwable $e) { + Route::crud('elearning-media', 'ElearningMediaCrudController'); + Route::crud('toolbox-translate', 'ToolboxTranslateCrudController'); + Route::crud('quiztranslation', 'QuiztranslationCrudController'); + Route::crud('team-emails', 'TeamEmailsCrudController'); + Route::crud('fluidbook-quote', 'FluidbookQuoteCrudController'); + Route::crud('locale', 'LocaleCrudController'); + Route::crud('tool-sprite', 'ToolSpriteCrudController'); + Route::crud('users', 'UsersCrudController'); + Route::crud('users', 'UsersCrudController'); + Route::crud('quiz', 'QuizCrudController'); + Route::crud('page', 'PageCrudController'); + Route::crud('settings', 'SettingsCrudController'); + Route::crud('fluidbook-collection', 'FluidbookCollectionCrudController'); + Route::crud('fluidbook-document', 'FluidbookDocumentCrudController'); + Route::crud('fluidbook-publication', 'FluidbookPublicationCrudController'); + Route::crud('quizatttempt', 'QuizatttemptCrudController'); + Route::crud('elearning-package', 'ElearningPackageCrudController'); + Route::crud('fluidbook-theme', 'FluidbookThemeCrudController'); + Route::crud('company', 'CompanyCrudController'); + Route::crud('signature', 'SignatureCrudController'); + Route::crud('fluidbook-iconset', 'FluidbookIconsetCrudController'); + Route::crud('users', 'UsersCrudController'); + Route::crud('fluidbook-translate', 'FluidbookTranslateCrudController'); + } catch(\Throwable $e) { } });