From ef16ca3d78625ac6d25527c1af5bfe3eeb9d8906 Mon Sep 17 00:00:00 2001
From: Moritz Strohm <strohm@data-quest.de>
Date: Wed, 11 May 2022 09:47:50 +0000
Subject: [PATCH] TIC #758

Merge request studip/studip!398
---
 app/controllers/help_content.php              |  1 +
 app/views/help_content/admin_overview.php     | 46 ++++++++++-----
 app/views/help_content/edit.php               | 12 ++--
 app/views/tour/admin_details.php              | 35 +++++------
 app/views/tour/admin_overview.php             | 59 +++++++++++--------
 .../5.2.7_add_comment_to_help_content.php     | 28 +++++++++
 lib/models/HelpContent.class.php              | 46 +++++++++------
 lib/models/HelpTour.class.php                 | 44 +++++++++-----
 lib/models/HelpTourStep.class.php             | 50 ++++++++++++----
 9 files changed, 214 insertions(+), 107 deletions(-)
 create mode 100644 db/migrations/5.2.7_add_comment_to_help_content.php

diff --git a/app/controllers/help_content.php b/app/controllers/help_content.php
index 1f9edc087f7..c63346b53da 100644
--- a/app/controllers/help_content.php
+++ b/app/controllers/help_content.php
@@ -212,6 +212,7 @@ class HelpContentController extends AuthenticatedController
 
         $help_content->content         = Request::get('help_content_content');
         $help_content->route           = Request::get('help_content_route');
+        $help_content->comment         = Request::get('help_content_comment');
         $help_content->author_email    = $GLOBALS['user']->Email;
         $help_content->installation_id = Config::get()->STUDIP_INSTALLATION_ID;
 
diff --git a/app/views/help_content/admin_overview.php b/app/views/help_content/admin_overview.php
index 5fc00529065..8d915849e1d 100644
--- a/app/views/help_content/admin_overview.php
+++ b/app/views/help_content/admin_overview.php
@@ -3,24 +3,20 @@
     <form action="<?= $controller->url_for('help_content/store_settings') ?>" method="post">
         <input type="hidden" name="help_content_searchterm" value="<?= $help_content_searchterm ?>">
         <?= CSRFProtection::tokenTag() ?>
-        <table class="default">
+        <table class="default sortable-table">
             <caption>
                 <?= sprintf(ngettext('%u Hilfe-Text', '%u Hilfe-Texte', $count), $count) ?>
             </caption>
-            <colgroup>
-                <col width="20">
-                <col width="20%">
-                <col width="10%">
-                <col>
-                <col width="80">
-            </colgroup>
             <thead>
                 <tr>
-                    <th><?= _("Aktiv") ?></th>
-                    <th><?= _("Seite") ?></th>
-                    <th><?= _("Sprache") ?></th>
-                    <th><?= _("Inhalt") ?></th>
-                    <th><?= _("Aktion") ?></th>
+                    <th><?= _('Aktiv') ?></th>
+                    <th data-sort="text"><?= _('Seite') ?></th>
+                    <th data-sort="text"><?= _('Sprache') ?></th>
+                    <th data-sort="text"><?= _('Stud.IP Version') ?></th>
+                    <th><?= _('Inhalt') ?></th>
+                    <th data-sort="htmldata"><?= _('Letzte Änderung') ?></th>
+                    <th data-sort="htmldata"><?= _('Geändert von') ?></th>
+                    <th class="actions"><?= _('Aktionen') ?></th>
                 </tr>
             </thead>
             <tbody>
@@ -30,10 +26,30 @@
                                    value="1" class="help_on"
                                 <?= tooltip(_("Status der Hilfe (aktiv oder inaktiv)"), false) ?><?= $help_content->visible ? ' checked' : '' ?>>
                         </td>
-                        <td><?= htmlReady($help_content->route) ?></td>
+                        <td>
+                            <?= htmlReady($help_content->route) ?>
+                            <? if ($help_content->comment) : ?>
+                                <?= tooltipIcon($help_content->comment) ?>
+                            <? endif ?>
+                        </td>
                         <td><?= htmlReady($help_content->language) ?></td>
+                        <td><?= htmlReady($help_content->studip_version) ?></td>
                         <td><?= formatReady($help_content->content) ?></td>
+                        <td><?= $help_content->chdate ? date('d.m.Y H:i', $help_content->chdate) : '' ?></td>
                         <td>
+                            <? if ($help_content->author) : ?>
+                                <a href="<?= URLHelper::getLink('dispatch.php/profile', ['username' => $help_content->author->username]) ?>" class="link-intern" title="<?= _('Zum Profil') ?>">
+                                    <?= htmlReady($help_content->author->getFullName()) ?>
+                                </a>
+                            <? elseif ($help_content->author_email) : ?>
+                                <a href="mailto:<?= htmlReady($help_content->author_email) ?>">
+                                    <?= htmlReady($help_content->author_email) ?>
+                                </a>
+                            <? else : ?>
+                                 <?= _('unbekannt') ?>
+                            <? endif ?>
+                        </td>
+                        <td class="actions">
                             <a href="<?= URLHelper::getURL('dispatch.php/help_content/edit/' . $help_content_id) ?>" <?= tooltip(_('Hilfe-Text bearbeiten')) ?>
                                data-dialog="size=auto;reload-on-close">
                                 <?= Icon::create('edit', 'clickable')->asImg() ?></a>
@@ -46,7 +62,7 @@
             </tbody>
             <tfoot>
                 <tr>
-                    <td colspan="6">
+                    <td colspan="8">
                         <?= Button::createAccept(_('Speichern'), 'save_help_content_settings') ?>
                     </td>
                 </tr>
diff --git a/app/views/help_content/edit.php b/app/views/help_content/edit.php
index dd8263ed8b9..b7e5d2e5bb0 100644
--- a/app/views/help_content/edit.php
+++ b/app/views/help_content/edit.php
@@ -11,7 +11,7 @@
         <? else : ?>
             <legend><?= _('Neuer Hilfe-Text') ?></legend>
             <label for="help_content_route">
-                <?= _('Seite:') ?>
+                <?= _('Seite') ?>:
                 <input type="text" size="60" maxlength="255" name="help_content_route"
                        value=""
                        placeholder="<?= _('Bitte geben Sie eine Route für den Hilfe-Text an') ?>">
@@ -19,7 +19,7 @@
         <? endif ?>
         <? if ($help_admin) : ?>
             <label for="help_content_language">
-                <span class="required"><?= _('Sprache des Textes:') ?></span>
+                <span class="required"><?= _('Sprache des Textes') ?>:</span>
                 <select name="help_content_language">
                     <? foreach ($GLOBALS['INSTALLED_LANGUAGES'] as $key => $language) : ?>
                         <option value="<?= mb_substr($key, 0, 2) ?>"<?= ($help_content->language == mb_substr($key, 0, 2)) ? ' selected' : '' ?>>
@@ -30,9 +30,13 @@
             </label>
         <? endif ?>
         <label for="help_content_content">
-            <?= _('Hilfe-Text:') ?>
+            <?= _('Hilfe-Text') ?>:
             <textarea cols="60" rows="5" name="help_content_content"
-                      placeholder="<?= _('Bitte geben Sie den Text ein') ?>"><?= $help_content->content ? htmlReady($help_content->content) : '' ?></textarea>
+                      placeholder="<?= _('Bitte geben Sie den Text ein') ?>"><?= htmlReady($help_content->content ?: '') ?></textarea>
+        </label>
+        <label for="help_content_comment">
+            <?= _('Bemerkung') ?>:
+            <textarea name="help_content_comment"><?= htmlReady($help_content->comment ?: '') ?></textarea>
         </label>
     </fieldset>
 
diff --git a/app/views/tour/admin_details.php b/app/views/tour/admin_details.php
index 8e89524abfd..7c7bcdb55ad 100644
--- a/app/views/tour/admin_details.php
+++ b/app/views/tour/admin_details.php
@@ -22,7 +22,7 @@
     <? endif ?>
 
         <label>
-            <span class="required"><?= _('Name der Tour:') ?></span>
+            <span class="required"><?= _('Name der Tour') ?>:</span>
             <input type="text" size="60" maxlength="255" name="tour_name"
                    value="<?= $tour ? htmlReady($tour->name) : '' ?>"
                    required="required" aria-required="true"
@@ -30,14 +30,14 @@
         </label>
 
         <label>
-            <span class="required"> <?= _('Beschreibung:') ?></span>
+            <span class="required"> <?= _('Bemerkung') ?>:</span>
             <textarea cols="60" rows="5" name="tour_description"
                       required="required" aria-required="true"
                       placeholder="<?= _('Bitte geben an, welchen Inhalt die Tour hat') ?>"><?= $tour ? htmlReady($tour->description) : '' ?></textarea>
         </label>
 
         <label>
-            <?= _('Art der Tour:') ?>
+            <?= _('Art der Tour') ?>:
             <select name="tour_type">
                 <option value="tour" <? if ($tour->type === 'tour') echo 'selected'; ?>>
                     <?= _('Tour (passiv)') ?>
@@ -49,7 +49,7 @@
         </label>
 
         <label>
-            <?= _('Zugang zur Tour:') ?>
+            <?= _('Zugang zur Tour') ?>:
             <select name="tour_access">
                 <option value="link" <? if ($tour->settings->access === 'link') echo 'selected'; ?>>
                     <?= _('unsichtbar') ?>
@@ -68,7 +68,7 @@
 
     <? if (!count($tour->steps)) : ?>
         <label>
-            <span class="required"><?= _('Startseite der Tour:') ?></span>
+            <span class="required"><?= _('Startseite der Tour') ?>:</span>
             <input type="text" size="60" maxlength="255" name="tour_startpage"
                    value="<?= $tour_startpage ? htmlReady($tour_startpage) : '' ?>"
                    required="required" aria-required="true"
@@ -78,7 +78,7 @@
     <? endif ?>
 
     <section>
-        <?= _('Geltungsbereich (Nutzendenstatus):') ?>
+        <?= _('Geltungsbereich (Nutzendenstatus)') ?>:
         <? foreach (['autor', 'tutor', 'dozent', 'admin', 'root'] as $role) : ?>
         <label>
             <input type="checkbox" name="tour_roles[]" value="<?= $role ?>"
@@ -114,24 +114,19 @@
 <? if (!$tour->isNew()) : ?>
     <form method="post">
         <?= CSRFProtection::tokenTag() ?>
-        <table class="default">
+        <table class="default sortable-table">
             <caption>
                 <div class="step_list_title"><?= _('Schritte') ?></div>
             </caption>
-            <colgroup>
-                <col width="2%">
-                <col width="25%">
-                <col>
-                <col width="15%">
-                <col width="80">
-            </colgroup>
             <thead>
                 <tr>
-                    <th><?= _('Nr.') ?></th>
-                    <th><?= _('Überschrift') ?></th>
+                    <th data-sort="htmldata"><?= _('Nr.') ?></th>
+                    <th data-sort="text"><?= _('Überschrift') ?></th>
                     <th><?= _('Inhalt') ?></th>
-                    <th><?= _('Seite') ?></th>
-                    <th><?= _('Aktion') ?></th>
+                    <th data-sort="text"><?= _('Seite') ?></th>
+                    <th data-sort="htmldata"><?= _('Letzte Änderung') ?></th>
+                    <th data-sort="htmldata"><?= _('Geändert von') ?></th>
+                    <th class="actions"><?= _('Aktionen') ?></th>
                 </tr>
             </thead>
             <tbody>
@@ -142,6 +137,8 @@
                         <td><?= htmlReady($step->title) ?></td>
                         <td><?= htmlReady($step->tip) ?></td>
                         <td><?= htmlReady($step->route) ?></td>
+                        <td><?= $tour->chdate ? date('d.m.Y H:i', $tour->chdate) : '' ?></td>
+                        <td><?= htmlReady($step->author ? $step->author->getFullName() : ($step->author_email ?: _('unbekannt'))) ?></td>
                         <td class="actions">
                         <? $actionMenu = ActionMenu::get()->setContext($step->title) ?>
                         <? $actionMenu->addLink(
@@ -167,7 +164,7 @@
                 <? endforeach ?>
             <? else : ?>
                 <tr>
-                    <td colspan="6">
+                    <td colspan="7">
                         <?= _('In dieser Tour sind bisher keine Schritte vorhanden.') ?>
                     </td>
                 </tr>
diff --git a/app/views/tour/admin_overview.php b/app/views/tour/admin_overview.php
index 6a892711310..de527b6195e 100644
--- a/app/views/tour/admin_overview.php
+++ b/app/views/tour/admin_overview.php
@@ -18,30 +18,23 @@
     </table>
 <? endif ?>
 
-    <table class="default">
+    <table class="default sortable-table">
         <caption>
             <div class="tour_list_title"><?= _('Touren') ?></div>
         </caption>
-        <colgroup>
-            <col width="20">
-            <col>
-            <col width="10%">
-            <col width="10%">
-            <col width="10%">
-            <col width="20%">
-            <col width="10%">
-            <col width="80">
-        </colgroup>
         <thead>
             <tr>
                 <th><?= _('Aktiv') ?></th>
-                <th><?= _('Überschrift') ?></th>
-                <th><?= _('Sprache') ?></th>
-                <th><?= _('Typ') ?></th>
-                <th><?= _('Zugang') ?></th>
-                <th><?= _('Startseite') ?></th>
-                <th><?= _('Anzahl der Schritte') ?></th>
-                <th><?= _('Aktion') ?></th>
+                <th data-sort="text"><?= _('Überschrift') ?></th>
+                <th data-sort="htmldata"><?= _('Stud.IP Version') ?></th>
+                <th data-sort="text"><?= _('Sprache') ?></th>
+                <th data-sort="text"><?= _('Typ') ?></th>
+                <th data-sort="text"><?= _('Zugang') ?></th>
+                <th data-sort="text"><?= _('Startseite') ?></th>
+                <th data-sort="htmldata"><?= _('Anzahl der Schritte') ?></th>
+                <th data-sort="htmldata"><?= _('Letzte Änderung') ?></th>
+                <th data-sort="htmldata"><?= _('Geändert von') ?></th>
+                <th class="actions"><?= _('Aktionen') ?></th>
             </tr>
         </thead>
     <? if (count($tours)) : ?>
@@ -49,23 +42,39 @@
         <? foreach ($tours as $tour_id => $tour) : ?>
             <tr>
                 <td>
-                    <input type="checkbox" name="tour_status_<?= $tour_id ?>" value="1"
+                    <input type="checkbox" name="tour_status_<?= htmlReady($tour_id) ?>" value="1"
                            aria-label="<?= _('Status der Tour (aktiv oder inaktiv)') ?>" <?= tooltip(_("Status der Tour (aktiv oder inaktiv)"), false) ?><?= ($tour->settings->active) ? ' checked' : '' ?>>
                 </td>
                 <td>
-                    <a href="<?= $controller->link_for('tour/admin_details/' . $tour_id) ?>">
+                    <a href="<?= $controller->link_for('tour/admin_details/' . htmlReady($tour_id)) ?>">
                         <?= htmlReady($tour->name) ?>
+                        <?= tooltipIcon($tour->description) ?>
                     </a>
                 </td>
-                <td><?= $tour->language ?></td>
-                <td><?= $tour->type ?></td>
-                <td><?= $tour->settings->access ?></td>
+                <td><?= htmlReady($tour->studip_version) ?></td>
+                <td><?= htmlReady($tour->language) ?></td>
+                <td><?= htmlReady($tour->type) ?></td>
+                <td><?= htmlReady($tour->settings->access) ?></td>
                 <td>
                 <? if (count($tour->steps)): ?>
                     <?= htmlReady($tour->steps[0]->route) ?>
                 <? endif; ?>
                 </td>
                 <td><?= count($tour->steps) ?></td>
+                <td><?= $tour->chdate ? date('d.m.Y H:i', $tour->chdate) : '' ?></td>
+                <td>
+                    <? if ($tour->author) : ?>
+                        <a href="<?= URLHelper::getLink('dispatch.php/profile', ['username' => $tour->author->username]) ?>" class="link-intern" title="<?= _('Zum Profil') ?>">
+                            <?= htmlReady($tour->author->getFullName()) ?>
+                        </a>
+                    <? elseif ($tour->author_email) : ?>
+                        <a href="mailto:<?= htmlReady($tour->author_email) ?>">
+                            <?= htmlReady($tour->author_email) ?>
+                        </a>
+                    <? else : ?>
+                        <?= _('unbekannt') ?>
+                    <? endif ?>
+                </td>
                 <td class="actions">
                     <?= ActionMenu::get()->setContext(
                         $tour->name
@@ -89,7 +98,7 @@
         </tbody>
         <tfoot>
             <tr>
-                <td colspan="8">
+                <td colspan="11">
                     <?= Button::createAccept(_('Speichern'), 'save_tour_settings') ?>
                 </td>
             </tr>
@@ -97,7 +106,7 @@
     <? else : ?>
         <tbody>
             <tr>
-                <td colspan="8" style="text-align: center">
+                <td colspan="11" style="text-align: center">
                     <?= _('Keine Touren vorhanden.') ?>
                 </td>
             </tr>
diff --git a/db/migrations/5.2.7_add_comment_to_help_content.php b/db/migrations/5.2.7_add_comment_to_help_content.php
new file mode 100644
index 00000000000..38d3f7a8672
--- /dev/null
+++ b/db/migrations/5.2.7_add_comment_to_help_content.php
@@ -0,0 +1,28 @@
+<?php
+
+
+class AddCommentToHelpContent extends Migration
+{
+    public function description()
+    {
+        return 'Adds the column "comment" to the help_content table.';
+    }
+
+
+    protected function up()
+    {
+        DBManager::get()->exec(
+            "ALTER IGNORE TABLE `help_content`
+            ADD COLUMN comment TEXT NULL"
+        );
+    }
+
+
+    protected function down()
+    {
+        DBManager::get()->exec(
+            "ALTER IGNORE TABLE `help_content`
+            DROP COLUMN comment"
+        );
+    }
+}
diff --git a/lib/models/HelpContent.class.php b/lib/models/HelpContent.class.php
index a767859b14c..b254e214565 100644
--- a/lib/models/HelpContent.class.php
+++ b/lib/models/HelpContent.class.php
@@ -23,26 +23,25 @@
 /**
  * HelpContent.class.php - model class for Stud.IP help content
  *
- *
- *
- *
  * @author   Arne Schröder <schroeder@data-quest>
  * @access   public
  *
- * @property string content_id database column
- * @property string language database column
- * @property string label database column
- * @property string icon database column
- * @property string content database column
- * @property string route database column
- * @property string studip_version database column
- * @property string position database column
- * @property string custom database column
- * @property string visible database column
- * @property string author_email database column
- * @property string installation_id database column
- * @property string mkdate database column
- * @property string chdate database column
+ * @property string $content_id database column
+ * @property string $language database column
+ * @property string $label database column
+ * @property string $icon database column
+ * @property string $content database column
+ * @property string $comment database column
+ * @property string $route database column
+ * @property string $studip_version database column
+ * @property string $position database column
+ * @property string $custom database column
+ * @property string $visible database column
+ * @property string $author_email database column
+ * @property string $installation_id database column
+ * @property string $mkdate database column
+ * @property string $chdate database column
+ * @property User|null $author has_one author
  */
 class HelpContent extends SimpleORMap
 {
@@ -55,6 +54,14 @@ class HelpContent extends SimpleORMap
     {
         $config['db_table'] = 'help_content';
 
+        $config['has_one']['author'] = [
+            'class_name'  => User::class,
+            'foreign_key' => 'author_email',
+            'assoc_func'  => 'findOneByEmail',
+        ];
+
+        $config['registered_callbacks']['before_store'][] = 'cbUpdateStudipVersion';
+
         parent::configure($config);
     }
 
@@ -174,4 +181,9 @@ class HelpContent extends SimpleORMap
         }
         return $objects;
     }
+
+    public function cbUpdateStudipVersion()
+    {
+        $this->studip_version = StudipVersion::getStudipVersion();
+    }
 }
diff --git a/lib/models/HelpTour.class.php b/lib/models/HelpTour.class.php
index 72e5efb0a43..18ed68ecaa2 100644
--- a/lib/models/HelpTour.class.php
+++ b/lib/models/HelpTour.class.php
@@ -29,26 +29,28 @@ require_once 'lib/object.inc.php';
  * @author   Arne Schröder <schroeder@data-quest>
  * @access   public
  *
- * @property string tour_id database column
- * @property string id alias column for tour_id
- * @property string name database column
- * @property string description database column
- * @property string type database column
- * @property string roles database column
- * @property string version database column
- * @property string language database column
- * @property string studip_version database column
- * @property string installation_id database column
- * @property string mkdate database column
- * @property SimpleORMapCollection steps has_many HelpTourStep
- * @property SimpleORMapCollection audiences has_many HelpTourAudience
- * @property HelpTourSettings settings has_one HelpTourSettings
+ * @property string $tour_id database column
+ * @property string $id alias column for tour_id
+ * @property string $name database column
+ * @property string $description database column
+ * @property string $type database column
+ * @property string $roles database column
+ * @property string $version database column
+ * @property string $language database column
+ * @property string $studip_version database column
+ * @property string $installation_id database column
+ * @property string $mkdate database column
+ * @property SimpleORMapCollection $steps has_many HelpTourStep
+ * @property SimpleORMapCollection $audiences has_many HelpTourAudience
+ * @property HelpTourSettings $settings has_one HelpTourSettings
+ * @property User|null $author has_one author
  */
 class HelpTour extends SimpleORMap
 {
     protected static function configure($config = [])
     {
         $config['db_table'] = 'help_tours';
+
         $config['has_one']['settings'] = [
             'class_name'        => HelpTourSettings::class,
             'assoc_foreign_key' => 'tour_id',
@@ -67,10 +69,24 @@ class HelpTour extends SimpleORMap
             'on_delete'         => 'delete',
             'on_store'          => 'store',
         ];
+        $config['has_one']['author'] = [
+            'class_name'  => User::class,
+            'foreign_key' => 'author_email',
+            'assoc_func'  => 'findOneByEmail',
+        ];
+
+        $config['registered_callbacks']['before_store'][] = 'cbUpdateStudipVersion';
 
         parent::configure($config);
     }
 
+
+    public function cbUpdateStudipVersion()
+    {
+        $this->studip_version = StudipVersion::getStudipVersion();
+    }
+
+
     /**
      * get visible tours for helpbar
      *
diff --git a/lib/models/HelpTourStep.class.php b/lib/models/HelpTourStep.class.php
index c74dbb89b46..d2ce1dcb3d7 100644
--- a/lib/models/HelpTourStep.class.php
+++ b/lib/models/HelpTourStep.class.php
@@ -30,19 +30,20 @@
  * @license     http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
  * @category    Stud.IP
  *
- * @property string tour_id database column
- * @property string step database column
- * @property string title database column
- * @property string tip database column
- * @property string orientation database column
- * @property string interactive database column
- * @property string css_selector database column
- * @property string route database column
- * @property string author_email database column
- * @property string mkdate database column
- * @property string chdate database column
- * @property string id computed column read/write
- * @property HelpTours help_tour belongs_to HelpTours
+ * @property string $tour_id database column
+ * @property string $step database column
+ * @property string $title database column
+ * @property string $tip database column
+ * @property string $orientation database column
+ * @property string $interactive database column
+ * @property string $css_selector database column
+ * @property string $route database column
+ * @property string $author_email database column
+ * @property string $mkdate database column
+ * @property string $chdate database column
+ * @property string $id computed column read/write
+ * @property HelpTour $help_tour belongs_to HelpTour
+ * @property User|null $author has_one author
  */
 class HelpTourStep extends SimpleORMap
 {
@@ -55,9 +56,32 @@ class HelpTourStep extends SimpleORMap
             'foreign_key' => 'tour_id',
         ];
 
+        $config['has_one']['author'] = [
+            'class_name'  => User::class,
+            'foreign_key' => 'author_email',
+            'assoc_func'  => 'findOneByEmail',
+        ];
+
+        $config['registered_callbacks']['after_store'][] = 'cbUpdateTour';
+
         parent::configure($config);
     }
 
+
+    public function cbUpdateTour()
+    {
+        if (!$this->help_tour) {
+            return;
+        }
+
+        $this->help_tour->author_email = $this->author_email;
+        $this->help_tour->chdate = $this->chdate;
+        if ($this->help_tour->isDirty()) {
+            $this->help_tour->store();
+        }
+    }
+
+
     /**
      * checks, if tour step data is complete
      *
-- 
GitLab