Commit a3d904e1 authored by Robert Lyon's avatar Robert Lyon

Bug 1692385: Adjusting the handle event for 'updateviewaccess'

We want to record things like so:

resourceid = view_access.id
resourcetype = what type the view_access row is for, eg 'token',
'user', 'loggedin' etc
parentresourceid = the id if the view the access is for
parentresourcetype = 'view';
ownerid = the id of the owning resource, eg usr.id / group.id / institution.name
ownertype = what owns the resource, eg user / group / institution

Also this patch adjusts how we index things into elasticsearch

behatnotneeded

Change-Id: I079a42ded2fefaab64a6e49fc26e8aad303c9e8a
Signed-off-by: Robert Lyon's avatarRobert Lyon <robertl@catalyst.net.nz>
parent d73a4a9e
......@@ -1699,6 +1699,14 @@ class LiveUser extends User {
// Record the successful login in the usr_login_data table
insert_record('usr_login_data', (object) array('usr' => $user->id, 'ctime' => db_format_timestamp($time)));
if (get_config('eventloglevel') == 'all') {
// if we are doing fill event logging also record it there as the records
// in usr_login_data is deleted when usr is deleted but event_log data stays
insert_record('event_log', (object) array('usr' => $user->id,
'realusr' => $user->id,
'event' => 'login',
'ctime' => db_format_timestamp($time)));
}
// If user has chosen a language while logged out, save it as their lang pref.
$sessionlang = $this->SESSION->get('lang');
......
......@@ -110,11 +110,14 @@ class Collection {
$collection->commit();
$views = $collection->get('views');
$viewids = array();
foreach ($views as $view) {
$viewids[] = $view->view;
if (!empty($views)) {
foreach ($views['views'] as $view) {
$viewids[] = $view->view;
}
}
$eventdata = array('id' => $collection->get('id'),
'name' => $collection->get('name'),
'eventfor' => 'collection',
'viewids' => $viewids);
handle_event($state, $eventdata);
return $collection; // return newly created Collections id
......@@ -159,6 +162,7 @@ class Collection {
}
$data = array('id' => $this->id,
'name' => $this->name,
'eventfor' => 'collection',
'viewids' => $viewids);
handle_event('deletecollection', $data);
db_commit();
......@@ -1351,12 +1355,15 @@ class Collection {
$todb->visible = $access->visible;
$todb->token = $access->token;
$todb->ctime = $access->ctime;
insert_record('view_access', $todb);
$vaid = insert_record('view_access', $todb, 'id', true);
handle_event('updateviewaccess', array(
'id' => $vaid,
'eventfor' => 'token',
'parentid' => current($viewids),
'parenttype' => 'view',
'rules' => $todb)
);
}
handle_event('updateviewaccess', array('id' => $this->id,
'eventfor' => 'collection',
'viewids' => $viewids,
'rules' => array($todb)));
return $access;
}
......
......@@ -320,6 +320,8 @@
<FIELD NAME="resourceid" TYPE="int" LENGTH="10" NOTNULL="false" />
<FIELD NAME="parentresourcetype" TYPE="char" LENGTH="255" NOTNULL="false" />
<FIELD NAME="parentresourceid" TYPE="int" LENGTH="10" NOTNULL="false" />
<FIELD NAME="ownertype" TYPE="char" LENGTH="255" NOTNULL="false" />
<FIELD NAME="ownerid" TYPE="int" LENGTH="10" NOTNULL="false" />
</FIELDS>
<KEYS>
<KEY NAME="usrfk" TYPE="foreign" FIELDS="usr" REFTABLE="usr" REFFIELDS="id" />
......
......@@ -5184,6 +5184,14 @@ function xmldb_core_upgrade($oldversion=0) {
$field->setAttributes(XMLDB_TYPE_CHAR, 255);
add_field($table, $field);
$field = new XMLDBField('ownerid');
$field->setAttributes(XMLDB_TYPE_INTEGER, 10);
add_field($table, $field);
$field = new XMLDBField('ownertype');
$field->setAttributes(XMLDB_TYPE_CHAR, 255);
add_field($table, $field);
log_debug('Adjust existing "event_log" data to fit new table structure');
// As there can be very many rows we need to do the adjusting in chuncks
$count = 0;
......@@ -5235,6 +5243,9 @@ function xmldb_core_upgrade($oldversion=0) {
$result->resourcetype = 'friend';
break;
}
list ($ownerid, $ownertype) = event_find_owner_type($result);
$result->ownerid = $ownerid;
$result->ownertype = $ownertype;
update_record('event_log', $result, $where);
}
$count += $chunk;
......@@ -5255,7 +5266,8 @@ function xmldb_core_upgrade($oldversion=0) {
'deletecollection',
'addsubmission',
'releasesubmission',
'updateviewaccess');
'updateviewaccess',
'sharedcommenttogroup');
foreach ($newevents as $newevent) {
$event = (object)array(
'name' => $newevent,
......
......@@ -544,11 +544,14 @@ function group_create($data) {
'accesstype' => $data['public'] ? 'public' : 'loggedin',
'ctime' => db_format_timestamp(time()),
);
insert_record('view_access', $newaccess);
handle_event('updateviewaccess', array('id' => $id,
'eventfor' => 'group',
'viewids' => $homepage->get('id'),
'rules' => array($newaccess)));
$vaid = insert_record('view_access', $newaccess, 'id', true);
handle_event('updateviewaccess', array(
'id' => $vaid,
'eventfor' => $data['public'] ? 'public' : 'loggedin',
'parentid' => $homepage->get('id'),
'parenttype' => 'view',
'rules' => $newaccess)
);
handle_event('creategroup', $data);
db_commit();
......@@ -737,7 +740,14 @@ function group_update($new, $create=false) {
'accesstype' => 'loggedin',
'ctime' => db_format_timestamp(time()),
);
insert_record('view_access', $newaccess);
$vaid = insert_record('view_access', $newaccess, 'id', true);
handle_event('updateviewaccess', array(
'id' => $vaid,
'eventfor' => 'loggedin',
'parentid' => $homepageid,
'parenttype' => 'view',
'rules' => $newaccess)
);
}
else if (!$old->public && $new->public) {
delete_records('view_access', 'view', $homepageid, 'accesstype', 'loggedin');
......@@ -746,12 +756,15 @@ function group_update($new, $create=false) {
'accesstype' => 'public',
'ctime' => db_format_timestamp(time()),
);
insert_record('view_access', $newaccess);
$vaid = insert_record('view_access', $newaccess, 'id', true);
handle_event('updateviewaccess', array(
'id' => $vaid,
'eventfor' => 'public',
'parentid' => $homepageid,
'parenttype' => 'view',
'rules' => $newaccess)
);
}
handle_event('updateviewaccess', array('id' => $new->id,
'eventfor' => 'group',
'viewids' => $homepageid,
'rules' => array($newaccess)));
}
// When the create/edit permissions change, update permissions on journal and posts
......
......@@ -1896,6 +1896,17 @@ function handle_event($event, $data, $ignorefields = array()) {
unset($logdata->id);
$reftype = $logdata->artefacttype;
unset($logdata->artefacttype);
$parentrefid = $refid;
$parentreftype = 'artefact';
if ($reftype == 'comment') {
if (isset($logdata->onview)) {
$parentrefid = $logdata->onview;
$parentreftype = 'view';
}
if (isset($logdata->onartefact)) {
$parentrefid = $logdata->onartefact;
}
}
}
else if ($logdata instanceof BlockInstance) {
$logdata->set('dirty', false);
......@@ -1929,6 +1940,12 @@ function handle_event($event, $data, $ignorefields = array()) {
$refid = $logdata->id;
$reftype = $logdata->eventfor;
unset($logdata->eventfor);
if (isset($logdata->parentid) && isset($logdata->parenttype)) {
$parentrefid = $logdata->parentid;
$parentreftype = $logdata->parenttype;
unset($logdata->parentid);
unset($logdata->parenttype);
}
}
$data = (array)$data;
}
......@@ -1936,6 +1953,12 @@ function handle_event($event, $data, $ignorefields = array()) {
$refid = !empty($logdata['id']) ? $logdata['id'] : null;
$reftype = !empty($logdata['eventfor']) ? $logdata['eventfor'] : null;
unset($logdata['eventfor']);
if (isset($logdata['parentid']) && isset($logdata['parenttype'])) {
$parentrefid = $logdata['parentid'];
$parentreftype = $logdata['parenttype'];
unset($logdata['parentid']);
unset($logdata['parenttype']);
}
}
// Then remove any unwanted items
......@@ -1963,7 +1986,37 @@ function handle_event($event, $data, $ignorefields = array()) {
'parentresourceid' => $parentrefid,
'parentresourcetype' => $parentreftype,
);
// find out who 'owns' the event
list ($ownerid, $ownertype) = event_find_owner_type($logentry);
$logentry->ownerid = $ownerid;
$logentry->ownertype = $ownertype;
insert_record('event_log', $logentry);
// If we are adding a comment to a page that is shared to a group
// we need to add a 'sharedcommenttogroup' event
if ($reftype == 'comment') {
if (!empty($logdata['onartefact'])) {
$commenttype = 'artefact';
$commenttypeid = $logdata['onartefact'];
$wheresql = " IN (SELECT view FROM {view_artefact} WHERE " . $commenttype . " = ?) ";
}
else {
$commenttype = 'view';
$commenttypeid = $logdata['onview'];
$wheresql = " = ? ";
}
if ($groupids = get_records_sql_array("SELECT \"group\" FROM {view_access}
WHERE view " . $wheresql . "
AND \"group\" IS NOT NULL", array($commenttypeid))) {
foreach ($groupids as $groupid) {
$logentry->event = 'sharedcommenttogroup';
$logentry->data = null;
$logentry->ownerid = $groupid->group;
$logentry->ownertype = 'group';
insert_record('event_log', $logentry);
}
}
}
// @TODO If we are sharing a page to a group that contains existing comments do we count these are sharedcomments?
}
if (empty($coreevents_cache)) {
......@@ -2017,6 +2070,46 @@ function handle_event($event, $data, $ignorefields = array()) {
}
}
/**
* Find out who / what owns the event
*
* @param obj $event event_log database record
*
* @return array An array of ($id, $type)
*/
function event_find_owner_type($event) {
$ownerid = null;
$ownertype = null;
$record = null;
$validtypes = array('view', 'collection', 'artefact');
if (!empty($event->parentresourcetype) && in_array($event->parentresourcetype, $validtypes)) {
$record = get_record($event->parentresourcetype, 'id', $event->parentresourceid);
}
else if (!empty($event->resourcetype) && in_array($event->resourcetype, $validtypes)) {
$record = get_record($event->resourcetype, 'id', $event->resourceid);
}
if ($record) {
if (!empty($record->institution)) {
$ownerid = get_field('institution', 'id', 'name', $record->institution);
$ownertype = 'institution';
}
if (!empty($record->group)) {
$ownerid = $record->group;
$ownertype = 'group';
}
if (!empty($record->owner)) {
$ownerid = $record->owner;
$ownertype = 'user';
}
}
else if (!empty($event->resourcetype) && in_array($event->resourcetype, array('group', 'user', 'institution'))) {
$ownerid = $event->resourceid;
$ownertype = $event->resourcetype;
}
return array($ownerid, $ownertype);
}
/**
* function to convert an array of objects to
* an array containing one field per place
......
This diff is collapsed.
......@@ -894,7 +894,8 @@ function core_install_firstcoredata_defaults() {
'deletecollection',
'addsubmission',
'releasesubmission',
'updateviewaccess'
'updateviewaccess',
'sharedcommenttogroup'
);
foreach ($eventtypes as $et) {
......
......@@ -514,11 +514,14 @@ class View {
$obj->ctime = db_format_timestamp(time());
$obj->usr = $template->get('owner');
$obj->group = $template->get('group');
insert_record('view_access', $obj);
handle_event('updateviewaccess', array('id' => $view->get('id'),
'eventfor' => 'view',
'viewids' => $view->get('id'),
'rules' => array($obj)));
$vaid = insert_record('view_access', $obj, 'id', true);
handle_event('updateviewaccess', array(
'id' => $vaid,
'eventfor' => (!empty($template->get('group')) ? 'group' : 'user'),
'parentid' => $view->get('id'),
'parenttype' => 'view',
'rules' => $obj)
);
}
db_commit();
......@@ -628,11 +631,14 @@ class View {
'group' => $viewdata['group'],
'ctime' => db_format_timestamp(time()),
);
insert_record('view_access', $newaccess);
handle_event('updateviewaccess', array('id' => $viewdata['group'],
'eventfor' => 'group',
'viewids' => $view->get('id'),
'rules' => array($newaccess)));
$vaid = insert_record('view_access', $newaccess, 'id', true);
handle_event('updateviewaccess', array(
'id' => $vaid,
'eventfor' => 'group',
'parentid' => $view->get('id'),
'parenttype' => 'view',
'rules' => $newaccess)
);
// Notify group members
$accessdata = new StdClass;
$accessdata->view = $view->get('id');
......@@ -767,11 +773,11 @@ class View {
throw new SystemException(get_string('onlonlyyoneprofileviewallowed', 'error'));
}
$this->id = insert_record('view', $fordb, 'id', true);
handle_event('createview', $this->id);
handle_event('createview', array('id' => $this->id, 'eventfor' => 'view', 'viewtype' => $this->type));
}
else {
update_record('view', $fordb, 'id');
handle_event('saveview', $this->id);
handle_event('saveview', array('id' => $this->id, 'eventfor' => 'view', 'viewtype' => $this->type));
}
if (isset($this->tags)) {
......@@ -877,7 +883,7 @@ class View {
delete_records('view_autocreate_grouptype', 'view', $this->id);
delete_records('view_tag','view',$this->id);
delete_records('view_visit','view',$this->id);
$eventdata = array('id' => $this->id);
$eventdata = array('id' => $this->id, 'eventfor' => 'view');
if ($collection = $this->get_collection()) {
$eventdata['collection'] = $collection->get('id');
$collection->remove_view($this->id);
......@@ -1308,7 +1314,6 @@ class View {
* @todo: merge overlapping date ranges.
*/
$time = time();
$accessrecords = array();
foreach ($accessdata as $item) {
if (!empty($item['stopdate']) && $item['stopdate'] < $time) {
......@@ -1379,18 +1384,18 @@ class View {
if (array_search($accessrecord, $accessdata_added) === false) {
$accessrecord->view = $this->get('id');
insert_record('view_access', $accessrecord);
$accessrecords[] = $accessrecord;
$vaid = insert_record('view_access', $accessrecord, 'id', true);
handle_event('updateviewaccess', array(
'id' => $vaid,
'eventfor' => $item['type'],
'parentid' => $accessrecord->view,
'parenttype' => 'view',
'rules' => $accessrecord)
);
unset($accessrecord->view);
$accessdata_added[] = $accessrecord;
}
}
if (!empty($accessrecords)) {
handle_event('updateviewaccess', array('id' => $this->get('id'),
'eventfor' => 'view',
'viewids' => !empty($viewids) ? $viewids : $this->get('id'),
'rules' => $accessrecords));
}
}
$data = new StdClass;
......@@ -1485,24 +1490,42 @@ class View {
);
if ($firstviewaccess) {
$accessrecords = array();
foreach ($toupdate as $id) {
foreach ($firstviewaccess as &$a) {
$a->view = $id;
$a->ctime = db_format_timestamp(time());
unset($a->id);
insert_record('view_access', $a);
$accessrecords[] = $a;
$vaid = insert_record('view_access', $a, 'id', true);
handle_event('updateviewaccess', array(
'id' => $vaid,
'eventfor' => self::eventfor($a),
'parentid' => $id,
'parenttype' => 'view',
'rules' => $a)
);
}
}
handle_event('updateviewaccess', array('id' => $this->id,
'eventfor' => 'view',
'viewids' => $toupdate,
'rules' => $accessrecords));
}
db_commit();
}
public static function eventfor($access) {
// Work out what event this access is for
if (!empty($access->token)) {
return 'token';
}
if (!empty($access->institution)) {
return 'institution';
}
if (!empty($access->group)) {
return 'group';
}
if (!empty($access->usr)) {
return 'user';
}
return $access->accesstype;
}
public function add_access($access) {
if (!$this->id) {
return false;
......@@ -1516,11 +1539,14 @@ class View {
if (!isset($access->ctime)) {
$access->ctime = db_format_timestamp(time());
}
ensure_record_exists('view_access', $whereobject, $access);
handle_event('updateviewaccess', array('id' => $this->id,
'eventfor' => 'view',
'viewids' => $this->id,
'rules' => array($access)));
$vaid = ensure_record_exists('view_access', $whereobject, $access, 'id', true);
handle_event('updateviewaccess', array(
'id' => $vaid,
'eventfor' => self::eventfor($access),
'parentid' => $this->id,
'parenttype' => 'view',
'rules' => $access)
);
}
public function add_owner_institution_access($instnames=array()) {
......@@ -1548,12 +1574,14 @@ class View {
$vaccess->approvecomments = 1;
$vaccess->ctime = db_format_timestamp(time());
insert_record('view_access', $vaccess);
handle_event('updateviewaccess', array('id' => $this->id,
'eventfor' => 'view',
'viewids' => $this->id,
'institution' => $i,
'rules' => array($vaccess)));
$vaid = insert_record('view_access', $vaccess, 'id', true);
handle_event('updateviewaccess', array(
'id' => $vaid,
'eventfor' => 'institution',
'parentid' => $this->id,
'parenttype' => 'view',
'rules' => $vaccess)
);
}
}
db_commit();
......@@ -5942,11 +5970,14 @@ class View {
while (record_exists('view_access', 'token', $data->token)) {
$data->token = get_random_key(20);
}
insert_record('view_access', $data);
handle_event('updateviewaccess', array('id' => $viewid,
'eventfor' => 'view',
'viewids' => $viewid,
'rules' => array($data)));
$vaid = insert_record('view_access', $data, 'id', true);
handle_event('updateviewaccess', array(
'id' => $vaid,
'eventfor' => 'token',
'parentid' => $viewid,
'parenttype' => 'view',
'rules' => $data)
);
return $data;
}
......@@ -6635,7 +6666,6 @@ class View {
execute_sql($sql, $params);
if ($group) {
$accessrecords = array();
foreach ($group->roles as $role) {
foreach ($viewids as $viewid) {
$accessrecord = (object) array(
......@@ -6647,14 +6677,16 @@ class View {
'approvecomments' => 0,
'ctime' => db_format_timestamp(time()),
);
ensure_record_exists('view_access', $accessrecord, $accessrecord);
$accessrecords[] = $accessrecord;
$vaid = ensure_record_exists('view_access', $accessrecord, $accessrecord);
handle_event('updateviewaccess', array(
'id' => $vaid,
'eventfor' => 'group',
'parentid' => $viewid,
'parenttype' => 'view',
'rules' => $accessrecord)
);
}
}
handle_event('updateviewaccess', array('id' => $groupid,
'eventfor' => 'group',
'viewids' => $viewids,
'rules' => $accessrecords));
}
ArtefactType::update_locked($userid);
......
......@@ -38,7 +38,8 @@ class ElasticsearchType_event_log extends ElasticsearchType {
'include_in_all' => FALSE
),
'resourcetype' => array (
'type' => 'text',
'type' => 'keyword',
'index' => 'not_analyzed',
'include_in_all' => TRUE
),
'parentresourceid' => array (
......@@ -46,14 +47,54 @@ class ElasticsearchType_event_log extends ElasticsearchType {
'include_in_all' => FALSE
),
'parentresourcetype' => array (
'type' => 'text',
'type' => 'keyword',
'index' => 'not_analyzed',
'include_in_all' => TRUE
),
'ownerid' => array (
'type' => 'integer',
'include_in_all' => FALSE
),
'ownertype' => array (
'type' => 'keyword',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
'ctime' => array (
'type' => 'date',
'format' => 'YYYY-MM-dd HH:mm:ss',
'include_in_all' => FALSE
)
),
'yearweek' => array (
'type' => 'keyword',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
'createdbyuser' => array (
'type' => 'boolean',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
'firstname' => array (
'type' => 'keyword',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
'lastname' => array (
'type' => 'keyword',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
'username' => array (
'type' => 'keyword',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
'displayname' => array (
'type' => 'keyword',
'index' => 'not_analyzed',
'include_in_all' => FALSE
),
);