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) {
......
This diff is collapsed.
......@@ -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
),
);
public static $mainfacetterm = 'Event';
public static $secfacetterm = 'Log';
......@@ -73,18 +114,50 @@ class ElasticsearchType_event_log extends ElasticsearchType {
'resourcetype' => NULL,
'parentresourceid' => NULL,
'parentresourcetype' => NULL,
'ownerid' => NULL,
'ownertype' => NULL,
'yearweek' => NULL,
'createdbyuser' => NULL,
'firstname' => NULL,
'lastname' => NULL,
'username' => NULL,
'displayname' => NULL,
);
parent::__construct ( $data );
}
public static function getRecordById($type, $id, $map = null) {
$record = parent::getRecordById ( $type, $id );
if (! $record) {
return false;
}
$record->secfacetterm = self::$secfacetterm;
$record->yearweek = date('Y_W', strtotime($record->ctime));
$user = get_record('usr', 'id', $record->usr);
$record->username = $user->username;
$record->firstname = $user->firstname;
$record->lastname = $user->lastname;
$record->displayname = $user->preferredname;
$record->createdbyuser = FALSE;
if ($record->usr === $record->realusr) {
// A non-masquerading event
if (in_array($record->event, array('createview', 'createcollection', 'creategroup', 'saveartefact'))) {
$data = json_decode($record->data);
if ($record->event == 'createview' && isset($data->viewtype) && $data->viewtype == 'portfolio') {
$record->createdbyuser = TRUE;
}
else if ($record->event == 'saveartefact' && ($data->ctime == $data->mtime)) {
$record->createdbyuser = TRUE;
}
else {
$record->createdbyuser = TRUE;
}
}
}
return $record;
}
public static function getRecordDataById($type, $id) {
global $USER;
......@@ -124,9 +197,12 @@ class ElasticsearchType_event_log extends ElasticsearchType {
$matching = array(
'match_all' => new \stdClass()
);
// Use provided filters and range otherwise default to all event_log rows
// Use provided query, filters and range otherwise default to all event_log rows
$matching = (!empty($options['query']) && is_array($options['query'])) ? $options['query'] : $matching;
$filters = (!empty($options['filters']) && is_array($options['filters'])) ? $options['filters'] : array('term' => array('secfacetterm' => 'Log'));
$range = (!empty($options['range']) && is_array($options['range'])) ? $options['range'] : array('range' => array('id' => array('gte' => 1)));
$sort = (!empty($options['sort']) && is_array($options['sort'])) ? $options['sort'] : array('ctime' => 'desc');
$aggs = (!empty($options['aggs']) && is_array($options['aggs'])) ? $options['aggs'] : array('EventType' => array('terms' => array('field' => 'event')));
$client = PluginSearchElasticsearch::make_client();
$params = array(
......@@ -146,18 +222,18 @@ class ElasticsearchType_event_log extends ElasticsearchType {
),
),
),
'aggs' => array(
'EventType' => array(
'terms' => array(
'field' => 'event',
),
),
'sort' => array(
$sort,
),
'aggs' => $aggs,
),
);
$results = $client->search($params);
$result['totalresults'] = $results['hits']['total'];
if ($result['totalresults'] > 0) {
$result['aggregations'] = $results['aggregations'];
}
if ($limit < 1) {
// We are just wanting the count of results so return now
return $result;
......@@ -225,4 +301,35 @@ class ElasticsearchType_event_log extends ElasticsearchType {
return $result;
}
/**
* Combine search aggregation results into aggregated array structure.
* To return the count of particular buckets and their sub buckets
*
* @param array $aggmap The array to hold the mappings
* @param array $data The array containing the elasticaseach result bucket information
* @param bool $all To also return a total count key called 'all'
* @param array $buckets Names of buckets in their nested order
* @param string $key The name of the key to display in $aggmap
*
* @return array $aggmap
*/
public static function process_aggregations(&$aggmap, $data, $all = false, $buckets=array(), $key='') {
$countall = 0;
$bucket = array_shift($buckets);
if (!empty($data[$bucket]['buckets'])) {
foreach ($data[$bucket]['buckets'] as $value) {
$aggmap[$key . $value['key']] = $value['doc_count'];
if ($all) {
$countall += $value['doc_count'];
}
if (!empty($buckets)) {
self::process_aggregations($aggmap, $value, $all, $buckets, $key . $value['key'] . '|');
}
}
}
if ($all) {
$tmp['all'] = $countall;
}
}
}
......@@ -665,12 +665,16 @@ function editurl_submit(Pieform $form, $values) {
foreach ($viewids as $id) {
$access->view = $id;
$whereobject->view = $id;
update_record('view_access', $access, $whereobject);
$vaid = update_record('view_access', $access, $whereobject, 'id', true);
handle_event('updateviewaccess', array(
'id' => $vaid,
'eventfor' => 'token',
'parentid' => $id,
'parenttype' => 'view',
'rules' => $access)
);
}
handle_event('updateviewaccess', array('id' => $collection ? $collection : $viewid,
'eventfor' => $collection ? 'collection' : 'view',
'viewids' => $viewids,
'rules' => array($access)));
$message = get_string('secreturlupdated', 'view');
$form->reply(PIEFORM_OK, $message);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment