Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
a4d68c4
use mail manager to send mails
TamaroWalter May 14, 2025
a3a6e89
delete send_mail in lib
TamaroWalter May 14, 2025
284a864
rename tasks, take lib back
TamaroWalter May 17, 2025
1076f06
merge with hotfix PR
TamaroWalter May 21, 2025
e973a80
move send_mails() to mailmanager
TamaroWalter May 21, 2025
1585d64
code cleaning
TamaroWalter May 21, 2025
a71723f
WIP: minimize function
TamaroWalter May 21, 2025
b432815
new mail class, WIP: sql
TamaroWalter Jun 4, 2025
c5790f6
sql query complete
TamaroWalter Jun 6, 2025
0178fa7
add field help text
TamaroWalter Jun 8, 2025
06ffb6c
WIP: rewrite send_mails
TamaroWalter Jun 8, 2025
79efa95
complete new process function
TamaroWalter Jun 11, 2025
7aa2ce0
code styling
TamaroWalter Jun 11, 2025
3f98e4d
phpdoc cleaning
TamaroWalter Jun 11, 2025
5cfbd18
phpdoc cleaning
TamaroWalter Jun 11, 2025
5bfaac7
remove unnecessary functions
TamaroWalter Jun 11, 2025
e888211
begin mail testing
TamaroWalter Jun 12, 2025
f7685af
little changes
TamaroWalter Jun 12, 2025
ce4dbc2
basic mail tests functions
TamaroWalter Jun 24, 2025
46443b8
wip: work on mail tests
TamaroWalter Jul 2, 2025
784a161
little changes
TamaroWalter Jul 7, 2025
c8dc012
Sync with Learnweb's centralized pull request template
github-actions[bot] Jul 7, 2025
1b213f9
use now reply user as sender
TamaroWalter Jul 9, 2025
5294ff8
add forced subscriptions to sql
TamaroWalter Jul 9, 2025
ead0767
access parameter directly
TamaroWalter Jul 9, 2025
4169f19
codecleaning
TamaroWalter Jul 9, 2025
cbb6fca
add mail digest function
TamaroWalter Jul 9, 2025
f606000
WIP: try to show mail in html
TamaroWalter Jul 10, 2025
c5e7b12
add recipient information
TamaroWalter Jul 13, 2025
b773bb1
improve message parameters
TamaroWalter Jul 14, 2025
465f293
add userto mail format fields
TamaroWalter Jul 14, 2025
d5ef6a0
replace message send function
TamaroWalter Jul 14, 2025
8d245cd
pull from update branch
TamaroWalter Jul 14, 2025
60c4819
WIP: adapt tests to new mail structure
TamaroWalter Jul 14, 2025
30ba955
fix typo
TamaroWalter Jul 17, 2025
4e6bc0b
remove redundant declaration
TamaroWalter Jul 17, 2025
dcb0dcd
adapt to new notification mail system
TamaroWalter Jul 17, 2025
a79d4d4
adapt dailymail to new mail system
TamaroWalter Jul 17, 2025
ff37a92
remove debugging statements
TamaroWalter Jul 17, 2025
642ac3e
add todo for further development
TamaroWalter Jul 17, 2025
8135603
Merge branch 'main' of github.com:learnweb/moodle-mod_moodleoverflow …
TamaroWalter Jul 17, 2025
83af04c
merge with changes from main
TamaroWalter Jul 25, 2025
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
771 changes: 304 additions & 467 deletions classes/manager/mail_manager.php

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions classes/output/moodleoverflow_email.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
namespace mod_moodleoverflow\output;

use mod_moodleoverflow\anonymous;
use mod_moodleoverflow\subscriptions;

/**
* Moodleoverflow email renderable for use in e-mail.
Expand Down Expand Up @@ -251,8 +252,7 @@ public function __set($name, $value) {
public function get_unsubscribediscussionlink() {

// Check whether the moodleoverflow is subscribable.
$subscribable = \mod_moodleoverflow\subscriptions::is_subscribable($this->moodleoverflow,
\context_module::instance($this->cm->id));
$subscribable = subscriptions::is_subscribable($this->moodleoverflow, \context_module::instance($this->cm->id));
if (!$subscribable) {
return null;
}
Expand Down Expand Up @@ -432,7 +432,7 @@ public function get_replylink() {
* @return string
*/
public function get_unsubscribemoodleoverflowlink() {
if (!\mod_moodleoverflow\subscriptions::is_subscribable($this->moodleoverflow,
if (!subscriptions::is_subscribable($this->moodleoverflow,
\context_module::instance($this->cm->id))) {
return null;
}
Expand Down
7 changes: 2 additions & 5 deletions classes/subscriptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -536,11 +536,8 @@ public static function get_subscribed_users($moodleoverflow, $context, $fields =

// Default fields if none are submitted.
if (empty($fields)) {
if ($CFG->branch >= 311) {
$allnames = \core_user\fields::for_name()->get_sql('u', false, '', '', false)->selects;
} else {
$allnames = get_all_user_name_fields(true, 'u');
}
$allnames = \core_user\fields::for_name()->get_sql('u', false, '', '', false)->selects;

$fields = "u.id, u.username, $allnames, u.maildisplay, u.mailformat, u.maildigest,
u.imagealt, u.email, u.emailstop, u.city, u.country, u.lastaccess, u.lastlogin,
u.picture, u.timezone, u.theme, u.lang, u.trackforums, u.mnethostid";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@
/**
* This task sends a daily mail of unread posts
*/
class send_daily_mail extends \core\task\scheduled_task {
class send_daily_mails extends \core\task\scheduled_task {

/**
* Return the task's name as shown in admin screens.
*
* @return string
*/
public function get_name() {
return get_string('tasksenddailymail', 'mod_moodleoverflow');
return get_string('tasksenddailymails', 'mod_moodleoverflow');
}

/**
Expand Down Expand Up @@ -88,7 +88,7 @@ public function execute() {
$message = implode('<br>', $mail);
$userto = $DB->get_record('user', ['id' => $user->userid]);
$from = \core_user::get_noreply_user();
$subject = get_string('tasksenddailymail', 'mod_moodleoverflow');
$subject = get_string('tasksenddailymails', 'mod_moodleoverflow');
email_to_user($userto, $from, $subject, $message);
$DB->delete_records('moodleoverflow_mail_info', ['userid' => $user->userid]);
}
Expand Down
144 changes: 21 additions & 123 deletions classes/task/send_mails.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,151 +18,49 @@
* A scheduled task for moodleoverflow cron.
*
* @package mod_moodleoverflow
* @copyright 2017 Kennet Winter <[email protected]>
* @copyright 2025 Tamaro Walter
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace mod_moodleoverflow\task;

use core\session\exception;
use mod_moodleoverflow\anonymous;
use mod_moodleoverflow\output\moodleoverflow_email;

defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/../../locallib.php');
use coding_exception;
use core\notification;
use Exception;
use lang_string;
use mod_moodleoverflow\manager\mail_manager;

/**
* Class for sending mails to users who have subscribed a moodleoverflow.
* Class for sending mails to users that need to review a moodleoverflow post.
*
* @package mod_moodleoverflow
* @copyright 2017 Kennet Winter <[email protected]>
* @copyright 2025 Tamaro Walter
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class send_mails extends \core\task\scheduled_task {

/**
* Get a descriptive name for this task (shown to admins).
* Get a descriptive name for this task (shwon to admins).
*
* @return string
* @return lang_string|string
* @throws coding_exception
*/
public function get_name() {
public function get_name(): lang_string|string {
return get_string('tasksendmails', 'mod_moodleoverflow');
}

/**
* Runs moodleoverflow cron.
*
* @return bool
*/
public function execute() {

// Send mail notifications.
moodleoverflow_send_mails();

$this->send_review_notifications();

// The cron is finished.
return true;

}

/**
* Sends initial notifications for needed reviews to all users with review capability.
*/
public function send_review_notifications() {
global $DB, $OUTPUT, $PAGE, $CFG;

$rendererhtml = $PAGE->get_renderer('mod_moodleoverflow', 'email', 'htmlemail');
$renderertext = $PAGE->get_renderer('mod_moodleoverflow', 'email', 'textemail');

$postinfos = $DB->get_records_sql(
'SELECT p.*, d.course as cid, d.moodleoverflow as mid, d.id as did FROM {moodleoverflow_posts} p ' .
'JOIN {moodleoverflow_discussions} d ON p.discussion = d.id ' .
"WHERE p.mailed = :mailpending AND p.reviewed = 0 AND p.created < :timecutoff " .
"ORDER BY d.course, d.moodleoverflow, d.id",
[
'mailpending' => MOODLEOVERFLOW_MAILED_PENDING,
'timecutoff' => time() - get_config('moodleoverflow', 'reviewpossibleaftertime'),
]
);

if (empty($postinfos)) {
mtrace('No review notifications to send.');
return;
}

$course = null;
$moodleoverflow = null;
$usersto = null;
$cm = null;
$discussion = null;
$success = [];

foreach ($postinfos as $postinfo) {
if ($course == null || $course->id != $postinfo->cid) {
$course = get_course($postinfo->cid);
}

if ($moodleoverflow == null || $moodleoverflow->id != $postinfo->mid) {
$cm = get_coursemodule_from_instance('moodleoverflow', $postinfo->mid, 0, false, MUST_EXIST);
$modulecontext = \context_module::instance($cm->id);
$userswithcapability = get_users_by_capability($modulecontext, 'mod/moodleoverflow:reviewpost');
$coursecontext = \context_course::instance($course->id);
$usersenrolled = get_enrolled_users($coursecontext);
$usersto = [];
foreach ($userswithcapability as $user) {
if (in_array($user, $usersenrolled)) {
array_push($usersto, $user);
}
}

$moodleoverflow = $DB->get_record('moodleoverflow', ['id' => $postinfo->mid], '*', MUST_EXIST);
}

if ($discussion == null || $discussion->id != $postinfo->did) {
$discussion = $DB->get_record('moodleoverflow_discussions', ['id' => $postinfo->did], '*', MUST_EXIST);
}

$post = $postinfo;
$userfrom = \core_user::get_user($postinfo->userid, '*', MUST_EXIST);
$userfrom->anonymous = anonymous::is_post_anonymous($discussion, $moodleoverflow, $postinfo->userid);

foreach ($usersto as $userto) {
try {
// Check for moodle version. Version 401 supported until 8 December 2025.
if ($CFG->branch >= 402) {
\core\cron::setup_user($userto, $course);
} else {
cron_setup_user($userto, $course);
}

$maildata = new moodleoverflow_email($course, $cm, $moodleoverflow, $discussion,
$post, $userfrom, $userto, false);

$textcontext = $maildata->export_for_template($renderertext, true);
$htmlcontext = $maildata->export_for_template($rendererhtml, false);

email_to_user(
$userto,
\core_user::get_noreply_user(),
get_string('email_review_needed_subject', 'moodleoverflow', $textcontext),
$OUTPUT->render_from_template('mod_moodleoverflow/email_review_needed_text', $textcontext),
$OUTPUT->render_from_template('mod_moodleoverflow/email_review_needed_html', $htmlcontext)
);
} catch (exception $e) {
mtrace("Error sending review notification for post $post->id to user $userto->id!");
}
}
$success[] = $post->id;
}

if (!empty($success)) {
list($insql, $inparams) = $DB->get_in_or_equal($success);
$DB->set_field_select(
'moodleoverflow_posts', 'mailed', MOODLEOVERFLOW_MAILED_REVIEW_SUCCESS,
'id ' . $insql, $inparams
);
mtrace('Sent review notifications for ' . count($success) . ' posts successfully!');
public function execute(): bool {
try {
mail_manager::moodleoverflow_send_mails();
} catch (Exception $e) {
notification::error(get_string('error_sending_mails', 'mod_moodleoverflow', $e->getMessage()));
return false;
}
return true;
}

}

Loading
Loading