Skip to content

Add possibility to subscribe to changes of language packs #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 34 commits into
base: MOODLE_36_STABLE
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e2aca87
Add amos_subscription database table
tobiasreischmann Sep 10, 2019
a634ca0
Started UI
Sep 10, 2019
d62a6b4
Add cron task for sending notifications to subscribers
tobiasreischmann Sep 10, 2019
643baf6
Added initial version of notify subscriber task
tobiasreischmann Sep 10, 2019
284fc0b
Move notifiaction subject to lang strings
tobiasreischmann Sep 11, 2019
f611ec8
Alter notification query and template
tobiasreischmann Sep 11, 2019
6cdefb7
Add branch to notify subscriber template and add comments
tobiasreischmann Sep 11, 2019
4ea9585
Enhanced mail with HTML tags
Kathrin84 Sep 11, 2019
6233903
Remove one sublevel of mustache templates
tobiasreischmann Sep 11, 2019
202a2c8
Fixed missing array initializiation
tobiasreischmann Sep 11, 2019
e02200a
Add subscription manager class and test
MartinGauk Sep 11, 2019
dcdecd1
Basic UI - form actions missing
Sep 11, 2019
38de627
Added some styling to the mail template.
Kathrin84 Sep 11, 2019
66c79d7
Added HTML content to email_to_user
Kathrin84 Sep 11, 2019
6596c42
Added plain text mail template.
Kathrin84 Sep 11, 2019
4abd3df
Account for html and plaintext mustache mail template
tobiasreischmann Sep 11, 2019
7834929
Alter subscription sql to not select the highest repo id but the newest
tobiasreischmann Sep 11, 2019
2b232ee
Fix wrong template name
tobiasreischmann Sep 11, 2019
ff1a1f2
Removed hr tag.
Kathrin84 Sep 11, 2019
3881b60
Inplace editable component languages
MartinGauk Sep 11, 2019
02ec08b
Initialize timesubnotified config
tobiasreischmann Sep 11, 2019
a0f5cb8
Add phpunit tests for notify subscribers
tobiasreischmann Sep 11, 2019
79d3d55
Fix old changes are send out to subscribers as well.
tobiasreischmann Sep 11, 2019
b45810e
Callback to remove user subscriptions when user will be deleted
MartinGauk Sep 11, 2019
cbec74b
Changed hardcoded strings to lang strings.
Kathrin84 Sep 11, 2019
9144532
Fixed wrong string reference.
Kathrin84 Sep 11, 2019
052b402
Hopefully fixed missing variable replacement.
Kathrin84 Sep 11, 2019
702bef2
Table UI ready (still needs some improvements)
Sep 11, 2019
9fbe9f1
Bugfix langstring
Sep 11, 2019
7a81276
Check component with isset
MartinGauk Sep 11, 2019
f5ca198
Documentation
MartinGauk Sep 11, 2019
296c761
Add more asserts to subscription manager test
MartinGauk Sep 11, 2019
9aa6bed
Use timelastrun as a parameter for sql query and also for innersql
tobiasreischmann Sep 11, 2019
b26d515
Added tests for notify_subscribers task
tobiasreischmann Sep 11, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions classes/local/subscription_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?php


// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* View your subscription and change settings
*
* @package local_amos
* @tags MoodleMootDACH2019
* @copyright 2019 Tobias Reischmann <[email protected]>
* @copyright 2019 Martin Gauk <[email protected]>
* @copyright 2019 Jan Eberhardt <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace local_amos\local;


use local_amos\subscription_manager;

defined('MOODLE_INTERNAL') || die();

global $CFG;

require_once $CFG->libdir . DIRECTORY_SEPARATOR . 'tablelib.php';
require_once $CFG->dirroot . '/local/amos/classes/subscription_manager.php';
require_once $CFG->dirroot . '/local/amos/mlanglib.php';

class subscription_table extends \flexible_table {

public function init($baseurl, $pagesize = -1)
{
global $USER;

$manager = new subscription_manager($USER->id);
$subs = $manager->fetch_subscriptions();

$this->define_baseurl($baseurl);
$this->define_columns([
'component',
'language'
]);
$this->define_headers([
get_string('component', 'local_amos'),
get_string('languages', 'local_amos')
]);
$this->pagesize($pagesize > 0 ? $pagesize : $this->pagesize, count($subs));
$this->sortable(true, 'component');
$this->no_sorting('language');
$this->setup();
}

public function out() {
global $USER;
$manager = new subscription_manager($USER->id);
$subs = $manager->fetch_subscriptions();
$sort = $this->get_sort_columns()['component'];
if ($sort === SORT_ASC) {
ksort($subs);
} else {
krsort($subs);
}
$this->start_output();
foreach ($subs as $component => $langarray) {
$row = $this->format_row([
'component' => $component,
'language' => $langarray
]);
$this->add_data_keyed($row);
}
$this->finish_output();
}

public function col_component($sub) {
global $PAGE;
$icon = $PAGE->get_renderer('local_amos')->pix_icon(
't/delete',
get_string('unsubscribe', 'local_amos')
);
$query_string = sprintf('?c=%s&m=unsubscribe', $sub->component);
$link = \html_writer::link($this->baseurl . $query_string, $icon, ['class' => 'unsubscribe']);
return sprintf('%s %s', $sub->component, $link);
}

public function col_language($sub) {
global $OUTPUT;

$inplace = self::get_lang_inplace_editable($sub->component, $sub->language);
return $OUTPUT->render_from_template('core/inplace_editable', $inplace->export_for_template($OUTPUT));
}

static public function get_lang_inplace_editable(string $component, array $langs) {
$options = \mlang_tools::list_languages(false);

$values = json_encode($langs);
$displayvalues = implode(', ', array_map(function($lang) use ($options) {
return (isset($options[$lang]))
? $options[$lang]
: get_string('unknown_language', 'local_amos', $lang);
}, $langs));

$inplace = new \core\output\inplace_editable('local_amos', 'subscription', $component,
true, $displayvalues, $values);

$attributes = ['multiple' => true];
$inplace->set_type_autocomplete($options, $attributes);

return $inplace;
}
}
189 changes: 189 additions & 0 deletions classes/subscription_manager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Provides the {@link subscription_manager} class.
*
* @package local_amos
* @copyright 2019 Tobias Reischmann <[email protected]>
* @copyright 2019 Martin Gauk <[email protected]>
* @copyright 2019 Jan Eberhardt <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace local_amos;

defined('MOODLE_INTERNAL') || die();

global $CFG;

require_once($CFG->dirroot.'/local/amos/mlanglib.php');

/**
* Manager class for accessing and updating the user's subscriptions.
*
* @copyright 2019 Tobias Reischmann <[email protected]>
* @copyright 2019 Martin Gauk <[email protected]>
* @copyright 2019 Jan Eberhardt <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class subscription_manager {
/** @var int user id */
private $userid;

/** @var array of array (component -> language) */
private $subscriptions;

/** @var array */
private $addsubscriptions;

/** @var array */
private $remsubscriptions;

/**
* Subscription manager constructor.
*
* @param int $userid user id
*/
public function __construct(int $userid) {
$this->userid = $userid;
$this->subscriptions = [];
$this->addsubscriptions = [];
$this->remsubscriptions = [];
}

/**
* Fetch all subscriptions of the user.
*
* @return array
*/
public function fetch_subscriptions() {
global $DB;

$this->subscriptions = [];
$rows = $DB->get_records('amos_subscription', ['userid' => $this->userid]);
foreach ($rows as $row) {
if (!isset($this->subscriptions[$row->component])) {
$this->subscriptions[$row->component] = [$row->lang];
} else {
$this->subscriptions[$row->component][] = $row->lang;
}
}

return $this->subscriptions;
}

/**
* Add new subscription.
*
* @param string $component component name
* @param string $lang language code
*/
public function add_subscription(string $component, string $lang) {
$this->addsubscriptions[] = (object) ['component' => $component, 'lang' => $lang];
}

/**
* Remove one subscription.
*
* @param string $component component name
* @param string $lang language code
*/
public function remove_subscription(string $component, string $lang) {
$this->remsubscriptions[] = (object) ['component' => $component, 'lang' => $lang];
}

/**
* Remove all language subscriptions of one component.
*
* @param string $component component name
*/
public function remove_component_subscription(string $component) {
$this->remsubscriptions[] = (object) ['component' => $component, 'lang' => null];
}

/**
* Apply all changes to the database.
*
* All changes that you registered with add_subscription, remove_subscription and remove_component_subscription.
*/
public function apply_changes() {
global $DB;

// Get available components and langs.
$components = \mlang_tools::list_components();
$langs = \mlang_tools::list_languages();

$transaction = $DB->start_delegated_transaction();

// Remove subscriptions.
foreach ($this->remsubscriptions as $sub) {
if ($sub->lang !== null) {
$DB->delete_records('amos_subscription', [
'userid' => $this->userid,
'component' => $sub->component,
'lang' => $sub->lang,
]);
} else {
$DB->delete_records('amos_subscription', [
'userid' => $this->userid,
'component' => $sub->component,
]);
}
}

// Refresh subscriptions to check for duplicates.
$this->fetch_subscriptions();

$inserts = [];
// Validate component names and language codes of subscriptions that should be added.
foreach ($this->addsubscriptions as $sub) {
if (!isset($components[$sub->component])) {
continue;
}

if (!isset($langs[$sub->lang])) {
continue;
}

// Check if not already subscribed.
if (isset($this->subscriptions[$sub->component]) &&
in_array($sub->lang, $this->subscriptions[$sub->component])) {
continue;
}

$sub->userid = $this->userid;
$inserts[] = $sub;
$this->subscriptions[$sub->component][] = $sub->lang;
}
$DB->insert_records('amos_subscription', $inserts);

$transaction->allow_commit();

// Reset list of changes.
$this->addsubscriptions = [];
$this->remsubscriptions = [];
}

/**
* Remove all subscriptions of the user.
*/
public function remove_all_subscriptions() {
global $DB;

$DB->delete_records('amos_subscription', ['userid' => $this->userid]);
}
}
83 changes: 83 additions & 0 deletions classes/task/notify_subscribers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Provides the {@link \local_amos\task\notify_subscribers} class.
*
* @package local_amos
* @category task
* @copyright 2019 Tobias Reischmann <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace local_amos\task;

defined('MOODLE_INTERNAL') || die();

require_once($CFG->dirroot . '/local/amos/locallib.php');

/**
* Sends notifications about changes of the language packs to the respective subsrcibers.
*
* @copyright 2019 Tobias Reischmann <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class notify_subscribers extends \core\task\scheduled_task {

/**
* Return the task name.
*
* @return string
*/
public function get_name() {
return get_string('tasknotifysubscribers', 'local_amos');
}

/**
* Execute the task.
*/
public function execute() {
global $DB, $PAGE;
$subject = get_string('subscription_mail_subject', 'local_amos');
$lasttimerun = get_config('local_amos', 'timesubnotified');
// For the very first run, we do not want to send out everything that ever happend.
// So we initialize the config with the date from yesterday.
if (!$lasttimerun) {
$today = strtotime('12:00:00');
$lasttimerun = strtotime('-1 day', $today);
}
$getsql = "SELECT distinct s.userid
FROM {amos_repository} r
JOIN {amos_subscription} s ON (s.lang = r.lang AND s.component = r.component)
WHERE r.timemodified > ?";

$users = $DB->get_records_sql($getsql, array($lasttimerun));
$output = $PAGE->get_renderer('local_amos');
foreach ($users as $user) {
$user = \core_user::get_user($user->userid);
if ($user) {
$notification_html = new \local_amos_sub_notification($user, $lasttimerun, true);
$notification = new \local_amos_sub_notification($user, $lasttimerun);

$content_html = $output->render($notification_html);
$content = $output->render($notification);
email_to_user($user, \core_user::get_noreply_user(), $subject, $content, $content_html);
}
}
set_config('timesubnotified', time(), 'local_amos');
}

}
Loading