diff --git a/app/controllers/settings/categories.php b/app/controllers/settings/categories.php index f62366498d28a60062ce519ffa5a29362097cb66..6e8bbab8fc6f0f6947f8c62a8e9f3bd9fa416316 100644 --- a/app/controllers/settings/categories.php +++ b/app/controllers/settings/categories.php @@ -135,23 +135,26 @@ class Settings_CategoriesController extends Settings_SettingsController */ public function store_action() { - $request = Request::getInstance(); $changed = false; - $categories = $request['categories']; - foreach ($categories as $id => $data) { - if (empty($data['name'])) { - PageLayout::postError(_('Kategorien ohne Namen können nicht gespeichert werden!')); - continue; - } - $category = Kategorie::find($id); - $category->name = $data['name']; - $category->content = Studip\Markup::purifyHtml($data['content']); - if ($category->isDirty() && $category->store()) { - $changed = true; - Visibility::renamePrivacySetting('kat_' . $category->id, $category->name); - } - } + Kategorie::findEachMany( + function (Kategorie $category) use (&$changed) { + $category->name = Request::i18n("category-name-{$category->id}"); + $category->content = Request::i18n( + "category-content-{$category->id}", + null, + function ($input) { + return Studip\Markup::purifyHtml($input); + } + ); + + if ($category->store()) { + $changed = true; + Visibility::renamePrivacySetting("kat_{$category->id}", $category->name->original()); + } + }, + Request::optionArray('ids') + ); if ($changed) { PageLayout::postSuccess(_('Kategorien geändert!')); diff --git a/app/views/settings/categories.php b/app/views/settings/categories.php index 663b54f6147feff432b298165a32c5e945e48333..12e9df589708cf68d236581774c37232f8631491 100644 --- a/app/views/settings/categories.php +++ b/app/views/settings/categories.php @@ -8,61 +8,57 @@ <input type="hidden" name="studip_ticket" value="<?= get_ticket() ?>"> <? foreach ($categories as $index => $category): ?> + <input type="hidden" name="ids[]" value="<?= htmlReady($category->id) ?>"> + <fieldset> - <legend><?= htmlReady($category->name) ?></legend> + <legend style="display: flex; flex-wrap: nowrap; justify-content: space-between"> + <span><?= htmlReady($category->name) ?></span> + <span> + <? if ($index > 0): ?> + <a href="<?= $controller->url_for('settings/categories/swap', $category->id, $last->id) ?>"> + <?= Icon::create('arr_2up', 'sort')->asImg(['class' => 'text-top', 'title' =>_('Kategorie nach oben verschieben')]) ?> + </a> + <? else: ?> + <?= Icon::create('arr_2up', 'inactive')->asImg(['class' => 'text-top']) ?> + <? endif; ?> - <table style="width: 100%"> - <colgroup> - <col> - <col width="100px"> - </colgroup> - <tbody> - <tr> - <td> - <div> - (<?= $visibilities[$category->id] ?>) - </div> + <? if ($index < $count - 1): ?> + <a href="<?= $controller->url_for('settings/categories/swap', $category->id, $categories[$index + 1]->id) ?>"> + <?= Icon::create('arr_2down', 'sort')->asImg(['class' => 'text-top', 'title' =>_('Kategorie nach unten verschieben')]) ?> + </a> + <? else: ?> + <?= Icon::create('arr_2down', 'inactive')->asImg(['class' => 'text-top']) ?> + <? endif; ?> - <label> - <?= _('Name') ?> - <input required type="text" name="categories[<?= $category->id ?>][name]" id="name<?= $index ?>" - aria-label="<?= _('Name der Kategorie') ?>" style="width: 100%" - value="<?= htmlReady($category->name) ?>"> - </label> + <a href="<?= $controller->url_for('settings/categories/delete', $category->id) ?>"> + <?= Icon::create('trash')->asImg(['class' => 'text-top', 'title' => _('Kategorie löschen')]) ?> + </a> + </span> + </legend> - <label> - <?= _('Inhalt') ?> + <p> + (<?= $visibilities[$category->id] ?>) + </p> - <textarea id="content<?= $index ?>" name="categories[<?= $category->id ?>][content]" - class="resizable add_toolbar wysiwyg size-l" style="width: 100%; height: 200px;" - aria-label="<?= _('Inhalt der Kategorie:') ?>" - ><?= wysiwygReady($category->content) ?></textarea> - </label> - </td> - <td style="vertical-align: top"> - <? if ($index > 0): ?> - <a href="<?= $controller->url_for('settings/categories/swap', $category->id, $last->id) ?>"> - <?= Icon::create('arr_2up', 'sort')->asImg(['class' => 'text-top', 'title' =>_('Kategorie nach oben verschieben')]) ?> - </a> - <? else: ?> - <?= Icon::create('arr_2up', 'inactive')->asImg(['class' => 'text-top']) ?> - <? endif; ?> + <label> + <?= _('Name') ?> + <?= I18N::input("category-name-{$category->id}", $category->name, [ + 'aria-label' => _('Name der Kategorie'), + 'class' => 'size-l', + 'id' => "name{$index}", + 'required' => '', + ]) ?> + </label> - <? if ($index < $count - 1): ?> - <a href="<?= $controller->url_for('settings/categories/swap', $category->id, $categories[$index + 1]->id) ?>"> - <?= Icon::create('arr_2down', 'sort')->asImg(['class' => 'text-top', 'title' =>_('Kategorie nach unten verschieben')]) ?> - </a> - <? else: ?> - <?= Icon::create('arr_2down', 'inactive')->asImg(['class' => 'text-top']) ?> - <? endif; ?> + <label> + <?= _('Inhalt') ?> - <a href="<?= $controller->url_for('settings/categories/delete', $category->id) ?>"> - <?= Icon::create('trash')->asImg(['class' => 'text-top', 'title' => _('Kategorie löschen')]) ?> - </a> - </td> - </tr> - </tbody> - </table> + <?= I18n::textarea("category-content-{$category->id}", $category->content, [ + 'aria-label' => _('Inhalt der Kategorie:'), + 'class' => 'resizable add_toolbar wysiwyg size-l', + 'id' => "content{$index}", + ]) ?> + </label> </fieldset> <? $last = $category; endforeach; ?> diff --git a/lib/models/Kategorie.class.php b/lib/models/Kategorie.class.php index 890009ce73f184a5dba76602c0ee0c02f0731811..13c9c3a464fe3e0266fff07c8cc603c1b2a9f128 100644 --- a/lib/models/Kategorie.class.php +++ b/lib/models/Kategorie.class.php @@ -1,5 +1,5 @@ -<? -/* +<?php +/** * Kategorie model * * This program is free software; you can redistribute it and/or @@ -12,14 +12,16 @@ * @category Stud.IP * @since 2.4 * - * @property string kategorie_id database column - * @property string id alias column for kategorie_id - * @property string range_id database column - * @property string name database column - * @property string content database column - * @property string mkdate database column - * @property string chdate database column - * @property string priority database column + * @property string $kategorie_id database column + * @property string $id alias column for kategorie_id + * @property string $range_id database column + * @property string|I18NString $name database column + * @property string|I18NString $content database column + * @property int $mkdate database column + * @property int $chdate database column + * @property int $priority database column + * + * @property User $user */ class Kategorie extends SimpleORMap @@ -32,6 +34,19 @@ class Kategorie extends SimpleORMap protected static function configure($config = []) { $config['db_table'] = 'kategorien'; + + $config['belongs_to'] = [ + 'user' => [ + 'class_name' => User::class, + 'foreign_key' => 'range_id', + ], + ]; + + $config['i18n_fields'] = [ + 'name' => true, + 'content' => true, + ]; + parent::configure($config); } @@ -39,9 +54,9 @@ class Kategorie extends SimpleORMap * Finds all categories of a specific user * * @param string $user_id Id of the user - * @return array of category objects + * @return Kategorie[] of category objects */ - public static function findByUserId($user_id) + public static function findByUserId(string $user_id): array { return self::findByRange_id($user_id, 'ORDER BY priority'); } @@ -50,9 +65,9 @@ class Kategorie extends SimpleORMap * Increases all category priorities of a user * * @param string $user_id Id of the user - * @return number of changed records + * @return bool indicating if anything has changed */ - public static function increasePrioritiesByUserId($user_id) + public static function increasePrioritiesByUserId(string $user_id): bool { $query = "UPDATE kategorien SET priority = priority + 1 WHERE range_id = ?"; $statement = DBManager::get()->prepare($query); diff --git a/lib/models/User.class.php b/lib/models/User.class.php index 30c38ad19dd6c0a3063e5488f150abebdd25c87d..3d6a7e0a90425d7637acb082ed6f5633d813c890 100644 --- a/lib/models/User.class.php +++ b/lib/models/User.class.php @@ -67,6 +67,7 @@ * @property SimpleORMapCollection contacts has_many Contact * @property UserInfo info has_one UserInfo * @property UserOnline online has_one UserOnline + * @property Kategorie[]|SimpleORMapCollection $profile_categories has_many Kategorie */ class User extends AuthUserMd5 implements Range, PrivacyObject { @@ -158,11 +159,18 @@ class User extends AuthUserMd5 implements Range, PrivacyObject 'class_name' => ConsultationBooking::class, 'on_delete' => 'delete', ]; + $config['has_many']['profile_categories'] = [ + 'class_name' => Kategorie::class, + 'assoc_foreign_key' => 'range_id', + 'on_delete' => 'delete', + ]; + $config['has_many']['mvv_assignments'] = [ 'class_name' => MvvContact::class, 'assoc_foreign_key' => 'contact_id', 'on_delete' => 'delete', + 'order_by' => 'ORDER BY priority', ]; $config['has_and_belongs_to_many']['domains'] = [ @@ -874,7 +882,7 @@ class User extends AuthUserMd5 implements Range, PrivacyObject } } - foreach (Kategorie::findByUserId($this->id) as $category) { + foreach ($this->profile_categories as $category) { $homepage_elements['kat_' . $category->id] = [ 'name' => $category->name, 'visibility' => $homepage_visibility['kat_' . $category->id] ?: get_default_homepage_visibility($this->id),