Commit a8b6cdf7 authored by Penny Leach's avatar Penny Leach
Browse files

Massive refactor of the activity stuff to support plugins generating activity.

parent b29838eb
......@@ -54,7 +54,7 @@ if ($markasread) {
// normal processing
$type = param_alpha('type', 'all');
$type = param_alphanum('type', 'all');
$limit = param_integer('limit', 10);
$offset = param_integer('offset', 0);
......@@ -62,23 +62,26 @@ $userid = $USER->get('id');
if ($type == 'all') {
$count = count_records('notification_internal_activity', 'usr', $userid);
$records = get_records_array('notification_internal_activity', 'usr', $userid,
'ctime DESC', '*', $offset, $limit);
$sql = 'SELECT a.*, at.name AS type,at.plugintype, at.pluginname FROM {notification_internal_activity} a
JOIN {activity_type} at ON a.type = at.id
WHERE a.usr = ? ORDER BY ctime DESC';
$records = get_records_sql_array($sql, array($userid), $offset, $limit);
} else if ($type == 'adminmessages' && $USER->get('admin')) {
$count = count_records_select('notification_internal_activity', 'usr = ? AND type IN (
SELECT name FROM {activity_type} WHERE admin = ?)',
SELECT id FROM {activity_type} WHERE admin = ?)',
array($userid, 1));
$records = get_records_select_array('notification_internal_activity', 'usr = ? AND type IN (
SELECT name FROM {activity_type} WHERE admin = ?)',
array($userid, 1),
'ctime DESC', '*', $offset, $limit);
$sql = 'SELECT a.*, at.name AS type,at.plugintype, at.pluginname FROM {notification_internal_activity} a
JOIN {activity_type} at ON a.type = at.id
WHERE a.usr = ? AND at.admin = ? ORDER BY ctime DESC';
$records = get_records_sql_array($sql, array($userid, 1), $offset, $limit);
}
else {
$count = count_records_select('notification_internal_activity', 'usr = ? AND type = ?',
array($userid,$type));
$records = get_records_select_array('notification_internal_activity', 'usr = ? AND type = ?',
array($userid, $type),
'ctime DESC', '*', $offset, $limit);
$sql = 'SELECT a.*, at.name AS type,at.plugintype, at.pluginname FROM {notification_internal_activity} a
JOIN {activity_type} at ON a.type = at.id
WHERE a.usr = ? AND a.type = ?';
$records = get_records_sql_array($sql, array($userid, $type), $offset, $limit);
}
if (empty($records)) {
......@@ -90,7 +93,11 @@ $unread = get_string('unread', 'activity');
foreach ($records as &$r) {
$r->date = format_date(strtotime($r->ctime));
$r->type = get_string('type' . $r->type, 'activity');
$section = 'activity';
if (!empty($r->plugintype)) {
$section = $r->plugintype . '.' . $r->pluginname;
}
$r->type = get_string('type' . $r->type, $section);
$r->message = format_whitespace($r->message);
}
......
......@@ -32,10 +32,18 @@ define('SECTION_PAGE', 'activity');
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
$types = get_records_array('activity_type', 'admin', 0);
$types = get_records_assoc('activity_type', 'admin', 0, 'plugintype,pluginname,name', 'id,name,plugintype,pluginname');
$types = array_map(create_function('$a', '
if (!empty($a->plugintype)) {
$section = "{$a->plugintype}.{$a->pluginname}";
}
else {
$section = "activity";
}
return get_string("type" . $a->name, $section);
'), $types);
if ($USER->get('admin')) {
$admintypes = get_records_array('activity_type');
$types[] = (object)array('name' => 'adminmessages');
$types['adminmessages'] = get_string('typeadminmessages', 'activity');
}
$morestr = get_string('more...');
......
......@@ -56,18 +56,24 @@ foreach ($activitytypes as $type) {
$dv = 'internal';
}
}
$elements[$type->name] = array(
if (!empty($type->plugintype)) {
$section = $type->plugintype . '.' . $type->pluginname;
}
else {
$section = 'activity';
}
$elements[$type->id] = array(
'defaultvalue' => $dv,
'type' => 'select',
'title' => get_string('type' . $type->name, 'activity'),
'title' => get_string('type' . $type->name, $section),
'options' => $options,
'rules' => array(
'required' => true
)
);
if (!empty($type->admin)) {
$elements[$type->name]['rules']['required'] = false;
$elements[$type->name]['options']['none'] = get_string('none');
$elements[$type->id]['rules']['required'] = false;
$elements[$type->id]['options']['none'] = get_string('none');
}
}
......@@ -98,11 +104,11 @@ function activityprefs_submit(Pieform $form, $values) {
$userid = $USER->get('id');
foreach ($activitytypes as $type) {
if ($values[$type->name] == 'none') {
$USER->set_activity_preference($type->name, null);
if ($values[$type->id] == 'none') {
$USER->set_activity_preference($type->id, null);
}
else {
$USER->set_activity_preference($type->name, $values[$type->name]);
$USER->set_activity_preference($type->id, $values[$type->id]);
}
}
$form->json_reply(PIEFORM_OK, get_string('prefssaved', 'account'));
......
......@@ -73,7 +73,7 @@ function adminusers_submit(Pieform $form, $values) {
SET admin = 1
WHERE id IN (' . join(',', $values['users']) . ')');
execute_sql('DELETE FROM {usr_activity_preference}
WHERE activity IN (SELECT name FROM {activity_type}
WHERE activity IN (SELECT id FROM {activity_type}
WHERE admin = 1)
AND usr NOT IN (' . join(',', $values['users']) . ')');
db_commit();
......
......@@ -35,16 +35,22 @@ define('SECTION_PAGE', 'notifications');
require_once('pieforms/pieform.php');
$sql = 'SELECT u.*, a.activity, a.method
$sql = 'SELECT u.*, a.activity, a.method
FROM {usr} u
LEFT JOIN {usr_activity_preference} a ON a.usr = u.id
WHERE u.admin = ?';
$admins = get_records_sql_array($sql, array(1));
$types = get_column('activity_type', 'name', 'admin', 1);
$types = array_flip($types);
foreach (array_keys($types) as $k) {
$types[$k] = get_string('type' . $k, 'activity');
$temptypes = get_records_array('activity_type', 'admin', 1);
$types = array();
foreach ($temptypes as $t) {
if (empty($t->plugintype)) {
$section = 'activity';
}
else {
$section = $t->plugintype . '.' . $t->pluginname;
}
$types[$t->id] = get_string('type' . $t->name, $section);
}
$users = array();
foreach ($admins as $u) {
......
......@@ -256,7 +256,7 @@ class User {
* This function returns a method for a particular
* activity type, or null if it's not set.
*
* @param string $key the activity type
* @param int $key the activity type id
*/
public function get_activity_preference($key) {
$activityprefs = $this->get('activityprefs');
......
......@@ -5,4 +5,5 @@ $string['nameplural'] = 'Forums';
$string['addtitle'] = 'Add forum';
$string['edittitle'] = 'Edit forum';
$string['typenewpost'] = 'New post';
?>
......@@ -5,6 +5,16 @@ class PluginInteractionForum extends PluginInteraction {
public static function instance_config_form($instance=null) {
return array();
}
public static function get_activity_types() {
return array(
(object)array(
'name' => 'newpost',
'admin' => 0,
'delay' => 1,
)
);
}
}
class InteractionForumInstance extends InteractionInstance {
......@@ -15,5 +25,13 @@ class InteractionForumInstance extends InteractionInstance {
}
class ActivityTypeInteractionForumNewPost extends ActivityType {
public function get_required_parameters() {
return array();
}
}
?>
<?php
$config->version = 2007111300;
$config->version = 2007111303;
$config->release = '0.1';
?>
......@@ -33,14 +33,11 @@ defined('INTERNAL') || die();
* @param string $activitytype type of activity
* @param mixed $data data
*/
function activity_occurred($activitytype, $data) {
if (!$at = get_record('activity_type', 'name', $activitytype)) {
throw new Exception("Invalid activity type $activitytype");
}
function activity_occurred($activitytype, $data, $plugintype=null, $pluginname=null) {
$at = activity_locate_typerecord($activitytype, $plugintype, $pluginname);
if (!empty($at->delay)) {
$delayed = new StdClass;
$delayed->type = $activitytype;
$delayed->type = $at->id;
$delayed->data = serialize($data);
$delayed->ctime = db_format_timestamp(time());
insert_record('activity_queue', $delayed);
......@@ -74,21 +71,9 @@ function activity_occurred($activitytype, $data) {
*/
function handle_activity($activitytype, $data, $cron=false) {
// mysql compatibility (sigh...)
$casturl = 'CAST(? AS TEXT)';
if (get_config('dbtype') == 'mysql') {
$casturl = 'CAST(? AS CHAR)'; // note, NOT varchar
}
$data = (object)$data;
if (is_string($activitytype)) {
$activitytype = get_record('activity_type', 'name', $activitytype);
}
if (!is_object($activitytype)) {
throw new InvalidArgumentException("Invalid activitytype $activitytype");
}
$activitytype = activity_locate_typerecord($activitytype);
$classname = 'ActivityType' . ucfirst($activitytype->name);
if (!empty($activitytype->plugintype)) {
......@@ -106,7 +91,7 @@ function handle_activity($activitytype, $data, $cron=false) {
$data = $activity->to_stdclass();
safe_require('notification', 'internal', 'lib.php', 'require_once');
$data->type = $activity->get_type();
$data->type = $activity->get_id();
foreach ($activity->get_users() as $user) {
$userdata = $data;
// some stuff gets overridden by user specific stuff
......@@ -144,7 +129,7 @@ function handle_activity($activitytype, $data, $cron=false) {
* for a particular activitytype
* including the notification method.
*
* @param string $activitytype the name of the activity type
* @param int $activitytype the id of the activity type
* @param array $userids an array of userids to filter by
* @param array $userobjs an array of user objects to filterby
* @param bool $adminonly whether to filter by admin flag
......@@ -201,7 +186,7 @@ function activity_process_queue() {
}
function activity_get_viewaccess_users($view, $owner, $type) {
$type = activity_locate_typerecord($type);
$sql = 'SELECT userid, u.*, p.method
FROM (
SELECT (CASE WHEN usr1 = ? THEN usr2 ELSE usr1 END) AS userid
......@@ -224,13 +209,35 @@ function activity_get_viewaccess_users($view, $owner, $type) {
JOIN {usr} u ON u.id = userlist.userid
LEFT JOIN {usr_activity_preference} p ON p.usr = u.id
WHERE p.activity = ?';
$values = array($owner, $owner, $owner, 'friends', $view, $view, $view, 0, 1, $view, $type);
$values = array($owner, $owner, $owner, 'friends', $view, $view, $view, 0, 1, $view, $type->id);
if (!$u = get_records_sql_assoc($sql, $values)) {
$u = array();
}
return $u;
}
function activity_locate_typerecord($activitytype, $plugintype=null, $pluginname=null) {
if (is_object($activitytype)) {
return $activitytype;
}
if (is_numeric($activitytype)) {
$at = get_record('activity_type', 'id', $activitytype);
}
else {
if (empty($plugintype) && empty($pluginname)) {
$at = get_record_select('activity_type',
'name = ? AND plugintype IS NULL AND pluginname IS NULL',
array($activitytype));
}
else {
$at = get_record('activity_type', 'name', $activitytype, 'plugintype', $plugintype, 'pluginname', $pluginname);
}
}
if (empty($at)) {
throw new Exception("Invalid activity type $activitytype");
}
return $at;
}
/** activity type classes **/
abstract class ActivityType {
......@@ -239,6 +246,15 @@ abstract class ActivityType {
protected $message;
protected $users = array();
protected $url;
protected $id;
public function get_id() {
if (!isset($this->id)) {
$tmp = activity_locate_typerecord($this->get_type());
$this->id = $tmp->id;
}
return $this->id;
}
public function get_type() {
$prefix = 'ActivityType';
......@@ -287,8 +303,7 @@ abstract class ActivityTypeAdmin extends ActivityType {
public function __construct($data) {
parent::__construct($data);
$this->users = activity_get_users($this->get_type(), null, null, true);
log_debug($this->users);
$this->users = activity_get_users($this->get_id(), null, null, true);
}
}
......@@ -378,7 +393,7 @@ class ActivityTypeMaharamessage extends ActivityType {
public function __construct($data) {
parent::__construct($data);
$this->users = activity_get_users('maharamessage', $this->users);
$this->users = activity_get_users($this->get_id(), $this->users);
}
public function get_required_parameters() {
......@@ -396,7 +411,7 @@ class ActivityTypeUsermessage extends ActivityType {
if (empty($this->subject)) {
$this->subject = get_string('newusermessage', 'mahara', display_name($this->userfrom));
}
$this->users = activity_get_users('usermessage', array($this->userto));
$this->users = activity_get_users($this->get_id(), array($this->userto));
if (empty($this->url)) {
$this->url = get_config('wwwroot') . 'user/view.php?id=' . $this->userfrom;
}
......@@ -442,7 +457,7 @@ class ActivityTypeFeedback extends ActivityType {
}
}
if ($userid) {
$this->users = activity_get_users('feedback', array($userid));
$this->users = activity_get_users($this->get_id(), array($userid));
}
}
......@@ -468,6 +483,11 @@ class ActivityTypeWatchlist extends ActivityType {
throw new ViewNotFoundException(get_string('viewnotfound', 'error', $this->view));
}
$this->message = $oldsubject . ' ' . $viewinfo->title;
// mysql compatibility (sigh...)
$casturl = 'CAST(? AS TEXT)';
if (get_config('dbtype') == 'mysql') {
$casturl = 'CAST(? AS CHAR)'; // note, NOT varchar
}
$sql = 'SELECT u.*, p.method, ' . $casturl . ' AS url
FROM {usr_watchlist_view} wv
JOIN {usr} u
......@@ -511,7 +531,7 @@ class ActivityTypeNewview extends ActivityType {
$this->url = get_config('wwwroot') . 'view/view.php?id=' . $this->view;
// add users on friendslist or userlist...
$this->users = activity_get_viewaccess_users($this->view, $this->owner, 'newview');
$this->users = activity_get_viewaccess_users($this->view, $this->owner, $this->get_id());
// ick
foreach ($this->users as &$user) {
$user->message = display_name($viewinfo, $user) . ' ' . $this->message;
......@@ -544,7 +564,7 @@ class ActivityTypeViewaccess extends ActivityType {
$this->subject = get_string('newviewaccesssubject', 'activity');
$this->url = get_config('wwwroot') . 'view/view.php?id=' . $this->view;
$this->users = array_diff_key(
activity_get_viewaccess_users($this->view, $this->owner, 'viewaccess'),
activity_get_viewaccess_users($this->view, $this->owner, $this->get_id()),
$this->oldusers
);
......@@ -559,4 +579,19 @@ class ActivityTypeViewaccess extends ActivityType {
}
}
abstract class ActivityTypePlugin extends ActivityType {
abstract public function get_plugintype();
abstract public function get_pluginname();
public function get_id() {
if (!isset($this->id)) {
$tmp = activity_locate_typerecord($this->get_type(), $this->get_plugintype(), $this->get_pluginname());
$this->id = $tmp->id;
}
return $this->id;
}
}
?>
......@@ -155,24 +155,28 @@
</TABLE>
<TABLE NAME="activity_type">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" />
<FIELD NAME="name" TYPE="char" LENGTH="50" NOTNULL="true" />
<FIELD NAME="admin" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" />
<FIELD NAME="delay" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" />
<FIELD NAME="plugintype" TYPE="char" LENGTH="25" NOTNULL="false" />
<FIELD NAME="pluginname" TYPE="char" LENGTH="255" NOTNULL="false" />
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="name" />
<KEY NAME="primary" TYPE="primary" FIELDS="id" />
<KEY NAME="namepluginuk" TYPE="unique" FIELDS="name, plugintype, pluginname" />
</KEYS>
</TABLE>
<TABLE NAME="activity_queue">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" />
<FIELD NAME="type" TYPE="char" LENGTH="50" NOTNULL="true" />
<FIELD NAME="type" TYPE="int" LENGTH="10" NOTNULL="true" />
<FIELD NAME="data" TYPE="text" NOTNULL="true" />
<FIELD NAME="ctime" TYPE="datetime" />
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" />
<KEY NAME="typefk" TYPE="foreign" FIELDS="type" REFTABLE="activity_type" REFFIELDS="name" />
<KEY NAME="typefk" TYPE="foreign" FIELDS="type" REFTABLE="activity_type" REFFIELDS="id" />
</KEYS>
</TABLE>
<TABLE NAME="artefact">
......@@ -307,13 +311,13 @@
<TABLE NAME="usr_activity_preference">
<FIELDS>
<FIELD NAME="usr" TYPE="int" LENGTH="10" NOTNULL="true" />
<FIELD NAME="activity" TYPE="char" LENGTH="100" NOTNULL="true" />
<FIELD NAME="activity" TYPE="int" LENGTH="10" NOTNULL="true" />
<FIELD NAME="method" TYPE="char" LENGTH="255" NOTNULL="true" />
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="usr,activity" />
<KEY NAME="usrfk" TYPE="foreign" FIELDS="usr" REFTABLE="usr" REFFIELDS="id" />
<KEY NAME="activityfk" TYPE="foreign" FIELDS="activity" REFTABLE="activity_type" REFFIELDS="name" />
<KEY NAME="activityfk" TYPE="foreign" FIELDS="activity" REFTABLE="activity_type" REFFIELDS="id" />
<KEY NAME="methodfk" TYPE="foreign" FIELDS="method" REFTABLE="notification_installed" REFFIELDS="name" />
</KEYS>
</TABLE>
......
......@@ -430,17 +430,89 @@ function xmldb_core_upgrade($oldversion=0) {
XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
$table->addFieldInfo('plugin', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
$table->addFieldInfo('title', XMLDB_TYPE_CHAR, 255, XMLDB_UNSIGNED, XMLDB_NOTNULL);
$table->addFieldInfo('description', XMLDB_TYPE_TEXT, null, XMLDB_UNSIGNED, XMLDB_NOTNULL);
$table->addFieldInfo('description', XMLDB_TYPE_TEXT, null, XMLDB_UNSIGNED, null);
$table->addFieldInfo('group', XMLDB_TYPE_INTEGER, 10, XMLDB_UNSIGNED, XMLDB_NOTNULL);
$table->addFieldInfo('ctime', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
$table->addFieldInfo('creator', XMLDB_TYPE_INTEGER, 10, XMLDB_UNSIGNED, XMLDB_NOTNULL);
$table->addFIeldInfo('deleted', XMLDB_TYPE_INTEGER, 1, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, 0);
$table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
$table->addKeyInfo('pluginfk', XMLDB_KEY_FOREIGN, array('plugin'), 'interaction_installed', array('name'));
$table->addKeyInfo('groupfk', XMLDB_KEY_FOREIGN, array('group'), 'group', array('id'));
$table->addKeyInfo('creatorfk', XMLDB_KEY_FOREIGN, array('creator'), 'usr', array('id'));
create_table($table);
}
if ($oldversion < 2007111900) {
// move the activitytype table around
$fks = array(
'activity_queue' => 'type',
'usr_activity_preference' => 'activity',
'notification_internal_activity' => 'type',
'notification_emaildigest_queue' => 'type',
);
// drop all the keys that fk to us
foreach ($fks as $table => $field) {
$xmldbtable = new XMLDBTable($table);
$xmldbkey = new XMLDBKey($field . 'fk');
$xmldbkey->setAttributes(XMLDB_KEY_FOREIGN, array($field), 'activity_type', array('name'));
drop_key($xmldbtable, $xmldbkey);
}
// drop the primary key
$typetable = new XMLDBTable('activity_type');
$typekey = new XMLDBKey('primary');
$typekey->setAttributes(XMLDB_KEY_PRIMARY, array('name'));
drop_key($typetable, $typekey);
// create the new field
$typefield = new XMLDBField('id');
$typefield->setAttributes(XMLDB_TYPE_INTEGER, 10, XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE);
add_field($typetable, $typefield);
// create the new primary key
$typekey = new XMLDBKey('primary');
$typekey->setAttributes(XMLDB_KEY_PRIMARY, array('id'));
add_key($typetable, $typekey);
foreach ($fks as $table => $field) {
$xmldbtable = new XMLDBTable($table);
$xmldbfield = new XMLDBField($field . 'new');
$xmldbfield->setAttributes(XMLDB_TYPE_INTEGER, 10, XMLDB_UNSIGNED, null);
add_field($xmldbtable, $xmldbfield);
$sql = 'UPDATE {' . $table . '}
SET ' . $field . 'new =
(SELECT id FROM {activity_type} t where ' . $field . ' = t.name)';
execute_sql($sql);
$xmldbfield->setAttributes(XMLDB_TYPE_INTEGER, 10, XMLDB_UNSIGNED, XMLDB_NOTNULL);
change_field_notnull($xmldbtable, $xmldbfield);
drop_field($xmldbtable, new XMLDBField($field));
rename_field($xmldbtable, $xmldbfield, $field);
$xmldbkey = new XMLDBKey($field . 'fk');
$xmldbkey->setAttributes(XMLDB_KEY_FOREIGN, array($field), 'activity_type', array('id'));
add_key($xmldbtable, $xmldbkey);
}
// special case...
$table = new XMLDBTable('usr_activity_preference');
$key = new XMLDBKey('primary');
$key->setAttributes(XMLDB_KEY_PRIMARY, array('usr', 'activity'));
add_key($table, $key);
// and now add the new fields to the activity_type table
$pluginfield = new XMLDBField('plugintype');
$pluginfield->setAttributes(XMLDB_TYPE_CHAR, 25);
add_field($typetable, $pluginfield);
$pluginfield = new XMLDBField('pluginname');
$pluginfield->setAttributes(XMLDB_TYPE_CHAR, 255);
add_field($typetable, $pluginfield);
// and the unique key
$key = new XMLDBKey('namepluginuk');
$key->setAttributes(XMLDB_KEY_UNIQUE, array('name', 'plugintype', 'pluginname'));
add_key($typetable, $key);
}
return $status;
}
......
......@@ -1007,6 +1007,15 @@ class Plugin {
public static function has_config() {
return false;
}
/**
* Does this plugin offer any activity types
* If it does, you must subclass ActivityTypePlugin like
* ActivityType{$PluginType}{$Pluginname}
*/
public static function get_activity_types() {
return array();
}
}
/**
......
......@@ -410,6 +410,21 @@ function upgrade_plugin($upgrade) {
}
}
if ($activities = call_static_method($pcname, 'get_activity_types')) {
foreach ($activities as $activity) {
$classname = 'ActivityType' . ucfirst($plugintype) . ucfirst($pluginname) . ucfirst($activity->name);
if (!class_exists($classname)) {
throw new InstallationException(get_string('classmissing', 'error', $classname, $pluginname, $plugintype));
}
$activity->plugintype = $plugintype;
$activity->pluginname = $pluginname;
$where = $activity;
unset($where->admin);
unset($where->delay);
ensure_record_exists('activity_type', $where, $activity);