Skip to content

Commit

Permalink
Merge branch 'wip-MDL-41285-master' of git://github.com/marinaglancy/…
Browse files Browse the repository at this point in the history
…moodle
  • Loading branch information
stronk7 committed Mar 25, 2014
2 parents 767a5a0 + 177052d commit eb4606a
Show file tree
Hide file tree
Showing 9 changed files with 589 additions and 40 deletions.
167 changes: 128 additions & 39 deletions blocks/recent_activity/block_recent_activity.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,54 +125,65 @@ protected function get_recent_enrolments() {
* 'module' - instance of cm_info (for 'delete mod' it is an object with attributes modname and modfullname)
*/
protected function get_structural_changes() {
global $DB, $CFG;
global $DB;
$course = $this->page->course;
$context = context_course::instance($course->id);
$canviewdeleted = has_capability('block/recent_activity:viewdeletemodule', $context);
$canviewupdated = has_capability('block/recent_activity:viewaddupdatemodule', $context);
if (!$canviewdeleted && !$canviewupdated) {
return;
}

$timestart = $this->get_timestart();
$changelist = array();
$logs = $DB->get_records_select('log',
"time > ? AND course = ? AND
module = 'course' AND
(action = 'add mod' OR action = 'update mod' OR action = 'delete mod')",
array($timestart, $course->id), "id ASC");
// The following query will retrieve the latest action for each course module in the specified course.
// Also the query filters out the modules that were created and then deleted during the given interval.
$sql = "SELECT
cmid, MIN(action) AS minaction, MAX(action) AS maxaction, MAX(modname) AS modname
FROM {block_recent_activity}
WHERE timecreated > ? AND courseid = ?
GROUP BY cmid
ORDER BY MAX(timecreated) ASC";
$params = array($timestart, $course->id);
$logs = $DB->get_records_sql($sql, $params);
if (isset($logs[0])) {
// If special record for this course and cmid=0 is present, migrate logs.
self::migrate_logs($course);
$logs = $DB->get_records_sql($sql, $params);
}
if ($logs) {
$modinfo = get_fast_modinfo($course);
$newgones = array(); // added and later deleted items
foreach ($logs as $key => $log) {
$info = explode(' ', $log->info);
foreach ($logs as $log) {
// We used aggregate functions since constants CM_CREATED, CM_UPDATED and CM_DELETED have ascending order (0,1,2).
$wasdeleted = ($log->maxaction == block_recent_activity_observer::CM_DELETED);
$wascreated = ($log->minaction == block_recent_activity_observer::CM_CREATED);

if (count($info) != 2) {
debugging("Incorrect log entry info: id = ".$log->id, DEBUG_DEVELOPER);
if ($wasdeleted && $wascreated) {
// Activity was created and deleted within this interval. Do not show it.
continue;
}

$modname = $info[0];
$instanceid = $info[1];

if ($log->action == 'delete mod') {
if (plugin_supports('mod', $modname, FEATURE_NO_VIEW_LINK, false)) {
// we should better call cm_info::has_view() because it can be
// dynamic. But there is no instance of cm_info now
} else if ($wasdeleted && $canviewdeleted) {
if (plugin_supports('mod', $log->modname, FEATURE_NO_VIEW_LINK, false)) {
// Better to call cm_info::has_view() because it can be dynamic.
// But there is no instance of cm_info now.
continue;
}
// unfortunately we do not know if the mod was visible
if (!array_key_exists($log->info, $newgones)) {
$changelist[$log->info] = array('action' => $log->action,
'module' => (object)array(
'modname' => $modname,
'modfullname' => get_string('modulename', $modname)
));
}
} else {
if (!isset($modinfo->instances[$modname][$instanceid])) {
if ($log->action == 'add mod') {
// do not display added and later deleted activities
$newgones[$log->info] = true;
}
continue;
}
$cm = $modinfo->instances[$modname][$instanceid];
if ($cm->has_view() && $cm->uservisible && empty($changelist[$log->info])) {
$changelist[$log->info] = array('action' => $log->action, 'module' => $cm);
// Unfortunately we do not know if the mod was visible.
$modnames = get_module_types_names();
$changelist[$log->cmid] = array('action' => 'delete mod',
'module' => (object)array(
'modname' => $log->modname,
'modfullname' => $modnames[$log->modname]
));

} else if (!$wasdeleted && isset($modinfo->cms[$log->cmid]) && $canviewupdated) {
// Module was either added or updated during this interval and it currently exists.
// If module was both added and updated show only "add" action.
$cm = $modinfo->cms[$log->cmid];
if ($cm->has_view() && $cm->uservisible) {
$changelist[$log->cmid] = array(
'action' => $wascreated ? 'add mod' : 'update mod',
'module' => $cm
);
}
}
}
Expand Down Expand Up @@ -216,5 +227,83 @@ protected function get_modules_recent_activity() {
function applicable_formats() {
return array('all' => true, 'my' => false, 'tag' => false);
}

/**
* Remove old entries from table block_recent_activity
*/
public function cron() {
global $DB;
// Those entries will never be displayed as RECENT anyway.
$DB->delete_records_select('block_recent_activity', 'timecreated < ?',
array(time() - COURSE_MAX_RECENT_PERIOD));
}

/**
* Migrates entries from table {log} into {block_recent_activity}
*
* We only migrate logs for the courses that actually have recent activity
* block and that are being viewed within COURSE_MAX_RECENT_PERIOD time
* after the upgrade.
*
* The presence of entry in {block_recent_activity} with the cmid=0 indicates
* that the course needs log migration. Those entries were installed in
* db/upgrade.php when the table block_recent_activity was created.
*
* @param stdClass $course
*/
protected static function migrate_logs($course) {
global $DB;
if (!$logstarted = $DB->get_record('block_recent_activity',
array('courseid' => $course->id, 'cmid' => 0),
'id, timecreated')) {
return;
}
$DB->delete_records('block_recent_activity', array('id' => $logstarted->id));
try {
$logs = $DB->get_records_select('log',
"time > ? AND time < ? AND course = ? AND
module = 'course' AND
(action = 'add mod' OR action = 'update mod' OR action = 'delete mod')",
array(time()-COURSE_MAX_RECENT_PERIOD, $logstarted->timecreated, $course->id),
'id ASC', 'id, time, userid, cmid, action, info');
} catch (Exception $e) {
// Probably table {log} was already removed.
return;
}
if (!$logs) {
return;
}
$modinfo = get_fast_modinfo($course);
$entries = array();
foreach ($logs as $log) {
$info = explode(' ', $log->info);
if (count($info) != 2) {
continue;
}
$modname = $info[0];
$instanceid = $info[1];
$entry = array('courseid' => $course->id, 'userid' => $log->userid,
'timecreated' => $log->time, 'modname' => $modname);
if ($log->action == 'delete mod') {
if (!$log->cmid) {
continue;
}
$entry['action'] = 2;
$entry['cmid'] = $log->cmid;
} else {
if (!isset($modinfo->instances[$modname][$instanceid])) {
continue;
}
$entry['cmid'] = $modinfo->instances[$modname][$instanceid]->id;
if ($log->action == 'add mod') {
$entry['action'] = 0;
} else {
$entry['action'] = 1;
}
}
$entries[] = $entry;
}
$DB->insert_records('block_recent_activity', $entries);
}
}

73 changes: 73 additions & 0 deletions blocks/recent_activity/classes/observer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?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/>.

/**
* Event observer.
*
* @package block_recent_activity
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

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

/**
* Event observer.
* Stores all actions about modules create/update/delete in plugin own's table.
* This allows the block to avoid expensive queries to the log table.
*
* @package block_recent_activity
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class block_recent_activity_observer {

/** @var int indicates that course module was created */
const CM_CREATED = 0;
/** @var int indicates that course module was udpated */
const CM_UPDATED = 1;
/** @var int indicates that course module was deleted */
const CM_DELETED = 2;

/**
* Store all actions about modules create/update/delete in own table.
*
* @param \core\event\base $event
*/
public static function store(\core\event\base $event) {
global $DB;
$eventdata = new \stdClass();
switch ($event->eventname) {
case '\core\event\course_module_created':
$eventdata->action = self::CM_CREATED;
break;
case '\core\event\course_module_updated':
$eventdata->action = self::CM_UPDATED;
break;
case '\core\event\course_module_deleted':
$eventdata->action = self::CM_DELETED;
$eventdata->modname = $event->other['modulename'];
break;
default:
return;
}
$eventdata->timecreated = $event->timecreated;
$eventdata->courseid = $event->courseid;
$eventdata->cmid = $event->objectid;
$eventdata->userid = $event->userid;
$DB->insert_record('block_recent_activity', $eventdata);
}
}
16 changes: 16 additions & 0 deletions blocks/recent_activity/db/access.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,20 @@

'clonepermissionsfrom' => 'moodle/site:manageblocks'
),

'block/recent_activity:viewaddupdatemodule' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => array(
'user' => CAP_ALLOW
)
),

'block/recent_activity:viewdeletemodule' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => array(
'user' => CAP_ALLOW
)
)
);
47 changes: 47 additions & 0 deletions blocks/recent_activity/db/events.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?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/>.

/**
* Event observer.
*
* @package block_recent_activity
* @category event
* @copyright 2014 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

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

$observers = array (
array (
'eventname' => '\core\event\course_module_created',
'callback' => 'block_recent_activity_observer::store',
'internal' => false, // This means that we get events only after transaction commit.
'priority' => 1000,
),
array (
'eventname' => '\core\event\course_module_updated',
'callback' => 'block_recent_activity_observer::store',
'internal' => false, // This means that we get events only after transaction commit.
'priority' => 1000,
),
array (
'eventname' => '\core\event\course_module_deleted',
'callback' => 'block_recent_activity_observer::store',
'internal' => false, // This means that we get events only after transaction commit.
'priority' => 1000,
),
);
25 changes: 25 additions & 0 deletions blocks/recent_activity/db/install.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="blocks/recent_activity/db" VERSION="20140120" COMMENT="XMLDB file for Moodle blocks/recent_activity"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="block_recent_activity" COMMENT="Recent activity block">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Course id"/>
<FIELD NAME="cmid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Course module id"/>
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="User performing the action"/>
<FIELD NAME="action" TYPE="int" LENGTH="1" NOTNULL="true" SEQUENCE="false" COMMENT="0 created, 1 updated, 2 deleted"/>
<FIELD NAME="modname" TYPE="char" LENGTH="20" NOTNULL="false" SEQUENCE="false" COMMENT="module type name (for delete action)"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="coursetime" UNIQUE="false" FIELDS="courseid, timecreated"/>
</INDEXES>
</TABLE>
</TABLES>
</XMLDB>
Loading

0 comments on commit eb4606a

Please sign in to comment.