Commit 673a2cc4 authored by Robert Lyon's avatar Robert Lyon Committed by Gerrit Code Review
Browse files

Merge changes from topic 'Smart evidence'

* changes:
  Bug 1409546: Styled smart evidence
  Bug 1409546: Fixes for issues found in the earlier patches
  Bug 1409546: Adding a 'framework_choices' table to db
  Bug 1409546: Adding an 'active' column to framework db
  Bug 1409546: More adjustments
  Bug 1409546: Altering matrix upload to a file upload field
  Bug 1409546: Restricting annotation assessment options
  Bug 1409546: Annotation feedback on form
  Bug 1409546: Alter annotation blocktype
  Bug 1409546: Add annotation to view via click on matrix point
  Bug 1409546: Allowing plugin page to show plugin name
  Bug 1409546: Adjusting collection navigation to include framework option
  Bug 1409546: Adding carousel type ability to matrix table
  Bug 1409546: Add framework option to add/edit collection form
  Bug 1409546: Adding smart evidence switch to institution config form
  Bug 1409546: Plugin config option to install a .maxtrix file
  Bug 1409546: Adding in the framework module
  Bug 1409546: Adding framework field to collection table
parents 861f7fd4 dcc4d655
......@@ -43,10 +43,12 @@ foreach (array_keys($plugins) as $plugin) {
continue;
}
$classname = generate_class_name($plugin, $key);
$plugins[$plugin]['installed'][$key] = array(
'active' => $i->active,
'disableable' => call_static_method(generate_class_name($plugin, $key), 'can_be_disabled'),
'deprecated' => method_exists(generate_class_name($plugin, $key), 'is_deprecated') ? call_static_method(generate_class_name($plugin, $key), 'is_deprecated') : 0,
'disableable' => call_static_method($classname, 'can_be_disabled'),
'deprecated' => call_static_method($classname, 'is_deprecated'),
'name' => call_static_method($classname, 'get_plugin_display_name'),
);
if ($plugins[$plugin]['installed'][$key]['disableable'] || !$i->active) {
$plugins[$plugin]['installed'][$key]['activateform'] = activate_plugin_form($plugin, $i);
......@@ -100,6 +102,8 @@ foreach (array_keys($plugins) as $plugin) {
validate_plugin($plugin, $dir);
$classname = generate_class_name($plugin, $dir);
$classname::sanity_check();
$name = call_static_method($classname, 'get_plugin_display_name');
$plugins[$plugin]['notinstalled'][$dir]['name'] = $name;
}
catch (InstallationException $e) {
$plugins[$plugin]['notinstalled'][$dir]['notinstallable'] = $e->GetMessage();
......
......@@ -207,6 +207,7 @@ if ($institution || $add) {
$data = get_record('institution', 'name', $institution);
$data->commentsortorder = get_config_institution($institution, 'commentsortorder');
$data->commentthreaded = get_config_institution($institution, 'commentthreaded');
$data->allowinstitutionsmartevidence = get_config_institution($institution, 'allowinstitutionsmartevidence');
$lockedprofilefields = (array) get_column('institution_locked_profile_field', 'profilefield', 'name', $institution);
// TODO: Find a better way to work around Smarty's minimal looping logic
......@@ -240,6 +241,7 @@ if ($institution || $add) {
$data->defaultmembershipperiod = null;
$data->showonlineusers = 2;
$data->allowinstitutionpublicviews = get_config('allowpublicviews') ? 1 : 0;
$data->allowinstitutionsmartevidence = 0;
$data->licensemandatory = 0;
$data->licensedefault = '';
$data->dropdownmenu = get_config('dropdownmenu') ? 1 : 0;
......@@ -522,7 +524,14 @@ if ($institution || $add) {
);
}
}
$elements['allowinstitutionsmartevidence'] = array(
'type' => 'switchbox',
'title' => get_string('allowinstitutionsmartevidence', 'admin'),
'description' => get_string('allowinstitutionsmartevidencedescription','admin'),
'defaultvalue' => is_plugin_active('framework', 'module') && $data->allowinstitutionsmartevidence,
'disabled' => is_plugin_active('framework', 'module') == false,
'help' => true,
);
$elements['lockedfields'] = array(
'type' => 'fieldset',
'class' => 'last with-formgroup',
......@@ -696,6 +705,9 @@ function institution_validate(Pieform $form, $values) {
if (!empty($values['lang']) && $values['lang'] != 'sitedefault' && !array_key_exists($values['lang'], get_languages())) {
$form->set_error('lang', get_string('institutionlanginvalid', 'admin'));
}
if (!is_plugin_active('framework', 'module') && (!empty($values['allowinstitutionsmartevidence']))) {
$form->set_error('allowinstitutionsmartevidence', get_string('institutionsmartevidencenotallowed', 'admin'));
}
// Validate plugins settings.
plugin_institution_prefs_validate($form, $values);
......@@ -832,6 +844,7 @@ function institution_submit(Pieform $form, $values) {
}
$newinstitution->allowinstitutionpublicviews = (isset($values['allowinstitutionpublicviews']) && $values['allowinstitutionpublicviews']) ? 1 : 0;
$newinstitution->allowinstitutionsmartevidence = (isset($values['allowinstitutionsmartevidence']) && $values['allowinstitutionsmartevidence']) ? 1 : 0;
// TODO: Move handling of authentication instances within the Institution class as well?
if (!empty($values['authplugin'])) {
......
......@@ -36,10 +36,6 @@ class PluginBlocktypeAnnotation extends MaharaCoreBlocktype {
return false; // true; // need to do more work on aretfact/artefact.php before this can be switched on.
}
public static function override_instance_title(BlockInstance $instance) {
return get_string('Annotation', 'artefact.annotation');
}
public static function allowed_in_view(View $view) {
// Annotations don't make sense in groups?
return $view->get('group') == null;
......@@ -239,10 +235,58 @@ class PluginBlocktypeAnnotation extends MaharaCoreBlocktype {
// The annotation is displayed as html, need to populate its value.
$elements['text']['value'] = $text;
}
$collection = $view->get('collection');
if (is_object($collection) && $collection->has_framework()) {
safe_require('module', 'framework');
$framework = new Framework($collection->get('framework'));
$standards = $framework->standards();
$evidence = $framework->get_evidence($collection->get('id'), $instance->get('id'));
$selectoptions = array();
$selectdesciptions = array();
foreach ($standards['standards'] as $standard) {
if (isset($standard->options)) {
$selectoptions[$standard->id] = array(
'label' => $standard->name,
'options' => array(),
);
foreach ($standard->options as $option) {
$selectoptions[$standard->id]['options'][$option->id] = $option->name;
$selectdescriptions[$option->id] = $option->description;
}
}
}
$elements['smartevidence'] = array(
'type' => 'select',
'title' => get_string('standard', 'module.framework'),
'optgroups' => $selectoptions,
'isSelect2' => true,
'width' => '280px',
'class' => 'last', // to remove base border
'defaultvalue' => (($evidence) ? $evidence->element : null),
);
array_walk($selectdescriptions, function (&$a, $b) {
$a = '<div class="hidden" id="option_' . $b . '">' . $a . '</div>';
});
$elements['smartevidencedesc'] = array(
'type' => 'html',
'class' => 'htmldescription',
'value' => implode("\n", $selectdescriptions),
'description' => get_string('standarddesc', 'module.framework'), // have desc for 'smartevidence' here so html falls between them
);
if (isset($instance->option) && !empty($instance->option)) {
// Need to add a readonly SmartEvidence field
$elements['smartevidence']['defaultvalue'] = $instance->option;
}
}
return $elements;
}
public static function delete_instance(BlockInstance $instance) {
// If annotation is evidence for SmartEvidence framework we need to delete that as well
if (is_plugin_active('framework', 'module')) {
delete_records('framework_evidence', 'annotation', $instance->get('id'));
}
$configdata = $instance->get('configdata');
if (!empty($configdata)) {
$artefactid = $configdata['artefactid'];
......@@ -255,6 +299,29 @@ class PluginBlocktypeAnnotation extends MaharaCoreBlocktype {
}
}
public static function instance_config_validate(Pieform $form, $values) {
if (!empty($values['smartevidence'])) {
// Check that the new smartevidence standard we are changing to is not alreay covered by another annotation block
$block = $form->get_element('blockconfig');
$view = $form->get_element('id');
require_once('view.php');
$view = new View($view['value']);
$collection = $view->get('collection');
if (is_object($collection) && $collection->get('framework')) {
$annotationid = get_field('framework_evidence', 'annotation',
'view', $view->get('id'),
'framework', $collection->get('framework'),
'element', $values['smartevidence']);
if ($annotationid && $annotationid != $block['value']) {
$result['message'] = get_string('annotationclash', 'module.framework');
$form->set_error('smartevidence', $result['message']);
$form->reply(PIEFORM_ERR, $result);
}
}
}
}
public static function instance_config_save($values, $instance) {
require_once('embeddedimage.php');
......@@ -270,7 +337,7 @@ class PluginBlocktypeAnnotation extends MaharaCoreBlocktype {
// The title will always be Annotation.
$title = get_string('Annotation', 'artefact.annotation');
$data['title'] = $title;
$values['title'] = $title;
$values['title'] = !empty($values['title']) ? $values['title'] : $title;
if (empty($configdata['artefactid'])) {
// This is a new annotation.
$artefact = new ArtefactTypeAnnotation(0, $data);
......@@ -300,10 +367,17 @@ class PluginBlocktypeAnnotation extends MaharaCoreBlocktype {
$values['artefactid'] = $artefact->get('id');
$instance->save_artefact_instance($artefact);
if (is_plugin_active('framework', 'module') && !empty($values['smartevidence'])) {
safe_require('module', 'framework');
$title = get_field('framework_standard_element', 'shortname', 'id', $values['smartevidence']);
$values['title'] = get_string('Annotation', 'artefact.annotation') . ': ' . $title;
$result = Framework::save_evidence_in_block($instance->get('id'), $values['smartevidence']);
}
unset($values['text']);
unset($values['allowfeedback']);
unset($values['annotationreadonlymsg']);
unset($values['smartevidence']);
unset($values['smartevidencedesc']);
// Pass back a list of any other blocks that need to be rendered
// due to this change.
$values['_redrawblocks'] = array_unique(get_column(
......@@ -319,6 +393,17 @@ class PluginBlocktypeAnnotation extends MaharaCoreBlocktype {
return 'full';
}
public static function has_feedback_allowed($id) {
return (bool) get_field_sql("
SELECT a.allowcomments FROM {artefact} a
JOIN {view_artefact} va ON va.artefact = a.id
JOIN {view} v ON v.id = va.view
JOIN {block_instance} bi ON bi.id = va.block
WHERE a.artefacttype = 'annotation'
AND bi.blocktype = 'annotation'
AND bi.id = ?", array($id));
}
public static function get_instance_javascript(BlockInstance $bi) {
return array(
array(
......@@ -338,4 +423,28 @@ class PluginBlocktypeAnnotation extends MaharaCoreBlocktype {
set_field('blocktype_installed', 'active', 0, 'artefactplugin', 'annotation');
}
}
public static function get_instance_config_javascript(BlockInstance $instance) {
return <<<EOF
jQuery(function($) {
if ($("#instconf_smartevidence").length) {
// block title will be overwritten with framework choice so make it disabled
$("#instconf_title").attr('disabled', true);
// Set up evidence choices and show/hide related descriptions
$("#instconf_smartevidence").select2();
function show_se_desc(id) {
$("#instconf_smartevidencedesc_container div:not(.description)").addClass('hidden');
$("#option_" + id).removeClass('hidden');
}
show_se_desc($("#instconf_smartevidence").val());
$("#instconf_smartevidence").on('change', function() {
show_se_desc($(this).val());
});
}
});
EOF;
}
}
......@@ -112,3 +112,4 @@ $string['private'] = 'Private';
$string['public'] = 'Public';
$string['enteredon'] = 'entered on';
$string['noreflectionentryfound'] = "Cannot find reflection entry for annotation.";
$string['nofeedback'] = "There is no feedback for this annotation yet.";
\ No newline at end of file
......@@ -627,7 +627,7 @@ class ArtefactTypeAnnotationfeedback extends ArtefactType {
$options->view = ''; // viewid that the annotation is linked to.
$options->block = ''; // blockid that the annotation lives in.
$options->export = false;
$options->export = 0;
$sortorder = get_user_institution_comment_sort_order();
$options->sort = (!empty($sortorder)) ? $sortorder : 'earliest';
return $options;
......@@ -797,7 +797,7 @@ class ArtefactTypeAnnotationfeedback extends ArtefactType {
if (isset($data->showcomment) && $data->showcomment == $item->id) {
$item->highlight = 1;
}
$is_export_preview = param_integer('export', 0);
$is_export_preview = param_integer('export', $data->export);
if ($item->deletedby) {
$item->deletedmessage = $deletedmessage[$item->deletedby];
}
......@@ -932,15 +932,160 @@ class ArtefactTypeAnnotationfeedback extends ArtefactType {
return $newest[0];
}
/**
* Fetching the annotations for an artefact to display on a matrix
*
* @param object $annotationartefact The annotation artefact to display feedbacks for.
* @param object $view The view on which the annotation artefact is linked to.
* @param int $blockid The id of the block instance that connects the artefact to the view
* @param boolean $listonly Only return the list and not the form
*
*/
public function get_annotation_feedback_for_matrix($annotationartefact, $view, $blockid, $listonly = false) {
$options = ArtefactTypeAnnotationfeedback::get_annotation_feedback_options();
$options->limit = 0;
$options->view = $view->get('id');
$options->annotation = $annotationartefact->get('id');
$options->block = $blockid;
$options->export = 1;
$options->sort = 'latest';
$annotationfeedback = ArtefactTypeAnnotationfeedback::get_annotation_feedback($options);
$annotationfeedbackcount = isset($annotationfeedback->count) ? $annotationfeedback->count : 0;
if ($listonly) {
return array($annotationfeedbackcount, $annotationfeedback);
}
$smarty = smarty_core();
$smarty->assign('blockid', $blockid);
$smarty->assign('annotationfeedbackcount', $annotationfeedbackcount);
$smarty->assign('annotationfeedback', $annotationfeedback);
if ($annotationartefact->get('allowcomments')) {
$form = ArtefactTypeAnnotationfeedback::add_annotation_feedback_form($annotationartefact, $view, null, $blockid, false, $annotationartefact->get('approvecomments'));
// Replace the submit/cancel with just a submit button
$submit = array(
'type' => 'submit',
'value' => get_string('placeannotationfeedback', 'artefact.annotation'),
'class' => 'btn-default'
);
$form['elements']['submit'] = $submit;
// Remove the 'assessment' option as we want that independent of submitting feedback here
unset($form['elements']['assessment']);
$addannotationfeedbackform = pieform($form);
$smarty->assign('addannotationfeedbackform', $addannotationfeedbackform);
}
else {
// The user has switched off annotation feedback. Don't create the add annotation feedback form.
$smarty->assign('addannotationfeedbackform', null);
}
$render = $smarty->fetch('artefact:annotation:annotationfeedbackmatrix.tpl');
return array($annotationfeedbackcount, $render);
}
/**
* Saving the annotation feedback via the matrix dock
*
* @param object $annotationartefact The annotation artefact to add feedback to.
* @param object $view The view the annotation artefact is on
* @param int $blockid The id of the block instance that connects the artefact to the view
* @param string $message The feedback message
* @param boolean $ispublic Whether it is a public message or not
*/
public function save_matrix_feedback($annotationartefact, $view, $blockid, $message, $ispublic = true) {
global $USER;
if (!is_object($annotationartefact) || !is_object($view) || empty($message)) {
throw new MaharaException(get_string('annotationinformationerror', 'artefact.annotation'));
}
$data = (object) array(
'title' => get_string('Annotation', 'artefact.annotation'),
'description' => $message,
'onannotation' => $annotationartefact->get('id'),
);
$data->view = $view->get('id');
$data->owner = $view->get('owner');
$data->group = $view->get('group');
$data->institution = $view->get('institution');
if ($author = $USER->get('id')) {
$anonymous = false;
$data->author = $author;
}
else {
$anonymous = true;
$data->authorname = $values['authorname'];
}
// @TODO deal with moderation
// if (isset($values['moderate']) && $values['ispublic'] && !$USER->can_edit_view($view)) {
// $data->private = 1;
// $data->requestpublic = 'author';
// $moderated = true;
// }
// else {
$data->private = (int) !$ispublic;
$moderated = false;
// }
$private = $data->private;
$annotationfeedback = new ArtefactTypeAnnotationfeedback(0, $data);
db_begin();
$annotationfeedback->commit();
db_commit();
if (isset($data->requestpublic) && $data->requestpublic === 'author' && $data->owner) {
$arg = $author ? display_name($USER, null, true) : $data->authorname;
$moderatemsg = (object) array(
'subject' => false,
'message' => false,
'strings' => (object) array(
'subject' => (object) array(
'key' => 'makepublicrequestsubject',
'section' => 'artefact.annotation',
'args' => array(),
),
'message' => (object) array(
'key' => 'makepublicrequestbyauthormessage',
'section' => 'artefact.annotation',
'args' => array(hsc($arg)),
),
'urltext' => (object) array(
'key' => 'Annotation',
'section' => 'artefact.annotation',
),
),
'users' => array($data->owner),
'url' => $url,
);
}
require_once('activity.php');
$data = (object) array(
'annotationfeedbackid' => $annotationfeedback->get('id'),
'annotationid' => $annotationartefact->get('id'),
'viewid' => $view->get('id'),
);
activity_occurred('annotationfeedback', $data, 'artefact', 'annotation');
if (isset($moderatemsg)) {
activity_occurred('maharamessage', $moderatemsg);
}
list($count, $newlist) = self::get_annotation_feedback_for_matrix($annotationartefact, $view, $blockid, true);
return $newlist->tablerows;
}
/**
* Fetching the annotations for an artefact to display on a view
*
* @param object $annotationartefact The annotation artefact to display feedbacks for.
* @param object $view The view on which the annotation artefact is linked to.
* @param int $blockid The id of the block instance that connects the artefact to the view
* @param int @annotationscountonview The number annotations alread on the view. If one is already
* on there, don't add the add_annotation_feedback_form as it's already been
* created.
* @param bool $html Whether to return the information rendered as html or not
* @param bool $editing Whether we are view edit mode or not
*/
......@@ -966,7 +1111,7 @@ class ArtefactTypeAnnotationfeedback extends ArtefactType {
// Return the rendered form.
$smarty = smarty_core();
if ($annotationartefact->get('allowcomments') && !$editing) {
$addannotationfeedbackform = pieform(ArtefactTypeAnnotationfeedback::add_annotation_feedback_form(false, $annotationartefact->get('approvecomments'), $annotationartefact, $view, null, $blockid));
$addannotationfeedbackform = pieform(ArtefactTypeAnnotationfeedback::add_annotation_feedback_form($annotationartefact, $view, null, $blockid, false, $annotationartefact->get('approvecomments')));
$smarty->assign('addannotationfeedbackform', $addannotationfeedbackform);
}
else {
......@@ -1058,14 +1203,15 @@ class ArtefactTypeAnnotationfeedback extends ArtefactType {
/**
* Create a form so the user can enter feedback for an annotation that is linked to
* a view or an artefact.
* @param boolean $defaultprivate set the private setting. Default is false.
* @param boolean $moderate if moderating feedback. Default is false.
* @param object $annotation the annotation artefact object.
* @param object $view the view object that the annotation is linked to.
* @param object $artefact the artefact object that the annotation is linked to.
* @param string $blockid the id of the block instance
* @param boolean $defaultprivate set the private setting. Default is false.
* @param boolean $moderate if moderating feedback. Default is false.
* @return multitype:string multitype:NULL string
*/
public static function add_annotation_feedback_form($defaultprivate=false, $moderate=false, $annotation, $view, $artefact, $blockid) {
public static function add_annotation_feedback_form($annotation, $view, $artefact, $blockid, $defaultprivate=false, $moderate=false) {
global $USER;
$form = array(
'name' => 'add_annotation_feedback_form_' . $blockid,
......@@ -1102,6 +1248,38 @@ class ArtefactTypeAnnotationfeedback extends ArtefactType {
'cols' => 80,
'rules' => array('maxlength' => 8192),
);
$collection = $view->get('collection');
if (is_object($collection) && $collection->has_framework()) {
$view->get_artefact_instances(); // populate the artefact_metadata
foreach ($view->get('artefact_metadata') as $metadata) {
if ($metadata->id === $annotation->get('id')) {
safe_require('module', 'framework');
$evidence = get_record('framework_evidence', 'annotation', $metadata->block);
$defaultval = $evidence->state;
if ($options = Framework::get_my_assessment_options_for_user($view->get('owner'), $evidence->framework)) {
if (!array_key_exists($defaultval, $options)) {
$defaultval = null;
}
$form['elements']['assessment'] = array(
'type' => 'select',
'title' => get_string('assessment', 'module.framework'),
'options' => $options,
'defaultvalue' => $defaultval,
'width' => '280px',
);
$form['elements']['evidence'] = array(
'type' => 'hidden',
'value' => $evidence->id,
);
}
}
}
}
$form['elements']['ispublic'] = array(
'type' => 'switchbox',
'title' => get_string('makepublic', 'artefact.annotation'),
......@@ -1593,6 +1771,18 @@ function add_annotation_feedback_form_submit(Pieform $form, $values) {
db_begin();
$annotationfeedback->commit();
if (!empty($values['evidence']) && !empty($values['assessment'])) {
$reviewer = null;
if ((int) $values['assessment'] === Framework::EVIDENCE_COMPLETED) {
$reviewer = $USER->get('id');
}
$fordb = array('mtime' => db_format_timestamp(time()),
'state' => $values['assessment'],
'reviewer' => $reviewer,
);
// update row
update_record('framework_evidence', (object) $fordb, (object) array('id' => $values['evidence']));
}
$url = $annotation->get_view_url($view->get('id'), true, false);
$goto = get_config('wwwroot') . $url;
......
......@@ -109,7 +109,8 @@ $form = pieform(array(
'name' => 'edit',
'plugintype' => 'core',
'pluginname' => 'collection',
'successcallback' => 'submit',
'validatecallback' => 'collectionedit_validate',
'successcallback' => 'collectionedit_submit',
'elements' => $elements,
));
......@@ -121,9 +122,32 @@ $smarty->assign('headingclass', 'page-header');
$smarty->assign_by_ref('form', $form);
$smarty->display('collection/edit.tpl');
function submit(Pieform $form, $values) {
function collectionedit_validate(Pieform $form, $values) {
if (!empty($values['id'])) {
$collection = new Collection($values['id']);
if ($collection->has_framework() && $collection->get('framework') != $values['framework']) {
// Make sure that if the user is changing the framework that there isn't annotations paired to the old framework
$views = get_records_sql_array("SELECT v.id, v.title FROM {view} v
JOIN {collection_view} cv ON cv.view = v.id
JOIN {framework_evidence} fe ON fe.view = cv.view
WHERE cv.collection = ?", array($values['id']));
if (!empty($views)) {
$errorstr = get_string('changeframeworkproblems', 'module.framework');
foreach ($views as $view) {
$errorstr .= " '" . $view->title . "'";
}
$form->set_error('framework', $errorstr);
}
}
}
}
function collectionedit_submit(Pieform $form, $values) {
global $SESSION, $new, $copy, $urlparams;
$values['navigation'] = (int) $values['navigation'];
if (empty($values['framework'])) {
$values['framework'] = null;
}
$collection = Collection::save($values);
if (!$new) {
$SESSION->add_ok_msg(get_string('collectionsaved', 'collection'));
......
......@@ -68,6 +68,10 @@ foreach ($data->data as $value) {
if (!empty($views)) {
$value->views = $views['views'];
}
if (is_plugin_active('framework', 'module') && $collection->has_framework()) {
$framework = new Framework($collection->get('framework'));
$value->frameworkname = $framework->get('name');
}
}
$smarty = smarty_core();
$smarty->assign('canedit', $canedit);
......
......@@ -96,6 +96,10 @@ foreach ($data->data as $value) {
if (!empty($views)) {
$value->views = $views['views'];
}
if (is_plugin_active('framework', 'module') && $collection->has_framework()) {
$framework = new Framework($collection->get('framework'));
$value->frameworkname = $framework->get('name');
}
}
$pagination = build_pagination(array(
......@@ -132,7 +136,6 @@ if (!empty($institutionname) && ($institutionname != 'mahara')) {