Commit 3abbb8b2 authored by Fabian-Andree Heidemann's avatar Fabian-Andree Heidemann
Browse files

[fs controller] add interface to facl

[file] integrate facl interface
parent 16416ee1
......@@ -439,3 +439,45 @@ class FSAjaxController(AbstractController):
path = json.loads(path)
path = fs.expand(path)
return {"permission": fs.checkPermissions(path)}
@cherrypy.expose
@cherrypy.tools.method(accept="GET")
def getfacl(self, path):
"""
Get the facl of a certain path.
:param path: path of interest
:returns: list of tuples with (type, user, mode[, default mode])
"""
self.release_session()
fs = self.get("fs")
self.release_database()
path = fs.expand(path)
return list(fs.getfacl(path))
@cherrypy.expose
@cherrypy.tools.method(accept="POST")
def setfacl(self, path, type, name, mode, remove=False, recursive=False, default=False):
"""
Set the facl entry for a certain user or group. On remote side, the commandline tool
'setfacl' is used, so this method delivers an interface to that.
:param path: path of interest
:param type: type, either 'user', 'group', 'mask' or 'other'
:param name: name of the user or group of interest
:param mode: mode to be set
:param remove: remove all extended facl entries (option '-x')
:param recursive: apply changes to all files and directories recursivley (option '-R')
:param default: edit the default values of an facl entry (option '-d')
:raises: AjaxException if type is not 'user', 'group', 'mask' or 'other'
"""
if type not in ("user", "group", "mask", "other"):
raise AjaxException("unknown type \"%s\"" % type)
self.release_session()
fs = self.get("fs")
self.release_database()
path = fs.expand(path)
if not isinstance(remove, bool): remove = json.loads(remove)
if not isinstance(recursive, bool): recursive = json.loads(recursive)
if not isinstance(default, bool): default = json.loads(default)
fs.setfacl(path, type, name, mode, remove, recursive, default)
......@@ -13,14 +13,14 @@
.fileselector .file-path-bar{position:absolute;top:3px}
.file-rightclickmenu{position:absolute}
.file-rightclickmenu .fa,.file-rightclickmenu .glyphicon{margin:0 10px 0 0!important}
.file-rightclickmenu.filemenu .compress,.file-rightclickmenu.filemenu .copy,.file-rightclickmenu.filemenu .cut,.file-rightclickmenu.filemenu .divider,.file-rightclickmenu.filemenu .download,.file-rightclickmenu.filemenu .info,.file-rightclickmenu.filemenu .openFile,.file-rightclickmenu.filemenu .openFileWith,.file-rightclickmenu.filemenu .remove,.file-rightclickmenu.filemenu .rename{display:block;visibility:visible}
.file-rightclickmenu.filemenu .compress,.file-rightclickmenu.filemenu .copy,.file-rightclickmenu.filemenu .cut,.file-rightclickmenu.filemenu .divider,.file-rightclickmenu.filemenu .download,.file-rightclickmenu.filemenu .info,.file-rightclickmenu.filemenu .openFile,.file-rightclickmenu.filemenu .openFileWith,.file-rightclickmenu.filemenu .remove,.file-rightclickmenu.filemenu .rename,.file-rightclickmenu.filemenu .setACLEntry,.file-rightclickmenu.filemenu .showACL{display:block;visibility:visible}
.file-rightclickmenu.filemenu .createFile,.file-rightclickmenu.filemenu .createFolder,.file-rightclickmenu.filemenu .openFolder,.file-rightclickmenu.filemenu .openFolderInNewTab,.file-rightclickmenu.filemenu .paste,.file-rightclickmenu.filemenu .upload{display:none;visibility:hidden}
.file-rightclickmenu.foldermenu .compress,.file-rightclickmenu.foldermenu .copy,.file-rightclickmenu.foldermenu .cut,.file-rightclickmenu.foldermenu .divider,.file-rightclickmenu.foldermenu .download,.file-rightclickmenu.foldermenu .info,.file-rightclickmenu.foldermenu .openFolder,.file-rightclickmenu.foldermenu .openFolderInNewTab,.file-rightclickmenu.foldermenu .remove,.file-rightclickmenu.foldermenu .rename{display:block;visibility:visible}
.file-rightclickmenu.foldermenu .compress,.file-rightclickmenu.foldermenu .copy,.file-rightclickmenu.foldermenu .cut,.file-rightclickmenu.foldermenu .divider,.file-rightclickmenu.foldermenu .download,.file-rightclickmenu.foldermenu .info,.file-rightclickmenu.foldermenu .openFolder,.file-rightclickmenu.foldermenu .openFolderInNewTab,.file-rightclickmenu.foldermenu .remove,.file-rightclickmenu.foldermenu .rename,.file-rightclickmenu.foldermenu .setACLEntry,.file-rightclickmenu.foldermenu .showACL{display:block;visibility:visible}
.file-rightclickmenu.foldermenu .createFile,.file-rightclickmenu.foldermenu .createFolder,.file-rightclickmenu.foldermenu .openFile,.file-rightclickmenu.foldermenu .openFileWith,.file-rightclickmenu.foldermenu .paste,.file-rightclickmenu.foldermenu .upload{display:none;visibility:hidden}
.file-rightclickmenu.bkgmenu .createFile,.file-rightclickmenu.bkgmenu .createFolder,.file-rightclickmenu.bkgmenu .upload{display:block;visibility:visible}
.file-rightclickmenu.bkgmenu .createFile,.file-rightclickmenu.bkgmenu .createFolder,.file-rightclickmenu.bkgmenu .divider,.file-rightclickmenu.bkgmenu .setACLEntry,.file-rightclickmenu.bkgmenu .showACL,.file-rightclickmenu.bkgmenu .upload{display:block;visibility:visible}
.file-rightclickmenu.bkgmenu .compress,.file-rightclickmenu.bkgmenu .copy,.file-rightclickmenu.bkgmenu .cut,.file-rightclickmenu.bkgmenu .download,.file-rightclickmenu.bkgmenu .info,.file-rightclickmenu.bkgmenu .openFile,.file-rightclickmenu.bkgmenu .openFileWith,.file-rightclickmenu.bkgmenu .openFolder,.file-rightclickmenu.bkgmenu .openFolderInNewTab,.file-rightclickmenu.bkgmenu .remove,.file-rightclickmenu.bkgmenu .rename{display:none;visibility:hidden}
.file-rightclickmenu.selectionmenu .compress,.file-rightclickmenu.selectionmenu .copy,.file-rightclickmenu.selectionmenu .cut,.file-rightclickmenu.selectionmenu .divider,.file-rightclickmenu.selectionmenu .download,.file-rightclickmenu.selectionmenu .info,.file-rightclickmenu.selectionmenu .remove{display:block;visibility:visible}
.file-rightclickmenu.selectionmenu .createFile,.file-rightclickmenu.selectionmenu .createFolder,.file-rightclickmenu.selectionmenu .openFile,.file-rightclickmenu.selectionmenu .openFileWith,.file-rightclickmenu.selectionmenu .openFolder,.file-rightclickmenu.selectionmenu .openFolderInNewTab,.file-rightclickmenu.selectionmenu .paste,.file-rightclickmenu.selectionmenu .rename,.file-rightclickmenu.selectionmenu .upload{display:none;visibility:hidden}
.file-rightclickmenu.selectionmenu .createFile,.file-rightclickmenu.selectionmenu .createFolder,.file-rightclickmenu.selectionmenu .openFile,.file-rightclickmenu.selectionmenu .openFileWith,.file-rightclickmenu.selectionmenu .openFolder,.file-rightclickmenu.selectionmenu .openFolderInNewTab,.file-rightclickmenu.selectionmenu .paste,.file-rightclickmenu.selectionmenu .rename,.file-rightclickmenu.selectionmenu .setACLEntry,.file-rightclickmenu.selectionmenu .showACL,.file-rightclickmenu.selectionmenu .upload{display:none;visibility:hidden}
.table-info-dialog>tbody>tr>td{border:none;border:0}
.table-info-dialog-width{width:114px}
.table-info-dialog{overflow:hidden;table-layout:fixed;word-wrap:break-word}
......
......@@ -94,7 +94,7 @@
margin: 0 10px 0 0 !important;
}
&.filemenu {
.openFile, .openFileWith, .rename, .copy, .cut, .remove, .download, .compress, .divider, .info {
.openFile, .openFileWith, .rename, .copy, .cut, .remove, .download, .compress, .divider, .info, .showACL, .setACLEntry {
.file-rightclickmenu-itemshow;
}
.openFolder, .openFolderInNewTab, .createFile, .createFolder, .upload, .paste {
......@@ -102,7 +102,7 @@
}
}
&.foldermenu {
.openFolder, .openFolderInNewTab, .rename, .copy, .cut, .remove, .download, .compress, .divider, .info {
.openFolder, .openFolderInNewTab, .rename, .copy, .cut, .remove, .download, .compress, .divider, .info, .showACL, .setACLEntry {
.file-rightclickmenu-itemshow;
}
.openFile, .openFileWith, .createFile, .createFolder, .upload, .paste {
......@@ -110,7 +110,7 @@
}
}
&.bkgmenu {
.createFile, .createFolder, .upload {
.createFile, .createFolder, .upload, .divider, .showACL, .setACLEntry {
.file-rightclickmenu-itemshow;
}
.openFile, .openFileWith, .openFolder, .openFolderInNewTab, .rename, .copy, .cut, .remove, .compress, .info, .download {
......@@ -121,7 +121,7 @@
.copy, .cut, .remove, .download, .compress, .divider, .info {
.file-rightclickmenu-itemshow;
}
.openFile, .openFileWith, .openFolder, .openFolderInNewTab, .rename, .createFile, .createFolder, .upload, .paste {
.openFile, .openFileWith, .openFolder, .openFolderInNewTab, .rename, .createFile, .createFolder, .upload, .paste, .showACL, .setACLEntry {
.file-rightclickmenu-itemhide;
}
}
......
......@@ -17,5 +17,7 @@
<li class="divider"></li>
<li class="paste"><a href="#" tabindex="14"><i class="glyphicon glyphicon-share-alt"></i>Paste</a></li>
<li class="info"><a href="#" tabindex="15"><i class="glyphicon glyphicon-info-sign"></i>Info</a></li>
<li class="showACL"><a href="#" tabindex="16"><i class="glyphicon glyphicon-search"></i>Show ACL</a></li>
<li class="setACLEntry"><a href="#" tabindex="17"><i class="glyphicon glyphicon-wrench"></i>Set ACL entry</a></li>
</ul>
</div>
\ No newline at end of file
......@@ -62,3 +62,11 @@
a(href="#", tabindex=15)
i.glyphicon.glyphicon-info-sign
| Info
li.showACL
a(href="#", tabindex=16)
i.glyphicon.glyphicon-search
| Show ACL
li.setACLEntry
a(href="#", tabindex=17)
i.glyphicon.glyphicon-wrench
| Set ACL entry
<div class="form-horizontal">
<div class="form-group">
<label for="type" class="control-label col-xs-2">Type:</label>
<div class="col-xs-10">
<select type="select" id="type" class="form-control">
<option>user</option>
<option>group</option>
<option>mask</option>
<option>other</option>
</select>
</div>
</div>
<div class="form-group">
<label for="name" class="control-label col-xs-2">Name:</label>
<div class="col-xs-10">
<input type="text" id="name" placeholder="Name" class="form-control"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-2">Rights:</label>
<div class="col-xs-3">
<label class="checkbox-inline">
<input type="checkbox" value="" id="read"/>Read
</label>
</div>
<div class="col-xs-3">
<label class="checkbox-inline">
<input type="checkbox" value="" id="write"/>Write
</label>
</div>
<div class="col-xs-3">
<label class="checkbox-inline">
<input type="checkbox" value="" id="execute"/>Execute
</label>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-2">Options:</label>
<div class="col-xs-3">
<label class="checkbox-inline">
<input type="checkbox" value="" id="remove"/>Remove
</label>
</div>
<div class="col-xs-3">
<label class="checkbox-inline">
<input type="checkbox" value="" id="recursive"/>Recursive
</label>
</div>
<div class="col-xs-3">
<label class="checkbox-inline">
<input type="checkbox" value="" id="default"/>Default
</label>
</div>
</div>
</div>
<div>
<button type="button" id="cancel" class="btn btn-default">Cancel</button>
<button type="button" id="ok" class="btn btn-primary">Ok</button>
</div>
\ No newline at end of file
div.form-horizontal
div.form-group
label.control-label.col-xs-2(for="type") Type:
div.col-xs-10
select.form-control(type="select", id="type")
option user
option group
option mask
option other
div.form-group
label.control-label.col-xs-2(for="name") Name:
div.col-xs-10
input.form-control(type="text", id="name", placeholder="Name")
div.form-group
label.control-label.col-xs-2 Rights:
div.col-xs-3
label.checkbox-inline
input(type="checkbox", value="", id="read")
|Read
div.col-xs-3
label.checkbox-inline
input(type="checkbox", value="", id="write")
|Write
div.col-xs-3
label.checkbox-inline
input(type="checkbox", value="", id="execute")
|Execute
div.form-group
label.control-label.col-xs-2 Options:
div.col-xs-3
label.checkbox-inline
input(type="checkbox", value="", id="remove")
|Remove
div.col-xs-3
label.checkbox-inline
input(type="checkbox", value="", id="recursive")
|Recursive
div.col-xs-3
label.checkbox-inline
input(type="checkbox", value="", id="default")
|Default
div
button.btn.btn-default(type="button", id="cancel") Cancel
button.btn.btn-primary(type="button", id="ok") Ok
<div>
<table class="table table-condensed table-hover">
<thead>
<tr>
<th>Type</th>
<th>Name</th>
<th>Rights</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr>
<td data-bind="type"></td>
<td data-bind="name"></td>
<td data-bind="rights"></td>
<td data-bind="default"></td>
</tr>
</tbody>
</table>
</div>
\ No newline at end of file
div
table.table.table-condensed.table-hover
thead
tr
th Type
th Name
th Rights
th Default
tbody
tr
td(data-bind="type")
td(data-bind="name")
td(data-bind="rights")
td(data-bind="default")
......@@ -4,6 +4,8 @@ define([
"text!../../html/openDialog.html",
"text!../../html/infodialog.html",
"text!../../html/infodialogmore.html",
"text!../../html/showACLdialog.html",
"text!../../html/setACLdialog.html",
"text!../../html/uploadProgressbar.html"
], function (
$,
......@@ -11,6 +13,8 @@ define([
openTmpl,
infoTmpl,
moreTmpl,
showACLdialogTmpl,
setACLdialogTmpl,
progressbarTmpl
) {
......@@ -202,11 +206,11 @@ define([
});
// footer
var $footer = $('<div>\
<div type="button" id="cancel" class="btn btn-danger">\
<div type="button" id="cancel" class="btn btn-default">\
<i class="glyphicon glyphicon-remove"></i>\
<span>cancel</span>\
</div>\
<div type="button" id="open" class="btn btn-success">\
<div type="button" id="open" class="btn btn-primary">\
<i class="glyphicon glyphicon-open"></i>\
<span>open</span>\
</div>\
......@@ -267,7 +271,6 @@ define([
defaultValue: name
});
});
},
_rename: function (path, name, newName) {
......@@ -353,7 +356,6 @@ define([
});
},
remove: function () {
var self = this;
this.entries = Object.keys(this.FileBase.selections.entries);
......@@ -370,7 +372,6 @@ define([
} else {
self._remove();
}
},
_remove: function () {
......@@ -447,6 +448,121 @@ define([
return this;
},
showACL: function () {
var self = this;
var path = Object.keys(self.FileBase.selections.entries);
var filetype = "file";
if (path.length == 0) {
path = self.FileBase.instance.getState("path");
filetype = "folder";
} else if (path.length == 1) {
path = Object.keys(self.FileBase.selections.entries)[0];
if (self.FileBase.selections.entries[path].data().data.type == "d") filetype = "folder";
} else {
self.FileBase.instance.alert("Can not get ACL of multiple files.");
return;
}
var filename = self.FileBase.helper.filenameFromPath(path);
self.FileBase.instance.GET("/ajax/fs/getfacl", {
path: path
}, function (err, res) {
if (err) return;
var $body = $(showACLdialogTmpl);
$("tbody", $body).render(res, {
type: {
text: function () {
return this[0];
}
},
name: {
text: function () {
return this[1];
}
},
rights: {
text: function () {
return this[2];
}
},
default: {
text: function () {
if (this.length == 4) {
return this[3];
} else {
return "-"
}
}
}
});
self.FileBase.instance.alert($body.html(), {
header: "ACL of " + filetype + " \"" + filename + "\"",
okLabel: "Close"
});
});
},
setACLEntry: function () {
var self = this;
var path = Object.keys(self.FileBase.selections.entries);
var filetype = "file";
if (path.length == 0) {
path = self.FileBase.instance.getState("path");
filetype = "folder";
} else if (path.length == 1) {
path = Object.keys(self.FileBase.selections.entries)[0];
if (self.FileBase.selections.entries[path].data().data.type == "d") filetype = "folder";
} else {
self.FileBase.instance.alert("Setting ACL entry for multiple files not implemented.");
return;
}
var filename = self.FileBase.helper.filenameFromPath(path);
// render dialog
var dialog = null;
// body
var $body = $(setACLdialogTmpl).first();
//footer
var $footer = $(setACLdialogTmpl).last();
$("#cancel", $footer).click(function () {
dialog.close();
});
$("#ok", $footer).click(function () {
opts = {
path: path
}
opts.type = $("#type", $body).val();
opts.name = $("#name", $body).val();
if (!opts.name && opts.type != "mask" && opts.type != "other") {
self.FileBase.instance.alert("Please insert a valid name.");
return;
}
opts.mode = ""
if ($("#read", $body).prop("checked")) opts.mode += "r"
if ($("#write", $body).prop("checked")) opts.mode += "w"
if ($("#execute", $body).prop("checked")) opts.mode += "x"
opts.remove = $("#remove", $body).prop("checked");
opts.recursive = $("#recursive", $body).prop("checked");
opts.default = $("#default", $body).prop("checked");
self.FileBase.instance.POST("/ajax/fs/setfacl", opts);
dialog.close();
});
// dialog
self.FileBase.instance.dialog({
header: "Set ACL entry for " + filetype + " \"" + filename + "\"",
body: $body,
footer: $footer,
beforeClose: function (cb) {
cb();
},
onRender: function () {
dialog = this;
}
});
},
info: function () {
var self = this;
var sizeSuffix = null;
......@@ -504,7 +620,7 @@ define([
});
// render when more items are selected
} else {
var appendToRender = $(moteTmpl);
var appendToRender = $(moreTmpl);
$("tbody", appendToRender).render(array);
$(".file-info-dialog-header", appendToRender).render({
"numberOfSelectedItems": numberOfSelectedItems,
......@@ -517,7 +633,6 @@ define([
});
}
}
},
createFile: function () {
......
......@@ -21,8 +21,8 @@ define(["jquery", "jclass"], function($, JClass) {
});
var events = ["openFile", "openFileWith", "openFolder", "openFolderInNewTab", "rename",
"copy", "cut", "remove", "download", "compress", "info", "select", "createFile",
"createFolder", "paste", "upload"
"copy", "cut", "remove", "download", "compress", "showACL", "setACLEntry", "info",
"createFile", "createFolder", "paste", "upload"
];
$.each(events, function() {
var name = this;
......
......@@ -7,6 +7,7 @@ import mimetypes
from zipfile import ZipFile
from threading import Lock, Thread
from time import time
from subprocess import call, check_output
import ConfigParser
import json
import logging
......@@ -456,6 +457,42 @@ class FileSystem(object):
def checkPermissions(self, path, permission=os.W_OK):
return os.access(path, permission)
def getfacl(self, path):
o = check_output(["getfacl", "-p", "-t", path])
facls = []
for line in o.splitlines():
if not line: continue
if line.startswith("#"): continue
e = line.split()
if e[0] in ["mask", "other"]: e[1:1] = [""]
facls.append(tuple(e))
return facls
def setfacl(self, path, type, name, mode, remove=False, recursive=False, default=False):
if type not in ("user", "group", "mask", "other"):
raise TypeError("type '%s' not in ('user', 'group', 'mask', 'other')" % type)
if type in ("mask", "other"):
name = ""
arguments = ["setfacl"]
if default:
arguments.append("-d")
if recursive:
arguments.append("-R")
if remove:
action = "-x"
acl = "%s:%s" % (type, name)
else:
action = "-m"
acl = "%s:%s:%s" % (type, name, mode)
arguments.append(action)
arguments.append(acl)
arguments.append(path)
call(arguments, stderr=open(os.devnull, "wb"))
def save_file_content(self, filename, content,
path=None, force=True, append=False):
# check write permissions
......
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