aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/accessibility/forms.php175
-rw-r--r--app/views/accessibility/forms/report_barrier.php2
-rw-r--r--db/migrations/5.3.15_add_accessibility_receiver_email_config.php33
-rw-r--r--lib/classes/forms/Form.php69
-rw-r--r--lib/classes/forms/Link.php166
-rw-r--r--lib/classes/forms/Part.php36
-rw-r--r--lib/classes/forms/Text.php72
-rw-r--r--lib/navigation/FooterNavigation.php9
-rw-r--r--locale/de/LC_MAILS/report_barrier.php21
-rw-r--r--locale/en/LC_MAILS/report_barrier.php21
-rw-r--r--templates/forms/form.php4
11 files changed, 599 insertions, 9 deletions
diff --git a/app/controllers/accessibility/forms.php b/app/controllers/accessibility/forms.php
new file mode 100644
index 0000000..71ab261
--- /dev/null
+++ b/app/controllers/accessibility/forms.php
@@ -0,0 +1,175 @@
+<?php
+class Accessibility_FormsController extends StudipController
+{
+ protected $with_session = true;
+
+ public function report_barrier_action()
+ {
+ PageLayout::setTitle(_('Barriere melden'));
+
+ $this->page = Request::get('page');
+
+ $user = User::findCurrent();
+ $user_salutation = '';
+ if (!empty($user)) {
+ if ($user->geschlecht == 1) {
+ $user_salutation = _('Herr');
+ } elseif ($user->geschlecht == 2) {
+ $user_salutation = _('Frau');
+ } elseif ($user->geschlecht == 3) {
+ $user_salutation = _('divers');
+ }
+ }
+
+ $this->form = \Studip\Forms\Form::create();
+ $this->form->addInput(
+ new \Studip\Forms\HiddenInput(
+ 'page',
+ '',
+ $this->page
+ )
+ );
+ $details_part = new \Studip\Forms\Fieldset(_('Angaben zur gefundenen Barriere'));
+ $details_part->addInput(
+ new \Studip\Forms\SelectInput(
+ 'barrier_type',
+ _('Um welche Art von Barriere handelt es sich?'),
+ '',
+ [
+ 'options' => [
+ _('Inhalte auf dieser Seite (z.B. PDF, Bilder oder Lernmodule)') => _('Inhalte auf dieser Seite (z.B. PDF, Bilder oder Lernmodule)'),
+ _('Ein Problem mit der Seite selbst oder der Navigation') => _('Ein Problem mit der Seite selbst oder der Navigation'),
+ _('Sonstiges') => _('Sonstiges')
+ ]
+ ]
+ )
+ )->setRequired();
+ $details_part->addInput(
+ new \Studip\Forms\TextareaInput(
+ 'barrier_details',
+ _('Beschreiben Sie die Barriere'),
+ ''
+ )
+ )->setRequired();
+ $this->form->addPart($details_part);
+ $personal_data_part = new \Studip\Forms\Fieldset(_('Ihre persönlichen Daten'));
+ $personal_data_part->addText(sprintf('<p>%s</p>', _('Geben Sie bitte Ihren Namen und Ihre E-Mail-Adresse an. Optional können Sie auch Ihre Telefonnummer angeben.')));
+ $personal_data_part->addInput(
+ new \Studip\Forms\SelectInput(
+ 'salutation',
+ _('Anrede'),
+ $user_salutation,
+ [
+ 'options' => [
+ _('Keine Angabe') => _('Keine Angabe'),
+ _('Frau') => _('Frau'),
+ _('Herr') => _('Herr'),
+ _('divers') => _('divers')
+ ]
+ ]
+ )
+ );
+ $personal_data_part->addInput(
+ new \Studip\Forms\TextInput(
+ 'name',
+ _('Vorname und Nachname'),
+ $user ? sprintf('%s %s', $user->vorname, $user->nachname) : ''
+ )
+ )->setRequired();
+ $personal_data_part->addInput(
+ new \Studip\Forms\TextInput(
+ 'phone_number',
+ _('Telefonnummer'),
+ $user ? ($user->privatcell ?: $user->privatnr) : ''
+ )
+ );
+ $personal_data_part->addInput(
+ new \Studip\Forms\TextInput(
+ 'email_address',
+ _('E-Mail-Adresse'),
+ $user ? $user->email : ''
+ )
+ )->setRequired();
+ $privacy_url = Config::get()->PRIVACY_URL;
+
+ if (is_internal_url($privacy_url)) {
+ $personal_data_part->addLink(
+ _('Datenschutzerklärung lesen'),
+ URLHelper::getURL($privacy_url, ['cancel_login' => '1']),
+ Icon::create('link-intern'),
+ ['data-dialog' => 'size=big']
+ );
+ } else {
+ $personal_data_part->addLink(
+ _('Datenschutzerklärung lesen'),
+ URLHelper::getURL($privacy_url),
+ Icon::create('link-extern'),
+ ['target' => '_blank']
+ );
+ }
+ $personal_data_part->addInput(
+ new \Studip\Forms\CheckboxInput(
+ 'confirm_privacy',
+ _('Ich habe die Datenschutzerklärung gelesen und akzeptiere sie.'),
+ ''
+ )
+ )->setRequired();
+ $this->form->addPart($personal_data_part);
+ $this->form->setSaveButtonText(_('Barriere melden'));
+ $this->form->setSaveButtonName('report');
+ $this->form->setURL($this->report_barrierURL());
+ $this->form->addStoreCallback(
+ function ($form, $form_values) {
+ $recipients = Config::get()->ACCESSIBILITY_RECEIVER_EMAIL;
+ if (empty($recipients)) {
+ //Fallback: Use the UNI_CONTACT mail address:
+ $recipients = [$GLOBALS['UNI_CONTACT']];
+ }
+ //Get the sender and their language:
+ $sender = User::findCurrent();
+ //Default to the system default language:
+ $lang = explode('_', $GLOBALS['DEFAULT_LANGUAGE'])[0];
+ if ($sender) {
+ //Use the senders language since the choices in the form
+ //are in their language as well.
+ $lang = explode('_', getUserLanguage($sender->id))[0];
+ }
+ //Format the senders name according to the salutation.
+ $formatted_name = '';
+ if ($form_values['salutation'] === _('Keine Angabe')) {
+ $formatted_name = $form_values['name'];
+ } elseif ($form_values['salutation'] === _('divers')) {
+ $formatted_name = sprintf('%s (%s)', $form_values['name'], $form_values['salutation']);
+ } else {
+ $formatted_name = sprintf('%s %s', $form_values['salutation'], $form_values['name']);
+ }
+ //Build the mail text:
+ $template = $GLOBALS['template_factory']->open("../locale/{$lang}/LC_MAILS/report_barrier.php");
+ $template->set_attributes([
+ 'sender' => $sender,
+ 'page' => $form_values['page'],
+ 'barrier_type' => $form_values['barrier_type'],
+ 'barrier_details' => $form_values['barrier_details'],
+ 'formatted_name' => $formatted_name,
+ 'phone_number' => $form_values['phone_number'],
+ 'email_address' => $form_values['email_address']
+ ]);
+ $mail_text = $template->render();
+
+ foreach ($recipients as $mail_address) {
+ //Send the mail:
+ $mail = new StudipMail();
+ $mail->addRecipient($mail_address)
+ ->setReplyToEmail($form_values['email_address'])
+ ->setSubject(_('Meldung einer Barriere in Stud.IP'))
+ ->setBodyText($mail_text)
+ ->send();
+ }
+
+ $form->setSuccessMessage(_('Ihre Meldung einer Barriere wurde weitergeleitet.'));
+ return 1;
+ }
+ );
+ $this->form->autoStore();
+ }
+}
diff --git a/app/views/accessibility/forms/report_barrier.php b/app/views/accessibility/forms/report_barrier.php
new file mode 100644
index 0000000..5dd8d7d
--- /dev/null
+++ b/app/views/accessibility/forms/report_barrier.php
@@ -0,0 +1,2 @@
+<?= MessageBox::info(_('Auf dieser Seite können Sie eine Barriere melden, die die Nutzbarkeit von Stud.IP für Sie einschränkt. Füllen Sie dazu das untenstehende Formular aus.'))->hideClose() ?></p>
+<?= $form->render() ?>
diff --git a/db/migrations/5.3.15_add_accessibility_receiver_email_config.php b/db/migrations/5.3.15_add_accessibility_receiver_email_config.php
new file mode 100644
index 0000000..d3d73c2
--- /dev/null
+++ b/db/migrations/5.3.15_add_accessibility_receiver_email_config.php
@@ -0,0 +1,33 @@
+<?php
+
+class AddAccessibilityReceiverEmailConfig extends Migration
+{
+ public function description()
+ {
+ return 'Adds the configuration ACCESSIBILITY_RECEIVER_EMAIL, if it doesn\'t exist yet.';
+ }
+
+ protected function up()
+ {
+ $db = DBManager::get();
+
+ $db->exec(
+ "INSERT IGNORE INTO `config`
+ (`field`, `type`, `range`, `value`, `section`, `description`, `mkdate`, `chdate`)
+ VALUES
+ (
+ 'ACCESSIBILITY_RECEIVER_EMAIL', 'array', 'global', '', 'accessibility',
+ 'Die E-Mail-Adressen der Personen, die beim Melden einer Barriere benachrichtigt werden sollen.',
+ UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
+ )"
+ );
+ }
+
+ protected function down()
+ {
+ $db = DBManager::get();
+
+ $db->exec("DELETE FROM `config_values` WHERE `field` = 'ACCESSIBILITY_RECEIVER_EMAIL'");
+ $db->exec("DELETE FROM `config` WHERE `field` = 'ACCESSIBILITY_RECEIVER_EMAIL'");
+ }
+}
diff --git a/lib/classes/forms/Form.php b/lib/classes/forms/Form.php
index b588ddb..ba0258d 100644
--- a/lib/classes/forms/Form.php
+++ b/lib/classes/forms/Form.php
@@ -6,7 +6,7 @@ class Form extends Part
{
//models:
- protected $afterStore = [];
+ protected $store_callbacks = [];
//internals
protected $inputs = [];
@@ -14,7 +14,12 @@ class Form extends Part
//appearance in html-form
protected $url = null;
+ protected $save_button_text = '';
+ protected $save_button_name = '';
+
protected $autoStore = false;
+ protected $success_message = '';
+
protected $collapsable = false;
//to identify a form element
@@ -57,6 +62,8 @@ class Form extends Part
final public function __construct(...$parts)
{
parent::__construct(...$parts);
+ //Set a default for the success message:
+ $this->success_message = _('Daten wurden gespeichert.');
}
/**
@@ -160,6 +167,48 @@ class Form extends Part
return $this->url;
}
+ /**
+ * Sets the text for the "save" button in the form.
+ *
+ * @param string $text The text for the button to save the form.
+ * @return $this
+ */
+ public function setSaveButtonText(string $text): Form
+ {
+ $this->save_button_text = $text;
+ return $this;
+ }
+
+ /**
+ * @return string The text for the "save" button in the form.
+ */
+ public function getSaveButtonText() : string
+ {
+ return $this->save_button_text ?: _('Speichern');
+ }
+
+ public function setSaveButtonName(string $name): Form
+ {
+ $this->save_button_name = $name;
+ return $this;
+ }
+
+ public function getSaveButtonName() : string
+ {
+ return $this->save_button_name ?: $this->getSaveButtonText();
+ }
+
+ public function setSuccessMessage(string $success_message): Form
+ {
+ $this->success_message = $success_message;
+ return $this;
+ }
+
+ public function getSuccessMessage() : string
+ {
+ return $this->success_message;
+ }
+
public function setCollapsable($collapsing = true)
{
$this->collapsable = $collapsing;
@@ -182,7 +231,9 @@ class Form extends Part
$this->autoStore = true;
if (\Request::isPost() && \Request::isAjax() && !\Request::isDialog()) {
$this->store();
- \PageLayout::postSuccess(_('Daten wurden gespeichert.'));
+ if ($this->success_message) {
+ \PageLayout::postSuccess($this->success_message);
+ }
page_close();
die();
}
@@ -200,9 +251,9 @@ class Form extends Part
* @param callable $c
* @return Form $this
*/
- public function addAfterStoreCallback(Callable $c)
+ public function addStoreCallback(Callable $c): Form
{
- $this->afterStore[] = $c;
+ $this->store_callbacks[] = $c;
return $this;
}
@@ -240,11 +291,15 @@ class Form extends Part
$stored = 0;
//store by each input
+ $all_values = [];
foreach ($this->getAllInputs() as $input) {
$value = $this->getStorableValueFromRequest($input);
if ($value !== null) {
$callback = $this->getStoringCallback($input);
- $stored += $callback($value, $input);
+ if (is_callable($callback)) {
+ $stored += $callback($value, $input);
+ }
+ $all_values[$input->getName()] = $value;
}
}
@@ -255,9 +310,9 @@ class Form extends Part
}
}
- foreach ($this->afterStore as $callback) {
+ foreach ($this->store_callbacks as $callback) {
if (is_callable($callback)) {
- $stored += call_user_func($callback, $this);
+ $stored += call_user_func($callback, $this, $all_values);
} else {
//throw warning if callback is not available:
if ($callback === null) {
diff --git a/lib/classes/forms/Link.php b/lib/classes/forms/Link.php
new file mode 100644
index 0000000..6f26f28
--- /dev/null
+++ b/lib/classes/forms/Link.php
@@ -0,0 +1,166 @@
+<?php
+namespace Studip\Forms;
+
+/**
+ * The Link class represents a part of a form that displays a link.
+ */
+class Link extends Part
+{
+ protected $url;
+ protected $label;
+ protected $icon;
+ protected $attributes = [];
+
+ public function __construct(string $url, string $label, \Icon $icon = null)
+ {
+ $this->url = $url;
+ $this->label = $label;
+ $this->icon = $icon;
+ }
+
+ /**
+ * Sets the url for the link.
+ *
+ * @param string $url
+ * @return $this
+ */
+ public function setURL(string $url): Link
+ {
+ $this->url = $url;
+ return $this;
+ }
+
+ /**
+ * Returns the url for the link.
+ * @return string
+ */
+ public function getURL(): string
+ {
+ return $this->url;
+ }
+
+ /**
+ * Sets the label for the link.
+ *
+ * @param string $label
+ * @return $this
+ */
+ public function setLabel(string $label): Link
+ {
+ $this->label = $label;
+ return $this;
+ }
+
+ /**
+ * Returns the label for the link.
+ *
+ * @return string
+ */
+ public function getLabel() : string
+ {
+ return $this->label;
+ }
+
+ /**
+ * Sets the icon for the link. May be null to remove the icon.
+ *
+ * @param \Icon $icon
+ * @return $this
+ */
+ public function setIcon(\Icon $icon = null): Link
+ {
+ $this->icon = $icon;
+ return $this;
+ }
+
+ /**
+ * Returns the icon for the link.
+ * @return \Icon|null
+ */
+ public function getIcon(): ?\Icon
+ {
+ return $this->icon;
+ }
+
+ /**
+ * Replaces all attributes for the link.
+ *
+ * @param array $attributes
+ * @return $this
+ */
+ public function setAttributes(array $attributes): Link
+ {
+ $this->attributes = $attributes;
+ return $this;
+ }
+
+ /**
+ * Adds/appends attributes to the current attributes for the link.
+ *
+ * @param array $attributes
+ * @return $this
+ */
+ public function addAttributes(array $attributes): Link
+ {
+ $this->attributes = array_merge($this->attributes, $attributes);
+ return $this;
+ }
+
+ /**
+ * Sets a single attribute for the link.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return $this
+ */
+ public function setAttribute(string $key, $value): Link
+ {
+ $this->attributes[$key] = $value;
+ return $this;
+ }
+
+ /**
+ * Returns the attributes for the link.
+ * @return array
+ */
+ public function getAttributes(): array
+ {
+ return $this->attributes;
+ }
+
+ /**
+ * Removes an attribute.
+ *
+ * @param string $key
+ * @param bool $throw_exception Throw an exception if the attribute does not exists (default: false)
+ * @return $this
+ */
+ public function removeAttribute(string $key, bool $throw_exception = false): Link
+ {
+ if (!isset($this->attributes[$key]) && $throw_exception) {
+ throw new \RuntimeException("No attribute {$key} defined");
+ }
+
+ if (isset($this->attributes[$key])) {
+ unset($this->attributes[$key]);
+ }
+
+ return $this;
+ }
+
+ /**
+ * "Renders" the text: Either return it directly, if it is HTML or call htmlReady first before returning it.
+ *
+ * @return string The text that shall be placed in the form, either as HTML or plain text.
+ */
+ public function render()
+ {
+ return sprintf(
+ '<div class="formpart"><a href="%1$s" %2$s>%3$s %4$s</a></div>',
+ \URLHelper::getLink($this->url, [], true),
+ arrayToHtmlAttributes($this->attributes),
+ $this->icon ? $this->icon->asImg(['class' => 'text-bottom']) : '',
+ htmlReady($this->label)
+ );
+ }
+}
diff --git a/lib/classes/forms/Part.php b/lib/classes/forms/Part.php
index 79c573b..4831945 100644
--- a/lib/classes/forms/Part.php
+++ b/lib/classes/forms/Part.php
@@ -77,6 +77,42 @@ abstract class Part
}
/**
+ * Adds a text block inside the form.
+ *
+ * @param string $text The text to be added.
+ * @param bool $text_is_html Whether the text is HTML (true) or plain text (false). Defaults to true.
+ * @return Text The added text form part.
+ */
+ public function addText(string $text, bool $text_is_html = true): Text
+ {
+ $text_part = new Text();
+ $text_part->setText($text, $text_is_html);
+ $text_part->setParent($this);
+ $this->parts[] = $text_part;
+ return $text_part;
+ }
+
+ /**
+ * Adds a link as a form part.
+ *
+ * @param string $title The title of the link.
+ * @param string $url The URL of the link.
+ * @param \Icon|null $icon The icon to be used for the link.
+ * @param array $attributes Additional link attributes.
+ *
+ * @return Link The Text form element containing the link as HTML.
+ */
+ public function addLink(string $title, string $url, ?\Icon $icon = null, array $attributes = []): Link
+ {
+ $link = new Link($url, $title, $icon);
+ $link->setAttributes($attributes);
+
+ $this->addPart($link);
+
+ return $link;
+ }
+
+ /**
* Renders this Part object. This could be a section or any other HTML element with child-elements.
* @return string
*/
diff --git a/lib/classes/forms/Text.php b/lib/classes/forms/Text.php
new file mode 100644
index 0000000..611ff83
--- /dev/null
+++ b/lib/classes/forms/Text.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace Studip\Forms;
+
+/**
+ * The Text class represents a part of a form that just displays text.
+ * The text can either be HTML or unformatted text.
+ */
+class Text extends Part
+{
+ /**
+ * The text to be displayed.
+ */
+ protected $text = '';
+
+ /**
+ * This attribute defines whether to interpret the text as HTML (true) or as plain text (false).
+ */
+ protected $text_is_html = true;
+
+ /**
+ * Sets the text that shall be displayed in this form part.
+ *
+ * @param string $text The text to be displayed.
+ * @param bool $text_is_html Whether the text is HTML (true) or plain text. Defaults to true.
+ * @return $this This form part.
+ */
+ public function setText(string $text, bool $text_is_html = true): Text
+ {
+ $this->text = $text;
+ $this->text_is_html = $text_is_html;
+ return $this;
+ }
+
+ /**
+ * @return string The "raw form" of the text that shall be displayed.
+ */
+ public function getText() : string
+ {
+ return $this->text;
+ }
+
+ /**
+ * @return bool Whether the text is HTML (true) or not (false).
+ */
+ public function isHtmlText() : bool
+ {
+ return $this->text_is_html;
+ }
+
+ /**
+ * "Renders" the text: Either return it directly, if it is HTML or call htmlReady first before returning it.
+ *
+ * @return string The text that shall be placed in the form, either as HTML or plain text.
+ */
+ public function render()
+ {
+ if ($this->text_is_html) {
+ return $this->text;
+ } else {
+ return htmlReady($this->text);
+ }
+ }
+
+ /**
+ * @see Text::render()
+ */
+ public function renderWithCondition()
+ {
+ return $this->render();
+ }
+}
diff --git a/lib/navigation/FooterNavigation.php b/lib/navigation/FooterNavigation.php
index a24dc11..ac62ff8 100644
--- a/lib/navigation/FooterNavigation.php
+++ b/lib/navigation/FooterNavigation.php
@@ -47,5 +47,14 @@ class FooterNavigation extends Navigation
$privacy_url = URLHelper::getURL($privacy_url, ['cancel_login' => '1']);
}
$this->addSubNavigation('privacy', new Navigation(_('Datenschutz'), $privacy_url));
+
+ $this->addSubNavigation(
+ 'report_barrier',
+ new Navigation(
+ _('Barriere melden'),
+ URLHelper::getURL('dispatch.php/accessibility/forms/report_barrier', ['page' => Request::url()]),
+ ['data-dialog' => '']
+ )
+ );
}
}
diff --git a/locale/de/LC_MAILS/report_barrier.php b/locale/de/LC_MAILS/report_barrier.php
new file mode 100644
index 0000000..7d7c28b
--- /dev/null
+++ b/locale/de/LC_MAILS/report_barrier.php
@@ -0,0 +1,21 @@
+Hallo,
+
+
+Die folgende Barriere, die Personen einschränkt bzw. behindert, wurde in Stud.IP entdeckt:
+
+<?= $barrier_type ?>
+
+
+<?= $barrier_details ?>
+
+
+Die Barriere befindet sich auf der Seite: <?= $page ?>
+
+
+Kontakt für Rückfragen:
+
+<?= $formatted_name ?>
+
+E-Mail: <?= $email_address ?>
+
+Telefon: <?= $phone_number ?>
diff --git a/locale/en/LC_MAILS/report_barrier.php b/locale/en/LC_MAILS/report_barrier.php
new file mode 100644
index 0000000..6f5907b
--- /dev/null
+++ b/locale/en/LC_MAILS/report_barrier.php
@@ -0,0 +1,21 @@
+Hello
+
+
+The following barrier which restrict or impede persons has been discovered in Stud.IP:
+
+<?= $barrier_type ?>
+
+
+<?= $barrier_details ?>
+
+
+The barrier has been found on the page: <?= $page ?>
+
+
+Contact details for request:
+
+<?= $formatted_name ?>
+
+E-Mail: <?= $email_address ?>
+
+Phone: <?= $phone_number ?>
diff --git a/templates/forms/form.php b/templates/forms/form.php
index 2e1a661..21eb9c8 100644
--- a/templates/forms/form.php
+++ b/templates/forms/form.php
@@ -62,12 +62,12 @@ $form_id = md5(uniqid());
</div>
<? if (!Request::isDialog()) : ?>
<footer>
- <?= \Studip\Button::create(_('Speichern'), null, ['form' => $form_id]) ?>
+ <?= \Studip\Button::create($form->getSaveButtonText(), $form->getSaveButtonName(), ['form' => $form_id]) ?>
</footer>
<? endif ?>
</form>
<? if (Request::isDialog()) : ?>
<footer data-dialog-button>
- <?= \Studip\Button::create(_('Speichern'), null, ['form' => $form_id]) ?>
+ <?= \Studip\Button::create($form->getSaveButtonText(), $form->getSaveButtonName(), ['form' => $form_id]) ?>
</footer>
<? endif ?>