Commit dc4f8c97 authored by Richard Mansfield's avatar Richard Mansfield
Browse files

Group files area

parent 6b30b435
......@@ -29,7 +29,6 @@ define('JSON', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
safe_require('artefact', 'file');
global $USER;
json_headers();
......@@ -39,6 +38,7 @@ $description = param_variable('description', null);
$tags = param_variable('tags', null);
$collideaction = param_variable('collideaction', 'fail');
$institution = param_alpha('institution', null);
$group = param_integer('group', null);
$data = new StdClass;
if ($parentfolder) {
......@@ -47,13 +47,24 @@ if ($parentfolder) {
$data->title = $title;
$data->description = $description;
$data->tags = $tags;
$data->owner = null;
if ($institution) {
$data->institution = $institution;
} else if ($group) {
require_once(get_config('docroot') . 'artefact/lib.php');
require_once(get_config('docroot') . 'lib/group.php');
if ($parentfolder && !$USER->can_edit_artefact(artefact_instance_from_id($parentfolder))) {
json_reply('local', get_string('cannoteditfolder', 'artefact.file'));
} else if (!$parentfolder && !user_can_access_group($group)) {
json_reply('local', get_string('usernotingroup', 'mahara'));
}
$data->group = $group;
$data->rolepermissions = json_decode(param_variable('permissions'));
} else {
$data->owner = $USER->get('id');
}
if ($oldid = ArtefactTypeFileBase::file_exists($data->title, $data->owner, $parentfolder, $institution)) {
if ($oldid = ArtefactTypeFileBase::file_exists($data->title, $data->owner, $parentfolder, $institution, $group)) {
if ($collideaction == 'replace') {
require_once(get_config('docroot') . 'artefact/lib.php');
$obj = artefact_instance_from_id($oldid);
......
......@@ -77,22 +77,53 @@ browser.changedircallback = uploader.updatedestination;
JAVASCRIPT;
$smarty = smarty(
array('tablerenderer', 'artefact/file/js/file.js'),
array(),
array(),
array(
'sideblocks' => array(
array(
'name' => 'quota',
'weight' => -10,
'data' => array(),
$groupid = param_integer('group', null);
if ($groupid and
$group = get_record_sql('
SELECT g.id, g.name, g.grouptype, m.role AS userrole
FROM {group} g INNER JOIN {group_member} m ON g.id = m.group
WHERE g.id = ' . $groupid . ' AND m.member = ' . $USER->get('id'))) {
require_once(get_config('docroot') . 'interaction/lib.php');
require_once(get_config('docroot') . 'lib/grouptype/' . $group->grouptype . '.php');
$groupdata = json_encode($group);
$grouproles = json_encode(call_static_method('GroupType' . $group->grouptype, 'get_roles'));
$javascript .= <<<GROUPJS
var group = {$groupdata};
group.roles = {$grouproles};
browser.setgroup({$groupid});
uploader.setgroup({$groupid});
GROUPJS;
$smarty = smarty(
array('tablerenderer', 'artefact/file/js/file.js'),
array(),
array(),
array(
'sideblocks' => array(
interaction_sideblock($groupid),
),
),
)
);
)
);
$smarty->assign('heading', get_string('filesfor', 'artefact.file', $group->name));
}
else {
$smarty = smarty(
array('tablerenderer', 'artefact/file/js/file.js'),
array(),
array(),
array(
'sideblocks' => array(
array(
'name' => 'quota',
'weight' => -10,
'data' => array(),
),
),
)
);
$smarty->assign('heading', get_string('myfiles', 'artefact.file'));
}
$smarty->assign('INLINEJAVASCRIPT', $javascript);
$smarty->assign('heading', get_string('myfiles', 'artefact.file'));
$smarty->display('artefact:file:index.tpl');
?>
......@@ -23,6 +23,53 @@ function ajaxlogin_iframe(form, crap) {
save_orig_data = true;
}
var group = 0;
function getpermissions(formid) {
var result = {};
var perms = getElementsByTagAndClassName('input', 'permission', formid);
for (var i = 0; i < perms.length; i++) {
var parts = perms[i].name.split(":");
if (!result[parts[1]]) {
result[parts[1]] = {};
}
result[parts[1]][parts[2]] = perms[i].checked;
}
return result;
}
var permissiontypes = ['view', 'edit', 'republish'];
function permissionform_inputs(permissions, role) {
var cells = [TD(null, get_string(role))];
for (var i = 0; i < permissiontypes.length; i++) {
var properties = {
'type':'checkbox',
'class':'permission',
'name':'permission:'+role+':'+permissiontypes[i],
};
if (role == 'admin' || permissions.all || permissions[role] && permissions[role][permissiontypes[i]] == 1) {
properties.checked = true;
if (role == 'admin') {
properties.disabled = true;
}
}
cells.push(TD(null, INPUT(properties)));
}
return cells;
}
function permissionform_row(permissions) {
if (!group) {
return null;
}
var rows = map(partial(TR, null), map(partial(permissionform_inputs, permissions), group.roles));
return TR(null, TH(null, LABEL(null, get_string('Permissions'))), TD(null,
TABLE({'class':'editpermissions'}, TBODY(null,
TR(null, TH(null, get_string('Role')), map(partial(TH, null), map(get_string, permissiontypes))),
rows))));
}
// The file browser part needs to be kept relatively separated from
// the file uploader because they are used slightly differently in the
// my files screen and the edit blog post screen
......@@ -86,7 +133,7 @@ function FileBrowser(element, source, statevars, changedircallback, actionname,
}
else {
this.lastcolumnfunc = function (r) {
if (r.isparent) {
if (r.isparent || r.can_edit == 0) {
return TD(null);
}
var editb = INPUT({'type':'button', 'class':'button', 'value':get_string('edit')});
......@@ -107,6 +154,11 @@ function FileBrowser(element, source, statevars, changedircallback, actionname,
}
}
this.setgroup = function(gid) {
self.source += '?group=' + gid;
self.createfolderscript += '?group=' + gid;
};
this.init = function() {
if (self.canmodify) {
......@@ -255,6 +307,10 @@ function FileBrowser(element, source, statevars, changedircallback, actionname,
data['description'] = $(formid).description.value;
data['tags'] = $(formid).tags.value;
if (group) {
data['permissions'] = serializeJSON(getpermissions(formid));
}
if (fileid) {
var script = self.updatemetadatascript;
data['id'] = fileid;
......@@ -284,8 +340,14 @@ function FileBrowser(element, source, statevars, changedircallback, actionname,
var cancelbutton = INPUT({'type':'button', 'class':'button',
'value':get_string('cancel'), 'onclick':cancelform});
var editformtitle = get_string(fileinfo.artefacttype == 'folder' ? 'editfolder' : 'editfile');
var edittable = TABLE({'align':'center'},TBODY(null,
TR(null,TH({'colspan':2},LABEL(editformtitle))),
if (group) {
var perm = permissionform_row(fileinfo.permissions);
}
else {
var perm = null;
}
var edittable = TABLE(null, TBODY(null,
TR(null,TH({'colSpan':2},LABEL(editformtitle))),
TR(null,TH(null,LABEL(get_string('Name'))),
TD(null,INPUT({'type':'text','class':'text','name':'name',
'value':fileinfo.title,'size':40}))),
......@@ -294,8 +356,9 @@ function FileBrowser(element, source, statevars, changedircallback, actionname,
'value':fileinfo.description,'size':40}))),
TR(null, TH(null, LABEL(null, get_string('tags'))),
TD(null, create_tags_control('tags', fileinfo.tags))),
TR(null,TD({'colspan':2},SPAN({'id':formid+'message'}))),
TR(null,TD({'colspan':2}, savebutton, replacebutton, cancelbutton))));
perm,
TR(null,TD({'colSpan':2},SPAN({'id':formid+'message'}))),
TR(null,TD({'colSpan':2}, savebutton, replacebutton, cancelbutton))));
hideElement(rowid);
insertSiblingNodesBefore(rowid, TR({'id':editid},
TD({'colSpan':6},
......@@ -329,6 +392,12 @@ function FileBrowser(element, source, statevars, changedircallback, actionname,
cancelcreateform();
}
}});
if (group) {
var perm = permissionform_row({'all':1});
}
else {
var perm = null;
}
return FORM({'method':'post', 'id':formid, 'style':'display: none;'},
TABLE(null,
TBODY(null,
......@@ -342,6 +411,7 @@ function FileBrowser(element, source, statevars, changedircallback, actionname,
TD(null,INPUT({'type':'text','class':'text','name':'description',
'value':'','size':40}))),
TR(null, TH(null, LABEL(null, get_string('tags'))), TD({'colspan':'2'}, create_tags_control('tags'))),
perm,
TR(null,TD({'colspan':2},SPAN({'id':formid+'message'}))),
TR(null,TD({'colspan':2},createbutton,replacebutton,cancelbutton)))));
};
......@@ -504,6 +574,10 @@ function FileUploader(element, uploadscript, statevars, foldername, folderid, up
this.fileexists = function (filename) { alert(filename); };
}
this.setgroup = function(gid) {
self.uploadscript += '?group=' + gid;
};
this.init = function() {
self.nextupload = 1;
......@@ -542,6 +616,12 @@ function FileUploader(element, uploadscript, statevars, foldername, folderid, up
var notice = SPAN(null);
notice.innerHTML = copyrightnotice + get_string('notice.help');
var destinationattributes = (self.folderid === false) ? {'style':'display: none;'} : null;
if (group) {
var perm = permissionform_row({'all':1});
}
else {
var perm = null;
}
appendChildNodes(form,
TABLE(null,
TBODY(null,
......@@ -560,6 +640,7 @@ function FileUploader(element, uploadscript, statevars, foldername, folderid, up
TD(null, INPUT({'type':'text', 'class':'text', 'name':'description', 'size':40}))),
TR(null, TH(null, LABEL(null, get_string('tags'))),
TD({'colspan': 2}, create_tags_control('tags'))),
perm,
TR(null,TD({'colspan':2, 'id':'uploadformmessage'})),
TR(null,TD({'colspan':2},
INPUT({'name':'upload','type':'button','class':'button',
......@@ -643,6 +724,14 @@ function FileUploader(element, uploadscript, statevars, foldername, folderid, up
INPUT({'type':'hidden', 'name':'createid', 'value':self.createid}));
}
if (group) {
appendChildNodes(self.form, INPUT({
'type':'hidden',
'name':'permissions',
'value':serializeJSON(getpermissions('uploadform'))
}));
}
self.form.submit();
// Display upload status
......
......@@ -59,6 +59,7 @@ $string['filelistloaded'] = 'File list loaded';
$string['filemoved'] = 'File moved successfully';
$string['filenamefieldisrequired'] = 'The file field is required';
$string['fileinstructions'] = 'Upload your images, documents, or other files for inclusion in views. To move a file or folder, drag and drop it onto a folder.';
$string['filesfor'] = 'Files for %s';
$string['filethingdeleted'] = '%s deleted';
$string['filetypes'] = 'Configure Uploadable File Types';
$string['filetypedescription'] = '<p>You may configure the allowed file types that users can upload here. This grants you more control over what can be uploaded. This checking is performed in addition to virus checking, if you have virus checking turned on.</p><p>Note that &quot;Unknown Application&quot; may be necessary for some movies and archive files (such as gzip) to work.<p>';
......
......@@ -109,7 +109,10 @@ class PluginArtefactFile extends PluginArtefact {
'cancel',
'delete',
'edit',
'Permissions',
'republish',
'tags',
'view',
),
'artefact.file' => array(
'copyrightnotice',
......@@ -140,6 +143,9 @@ class PluginArtefactFile extends PluginArtefact {
'uploadingfiletofolder',
'youmustagreetothecopyrightnotice',
),
'group' => array(
'Role',
),
),
);
return $jsstrings[$type];
......@@ -378,13 +384,18 @@ abstract class ArtefactTypeFileBase extends ArtefactType {
// Check if something exists in the db with a given title and parent,
// either in adminfiles or with a specific owner.
public static function file_exists($title, $owner, $folder, $institution=null) {
public static function file_exists($title, $owner, $folder, $institution=null, $group=null) {
$filetypesql = "('" . join("','", PluginArtefactFile::get_artefact_types()) . "')";
$phvals = array($title);
if ($institution) {
$ownersql = 'a.institution = ? AND a.owner IS NULL';
$phvals[] = $institution;
} else {
}
else if ($group) {
$ownersql = 'a.group = ? AND a.owner IS NULL';
$phvals[] = $group;
}
else {
$ownersql = 'a.institution IS NULL AND a.owner = ?';
$phvals[] = $owner;
}
......@@ -404,50 +415,93 @@ abstract class ArtefactTypeFileBase extends ArtefactType {
}
public static function get_my_files_data($parentfolderid, $userid, $institution=null) {
public static function get_my_files_data($parentfolderid, $userid, $institution=null, $group=null) {
$foldersql = $parentfolderid ? ' = ' . $parentfolderid : ' IS NULL';
if ($institution) {
$ownersql = 'a.institution = ? AND a.owner IS NULL';
$phvals = array($institution);
} else {
$ownersql = 'a.institution IS NULL AND a.owner = ?';
$phvals = array($userid);
}
// if blogs are installed then also return the number of blog
// posts each file is attached to
$bloginstalled = get_field('artefact_installed', 'active', 'name', 'blog');
$filetypesql = "('" . join("','", PluginArtefactFile::get_artefact_types()) . "')";
$filedata = get_records_sql_array('
$select = '
SELECT
a.id, a.artefacttype, a.mtime, f.size, a.title, a.description,
COUNT(c.id) AS childcount '
. ($bloginstalled ? ', COUNT (b.blogpost) AS attachcount' : '') . '
COUNT(c.id) AS childcount, COUNT (b.blogpost) AS attachcount';
$from = '
FROM {artefact} a
LEFT OUTER JOIN {artefact_file_files} f ON f.artefact = a.id
LEFT OUTER JOIN {artefact} c ON c.parent = a.id '
. ($bloginstalled ? ('LEFT OUTER JOIN
{artefact_blog_blogpost_file} b ON b.file = a.id') : '') . '
WHERE a.parent' . $foldersql . '
AND ' . $ownersql . '
AND a.artefacttype IN ' . $filetypesql . '
LEFT OUTER JOIN {artefact} c ON c.parent = a.id
LEFT OUTER JOIN {artefact_blog_blogpost_file} b ON b.file = a.id';
$where = "
WHERE a.artefacttype IN ('" . join("','", PluginArtefactFile::get_artefact_types()) . "')";
$groupby = '
GROUP BY
a.id, a.artefacttype, a.mtime, f.size, a.title, a.description;', $phvals);
a.id, a.artefacttype, a.mtime, f.size, a.title, a.description';
$phvals = array();
if ($institution) {
$where .= '
AND a.institution = ? AND a.owner IS NULL';
$phvals[] = $institution;
}
else if ($group) {
global $USER;
$select .= ',
r.can_edit, r.can_view';
$from .= '
LEFT OUTER JOIN (
SELECT ar.artefact, ar.can_edit, ar.can_view
FROM {artefact_access_role} ar
INNER JOIN {group_member} gm ON ar.role = gm.role
WHERE gm.group = ? AND gm.member = ?
) r ON r.artefact = a.id';
$phvals[] = $group;
$phvals[] = $USER->get('id');
$where .= '
AND a.group = ? AND a.owner IS NULL AND r.can_view = 1';
$phvals[] = $group;
$groupby .= ', r.can_edit, r.can_view';
}
else {
$where .= '
AND a.institution IS NULL AND a.owner = ?';
$phvals[] = $userid;
}
if ($parentfolderid) {
$where .= '
AND a.parent = ? ';
$phvals[] = $parentfolderid;
}
else {
$where .= '
AND a.parent IS NULL';
}
$filedata = get_records_sql_assoc($select . $from . $where . $groupby, $phvals);
if (!$filedata) {
$filedata = array();
}
else {
foreach ($filedata as $item) {
$item->mtime = format_date(strtotime($item->mtime), 'strfdaymonthyearshort');
$item->tags = get_column('artefact_tag', 'tag', 'artefact', $item->id);
if (!is_array($item->tags)) {
$item->tags = array();
$item->tags = array();
}
$where = 'artefact IN (' . join(',', array_keys($filedata)) . ')';
$tags = get_records_select_array('artefact_tag', $where);
if ($tags) {
foreach ($tags as $t) {
$filedata[$t->artefact]->tags[] = $t->tag;
}
}
if ($group) { // Fetch permissions for each artefact
$perms = get_records_select_array('artefact_access_role', $where);
if ($perms) {
foreach ($perms as $perm) {
$filedata[$perm->artefact]->permissions[$perm->role] = array(
'view' => $perm->can_view,
'edit' => $perm->can_edit,
'republish' => $perm->can_republish
);
}
}
}
$filedata = array_values($filedata);
}
// Add parent folder to the list
......
......@@ -35,10 +35,11 @@ $limit = param_integer('limit', null);
$offset = param_integer('offset', 0);
$folder = param_integer('folder', null);
$institution = param_alpha('institution', null);
$group = param_integer('group', null);
$userid = $USER->get('id');
safe_require('artefact', 'file');
$filedata = ArtefactTypeFileBase::get_my_files_data($folder, $userid, $institution);
$filedata = ArtefactTypeFileBase::get_my_files_data($folder, $userid, $institution, $group);
$result = array(
'count' => count($filedata),
......
......@@ -32,18 +32,21 @@ safe_require('artefact', 'file');
json_headers();
global $USER;
$parentfolder = param_variable('parentfolder', null); // id of parent artefact
$id = param_integer('id');
$name = param_variable('name');
$description = param_variable('description');
$tags = param_variable('tags');
$collideaction = param_variable('collideaction', 'fail');
$institution = param_alpha('institution', null);
$owner = $USER->get('id');
if ($existingid = ArtefactTypeFileBase::file_exists($name, $owner, $parentfolder, $institution)) {
$artefact = artefact_instance_from_id($id);
$group = $artefact->get('group');
if ($group && !$USER->can_edit_artefact($artefact)) {
json_reply('local', get_string('noeditpermission', 'mahara'));
}
if ($existingid = ArtefactTypeFileBase::file_exists($name, $artefact->get('owner'), $parentfolder,
$artefact->get('institution'), $group)) {
if ($existingid != $id) {
if ($collideaction == 'replace') {
log_debug('deleting ' . $existingid);
......@@ -56,14 +59,11 @@ if ($existingid = ArtefactTypeFileBase::file_exists($name, $owner, $parentfolder
}
}
$artefact = artefact_instance_from_id($id);
$artefact->set('title', $name);
$artefact->set('description', $description);
$artefact->set('tags', preg_split("/\s*,\s*/", trim($tags)));
if ($institution) {
$artefact->set('institution', $institution);
} else {
$artefact->set('owner', $owner);
if ($group) {
$artefact->set('rolepermissions', json_decode(param_variable('permissions')));
}
$artefact->commit();
......
......@@ -28,7 +28,6 @@ define('INTERNAL', 1);
define('IFRAME', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
safe_require('artefact', 'file');
global $USER;
$parentfolder = param_variable('parentfolder', null); // id of parent artefact
$parentfoldername = param_variable('parentfoldername', ''); // path to parent folder
......@@ -38,6 +37,7 @@ $tags = param_variable('tags', null);
$uploadnumber = param_integer('uploadnumber'); // id of target iframe
$collideaction = param_variable('collideaction', 'fail');
$institution = param_alpha('institution', null);
$group = param_integer('group', null);
$data = new StdClass;
if ($parentfolder) {
......@@ -48,6 +48,16 @@ $data->description = $description;
$data->tags = $tags;
if ($institution) {
$data->institution = $institution;
} else if ($group) {
require_once(get_config('docroot') . 'artefact/lib.php');
require_once(get_config('docroot') . 'lib/group.php');
if ($parentfolder && !$USER->can_edit_artefact(artefact_instance_from_id($parentfolder))) {
json_reply('local', get_string('cannoteditfolder', 'artefact.file'));
} else if (!$parentfolder && !user_can_access_group($group)) {
json_reply('local', get_string('usernotingroup', 'mahara'));
}
$data->group = $group;
$data->rolepermissions = json_decode(param_variable('permissions'));
} else {
$data->owner = $USER->get('id');
}
......@@ -57,7 +67,7 @@ $data->locked = 0;
$result = new StdClass;
$result->uploadnumber = $uploadnumber;
if ($oldid = ArtefactTypeFileBase::file_exists($title, $data->owner, $parentfolder, $institution)) {
if ($oldid = ArtefactTypeFileBase::file_exists($title, $data->owner, $parentfolder, $institution, $group)) {
if ($collideaction == 'replace') {
$obj = artefact_instance_from_id($oldid);
$obj->delete();
......
......@@ -96,6 +96,7 @@ abstract class ArtefactType {
protected $tags = array();
protected $institution;
protected $group;
protected $rolepermissions;
protected $viewsinstances;
protected $viewsmetadata;
......@@ -148,6 +149,11 @@ abstract class ArtefactType {
}
}
// load group permissions
if ($this->group) {
$this->load_rolepermissions();
}
$this->atime = time();
$this->artefacttype = $this->get_artefact_type();
}
......@@ -317,6 +323,10 @@ abstract class ArtefactType {
update_record('artefact', $fordb, 'id');
}
if (!empty($this->group)) {
$this->save_rolepermissions();
}
delete_records('artefact_tag', 'artefact', $this->id);
if (is_array($this->tags)) {
foreach (array_unique($this->tags) as $tag) {
......@@ -550,6 +560,44 @@ abstract class ArtefactType {
public static function collapse_config() {
return false;
}
private function save_rolepermissions() {
$group = $this->get('group');
if (!$group) {
return;