cyclic structure resolution & edit sharing
This commit is contained in:
parent
2dafb07cea
commit
a078b768da
@ -152,9 +152,26 @@ const breakpoint = (html = false, name = null) => {
|
||||
}
|
||||
if ( window ) window.out = out; window.breakpoint = breakpoint;
|
||||
// ===========================================================`
|
||||
}
|
||||
},
|
||||
permission: {
|
||||
project: {
|
||||
edit(project, target_user){
|
||||
if ( project.user_id === target_user.uuid ) return true
|
||||
else if ( project.edit_user_ids.includes(target_user.uuid) ) return true
|
||||
else return false
|
||||
},
|
||||
view(project, target_user){
|
||||
if ( project.user_id === target_user.uuid ) return true
|
||||
else if ( project.shared_user_ids.includes(target_user.uuid) ) return true
|
||||
else if ( project.edit_user_ids.includes(target_user.uuid) ) return true
|
||||
else return false
|
||||
},
|
||||
owns(project, target_user){
|
||||
return (project.user_id === target_user.uuid)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
name(){
|
||||
|
52
app/assets/agents/web.js
Normal file
52
app/assets/agents/web.js
Normal file
@ -0,0 +1,52 @@
|
||||
// ===========================================================
|
||||
// DEVBUG INLINE DEBUGGING HELPER - FOR USE WITH DEVBUG SERVER
|
||||
// TODO: REMOVE BEFORE COMMITTING
|
||||
let outs = {}
|
||||
let devbug_url = 'http://localhost:8000/'
|
||||
let project_api_key = 'CHANGEME'
|
||||
const out = (key, what, group="") => {
|
||||
if ( group ){
|
||||
if ( Object.keys(outs).includes(group) ) outs[group][key] = what
|
||||
else outs[group] = {}; outs[group][key] = what
|
||||
}
|
||||
else {
|
||||
outs[key] = what
|
||||
}
|
||||
}
|
||||
const breakpoint = (html = false, name = null) => {
|
||||
var e = new Error();
|
||||
(function() {
|
||||
// Load better json
|
||||
var js_decycle = document.createElement("script");
|
||||
js_decycle.src = devbug_url+"assets/cycle.js";
|
||||
js_decycle.type = 'text/javascript';
|
||||
js_decycle.onload = () => {
|
||||
// Load the script
|
||||
var script = document.createElement("script");
|
||||
script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js';
|
||||
script.type = 'text/javascript';
|
||||
script.onload = () => {
|
||||
var $ = window.jQuery;
|
||||
$(() => {
|
||||
var s = e.stack.split('at'); var caller = '';
|
||||
if ( s.length < 3 ) s = e.stack.split('@')
|
||||
if ( s.length > 2 ) caller = s[2].trim()
|
||||
else if ( s.length > 1 ) caller = s[1]
|
||||
else caller = 'Unable to determine stacktrace'
|
||||
var data = new FormData();
|
||||
console.log(JSON.decycle({brief: (name ? name : 'Breakpoint: ')+caller,data: outs}))
|
||||
data.append('data', JSON.stringify(JSON.rmref(JSON.decycle({brief: (name ? name : 'Breakpoint: ')+caller,data: outs}))))
|
||||
$.ajax({
|
||||
url: devbug_url+'api/v1/out/'+project_api_key,
|
||||
data: data, cache: false, contentType: false, processData: false, method: 'POST', type: 'POST',
|
||||
success: (res) => { console.log('DevBug POST Completed'); console.log(res) }
|
||||
})
|
||||
});
|
||||
};
|
||||
document.getElementsByTagName("head")[0].appendChild(script);
|
||||
}
|
||||
document.getElementsByTagName("head")[0].appendChild(js_decycle);
|
||||
})();
|
||||
}
|
||||
window.out = out; window.breakpoint = breakpoint;
|
||||
// ===========================================================
|
118
app/assets/cycle.js
Normal file
118
app/assets/cycle.js
Normal file
@ -0,0 +1,118 @@
|
||||
if (typeof JSON.rmref !== "function") {
|
||||
JSON.rmref = function rmref(o){
|
||||
function eachRecursive(obj) {
|
||||
for (var k in obj)
|
||||
{
|
||||
if (typeof obj[k] == "object" && obj[k] !== null)
|
||||
eachRecursive(obj[k]);
|
||||
else {
|
||||
for ( var key in obj ){
|
||||
if ( key === "$ref" ){
|
||||
obj[k] = "cyclic structure removed";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
eachRecursive(o)
|
||||
return o
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof JSON.decycle !== "function") {
|
||||
JSON.decycle = function decycle(object, replacer) {
|
||||
"use strict";
|
||||
|
||||
var objects = new WeakMap(); // object to path mappings
|
||||
|
||||
return (function derez(value, path) {
|
||||
|
||||
var old_path; // The path of an earlier occurance of value
|
||||
var nu; // The new object or array
|
||||
|
||||
if (replacer !== undefined) {
|
||||
value = replacer(value);
|
||||
}
|
||||
|
||||
if (
|
||||
typeof value === "object"
|
||||
&& value !== null
|
||||
&& !(value instanceof Boolean)
|
||||
&& !(value instanceof Date)
|
||||
&& !(value instanceof Number)
|
||||
&& !(value instanceof RegExp)
|
||||
&& !(value instanceof String)
|
||||
) {
|
||||
|
||||
|
||||
old_path = objects.get(value);
|
||||
if (old_path !== undefined) {
|
||||
return {$ref: old_path};
|
||||
}
|
||||
|
||||
|
||||
objects.set(value, path);
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
nu = [];
|
||||
value.forEach(function (element, i) {
|
||||
nu[i] = derez(element, path + "[" + i + "]");
|
||||
});
|
||||
} else {
|
||||
|
||||
nu = {};
|
||||
Object.keys(value).forEach(function (name) {
|
||||
nu[name] = derez(
|
||||
value[name],
|
||||
path + "[" + JSON.stringify(name) + "]"
|
||||
);
|
||||
});
|
||||
}
|
||||
return nu;
|
||||
}
|
||||
return value;
|
||||
}(object, "$"));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
if (typeof JSON.retrocycle !== "function") {
|
||||
JSON.retrocycle = function retrocycle($) {
|
||||
"use strict";
|
||||
|
||||
var px = /^\$(?:\[(?:\d+|"(?:[^\\"\u0000-\u001f]|\\(?:[\\"\/bfnrt]|u[0-9a-zA-Z]{4}))*")\])*$/;
|
||||
|
||||
(function rez(value) {
|
||||
|
||||
|
||||
if (value && typeof value === "object") {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach(function (element, i) {
|
||||
if (typeof element === "object" && element !== null) {
|
||||
var path = element.$ref;
|
||||
if (typeof path === "string" && px.test(path)) {
|
||||
value[i] = eval(path);
|
||||
} else {
|
||||
rez(element);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Object.keys(value).forEach(function (name) {
|
||||
var item = value[name];
|
||||
if (typeof item === "object" && item !== null) {
|
||||
var path = item.$ref;
|
||||
if (typeof path === "string" && px.test(path)) {
|
||||
value[name] = eval(path);
|
||||
} else {
|
||||
rez(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}($));
|
||||
return $;
|
||||
};
|
||||
}
|
@ -3,6 +3,7 @@ function output(inp) {
|
||||
}
|
||||
|
||||
function syntaxHighlight(json) {
|
||||
console.log(json)
|
||||
json = JSON.stringify(JSON.parse(json.replace(/"/g, '"')), undefined, 4)
|
||||
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
|
||||
|
@ -15,15 +15,26 @@ class v1 {
|
||||
|
||||
const projects = await Project.find({ archived: false, user_id: req.session.auth.uuid })
|
||||
|
||||
let find = {
|
||||
let view_find = {
|
||||
shared_user_ids: {
|
||||
$elemMatch: {
|
||||
$eq: req.session.auth.uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let edit_find = {
|
||||
edit_user_ids: {
|
||||
$elemMatch: {
|
||||
$eq: req.session.auth.uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const shared_projects = await Project.find(find)
|
||||
const shared_projects = {
|
||||
view: await Project.find(view_find),
|
||||
edit: await Project.find(edit_find),
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the main view.
|
||||
@ -45,7 +56,7 @@ class v1 {
|
||||
}
|
||||
|
||||
// check access perms
|
||||
if ( !(project.user_id === req.session.auth.uuid) ){
|
||||
if ( !devbug.permission.project.edit(project, req.session.auth.user) ){
|
||||
return _flitter.error(res, 401, {reason: 'You do not have permissions to edit this project.'})
|
||||
}
|
||||
|
||||
@ -63,8 +74,8 @@ class v1 {
|
||||
}
|
||||
|
||||
// check access perms
|
||||
if ( !(project.user_id === req.session.auth.uuid) ){
|
||||
return _flitter.error(res, 401, {reason: 'Project not found with the specified ID.'})
|
||||
if ( !devbug.permission.project.edit(project, req.session.auth.user) ){
|
||||
return _flitter.error(res, 401, {reason: 'You do not have permissions to edit this project.'})
|
||||
}
|
||||
|
||||
project.name = req.body.name
|
||||
@ -102,7 +113,7 @@ class v1 {
|
||||
|
||||
const outs = await Out.find({ project_id: project.id }).sort('-created')
|
||||
|
||||
if ( !(project.user_id === req.session.auth.uuid) && !(project.shared_user_ids.includes(req.session.auth.uuid)) ){
|
||||
if ( !devbug.permission.project.view(project, req.session.auth.user) ){
|
||||
return _flitter.error(res, 401, {reason: 'You do not have permission to view this project.'})
|
||||
}
|
||||
|
||||
@ -119,6 +130,7 @@ class v1 {
|
||||
let pretty
|
||||
try {
|
||||
pretty = JSON.stringify(JSON.parse(out.data), null, 4)
|
||||
console.log('Pretty out: ', pretty)
|
||||
}
|
||||
catch (e){
|
||||
return _flitter.error(res, 500, {reason: 'Unable to parse output data. Data contains invalid JSON.'})
|
||||
@ -126,11 +138,10 @@ class v1 {
|
||||
|
||||
const project = await Project.findById(out.project_id)
|
||||
|
||||
if ( !project || (!(project.user_id === req.session.auth.uuid) && !(project.shared_user_ids.includes(req.session.auth.uuid))) ){
|
||||
if ( !project || (!devbug.permission.project.view(project, req.session.auth.user)) ){
|
||||
return _flitter.error(res, 401, {reason: 'You do not have permission to view this project.'})
|
||||
}
|
||||
|
||||
// TODO permission access check
|
||||
return _flitter.view(res, 'dash_v1:out', {project, user: req.session.auth.user, out, prettyd:pretty, show_back: true, title: out.brief, title_small: true });
|
||||
}
|
||||
|
||||
@ -138,7 +149,7 @@ class v1 {
|
||||
const out = await Out.findById(req.params.id)
|
||||
|
||||
const project = await Project.findById(req.params.project)
|
||||
if ( !project || ( !(project.user_id === req.session.auth.uuid) ) ){
|
||||
if ( !project || ( !devbug.permission.project.edit(project, req.session.auth.user) ) ){
|
||||
return _flitter.error(res, 401, {reason: 'You do not have permission to edit this project.'})
|
||||
}
|
||||
|
||||
@ -155,7 +166,7 @@ class v1 {
|
||||
return _flitter.error(res, 404, {reason: 'Project not found with the specified ID.'})
|
||||
}
|
||||
|
||||
if ( !(project.user_id === req.session.auth.uuid) ){
|
||||
if ( !devbug.permission.project.owns(project, req.session.auth.user) ){
|
||||
return _flitter.error(res, 401, {reason: 'You do not have permission to edit this project.'})
|
||||
}
|
||||
|
||||
@ -165,7 +176,7 @@ class v1 {
|
||||
async project_delete_do(req, res, next){
|
||||
const project = await Project.findById(req.params.id)
|
||||
|
||||
if ( project && ( !(project.user_id === req.session.auth.uuid) ) ){
|
||||
if ( project && ( !devbug.permission.project.owns(project, req.session.auth.user) ) ){
|
||||
return _flitter.error(res, 401, {reason: 'You do not have permission to edit this project.'})
|
||||
}
|
||||
|
||||
@ -191,24 +202,44 @@ class v1 {
|
||||
|
||||
if ( !project ) return _flitter.error(res, 404, {reason: 'Project not found with the specified ID.'})
|
||||
|
||||
if ( !(project.user_id === req.session.auth.uuid) ) return _flitter.error(res, 401, {reason: 'You do not have permission to edit this project.'})
|
||||
if ( !devbug.permission.project.owns(project, req.session.auth.user) ) return _flitter.error(res, 401, {reason: 'You do not have permission to edit this project.'})
|
||||
|
||||
let find = {
|
||||
uuid: { $nin: [] }
|
||||
// Find read-only users
|
||||
const read_find = {
|
||||
uuid: { $in: [] }
|
||||
}
|
||||
read_find.uuid.$in = read_find.uuid.$in.concat(project.shared_user_ids)
|
||||
|
||||
const read = await _flitter.model('User').find(read_find)
|
||||
|
||||
// Find edit users
|
||||
const edit_find = {
|
||||
uuid: { $in : [] }
|
||||
}
|
||||
edit_find.uuid.$in = edit_find.uuid.$in.concat(project.edit_user_ids)
|
||||
|
||||
const edit = await _flitter.model('User').find(edit_find)
|
||||
|
||||
// Find other users
|
||||
const other_find = {
|
||||
uuid: { $nin: [ project.user_id ] }
|
||||
}
|
||||
other_find.uuid.$nin = other_find.uuid.$nin.concat(project.edit_user_ids).concat(project.shared_user_ids)
|
||||
|
||||
const other = await _flitter.model('User').find(other_find)
|
||||
|
||||
// Get the owner user
|
||||
const owner = await _flitter.model('User').findOne({ uuid: project.user_id })
|
||||
|
||||
const sharing = {
|
||||
read,
|
||||
edit,
|
||||
other,
|
||||
owner,
|
||||
current_owns: (project.user_id === req.session.auth.uuid)
|
||||
}
|
||||
|
||||
find.uuid.$nin.push(req.session.auth.uuid)
|
||||
find.uuid.$nin = find.uuid.$nin.concat(project.shared_user_ids)
|
||||
|
||||
const to_share = await _flitter.model('User').find(find)
|
||||
|
||||
find = {
|
||||
uuid: { $in: find.uuid.$nin }
|
||||
}
|
||||
|
||||
const shared = await _flitter.model('User').find(find)
|
||||
|
||||
return _flitter.view(res, 'dash_v1:share', { user: req.session.auth.user, sharing: { to_share, shared }, project, title: 'Share Project: '+project.name, show_back: true })
|
||||
return _flitter.view(res, 'dash_v1:share', { user: req.session.auth.user, sharing, project, title: 'Share Project: '+project.name, show_back: true })
|
||||
}
|
||||
|
||||
async project_share_do(req, res, next){
|
||||
@ -218,7 +249,7 @@ class v1 {
|
||||
const target_user = await _flitter.model('User').findOne({uuid: req.params.user})
|
||||
if ( !target_user ) return _flitter.error(res, 404, {reason: 'User not found with the specified ID.'})
|
||||
|
||||
if ( !(project.user_id === req.session.auth.uuid) ) return _flitter.error(res, 401, {reason: "You do not have permission to edit this project."})
|
||||
if ( !devbug.permission.project.owns(project, req.session.auth.user) ) return _flitter.error(res, 401, {reason: "You do not have permission to edit this project."})
|
||||
|
||||
if ( !(project.user_id === target_user.uuid) && !(project.shared_user_ids.includes(target_user.uuid)) ){
|
||||
project.shared_user_ids.push(target_user.uuid)
|
||||
@ -227,6 +258,28 @@ class v1 {
|
||||
|
||||
return res.redirect('/dash/v1/project/share/'+project.id)
|
||||
}
|
||||
|
||||
async project_share_edit_do(req, res, next){
|
||||
const project = await Project.findById(req.params.id)
|
||||
if ( !project ) return _flitter.error(res, 404, {reason: 'Project not found with the specified ID.'})
|
||||
|
||||
const target_user = await _flitter.model('User').findOne({uuid: req.params.user})
|
||||
if ( !target_user ) return _flitter.error(res, 404, {reason: 'User not found with the specified ID.'})
|
||||
|
||||
if ( !devbug.permission.project.owns(project, req.session.auth.user) ) return _flitter.error(res, 401, {reason: "You do not have permission to edit this project."})
|
||||
|
||||
if ( !(project.user_id === target_user.uuid) && !(project.edit_user_ids.includes(target_user.uuid)) ){
|
||||
// check if read access. If so, revoke.
|
||||
if ( project.shared_user_ids.includes(target_user.uuid) ){
|
||||
project.shared_user_ids.splice(project.shared_user_ids.indexOf(target_user.uuid), 1)
|
||||
}
|
||||
|
||||
project.edit_user_ids.push(target_user.uuid)
|
||||
await project.save()
|
||||
}
|
||||
|
||||
return res.redirect('/dash/v1/project/share/'+project.id)
|
||||
}
|
||||
|
||||
async project_share_revoke(req, res, next){
|
||||
const project = await Project.findById(req.params.id)
|
||||
@ -235,7 +288,7 @@ class v1 {
|
||||
const target_user = await _flitter.model('User').findOne({uuid: req.params.user})
|
||||
if ( !target_user ) return _flitter.error(res, 404, {reason: 'User not found with the specified ID.'})
|
||||
|
||||
if ( !(project.user_id === req.session.auth.uuid || project.shared_user_ids.includes(req.session.auth.uuid)) ) return _flitter.error(res, 401, {reason: "You do not have permission to edit this project."})
|
||||
if ( !devbug.permission.project.view(project, req.session.auth.user) ) return _flitter.error(res, 401, {reason: "You do not have permission to edit this project."})
|
||||
|
||||
const to_dash = project.shared_user_ids.includes(req.session.auth.uuid)
|
||||
|
||||
@ -248,6 +301,27 @@ class v1 {
|
||||
|
||||
return res.redirect('/dash/v1/project/share/'+project.id)
|
||||
}
|
||||
|
||||
async project_share_revoke_edit(req, res, next){
|
||||
const project = await Project.findById(req.params.id)
|
||||
if ( !project ) return _flitter.error(res, 404, {reason: 'Project not found with the specified ID.'})
|
||||
|
||||
const target_user = await _flitter.model('User').findOne({uuid: req.params.user})
|
||||
if ( !target_user ) return _flitter.error(res, 404, {reason: 'User not found with the specified ID.'})
|
||||
|
||||
if ( !devbug.permission.project.view(project, req.session.auth.user) ) return _flitter.error(res, 401, {reason: "You do not have permission to edit this project."})
|
||||
|
||||
const to_dash = project.edit_user_ids.includes(req.session.auth.uuid)
|
||||
|
||||
if ( !(target_user.uuid === project.user_id) && (project.edit_user_ids.includes(target_user.uuid)) ){
|
||||
project.edit_user_ids.splice(project.edit_user_ids.indexOf(target_user.uuid), 1)
|
||||
await project.save()
|
||||
}
|
||||
|
||||
if ( to_dash ) return res.redirect('/dash/v1')
|
||||
|
||||
return res.redirect('/dash/v1/project/share/'+project.id)
|
||||
}
|
||||
|
||||
async project_share_transfer(req, res, next){
|
||||
const project = await Project.findById(req.params.id)
|
||||
@ -256,14 +330,18 @@ class v1 {
|
||||
const target_user = await _flitter.model('User').findOne({uuid: req.params.user})
|
||||
if ( !target_user ) return _flitter.error(res, 404, {reason: 'User not found with the specified ID.'})
|
||||
|
||||
if ( !project.user_id === req.session.auth.uuid ) return _flitter.error(res, 401, {reason: 'You do not have permission to edit this project.'})
|
||||
if ( !devbug.permission.project.owns(project, req.session.auth.user) ) return _flitter.error(res, 401, {reason: 'You do not have permission to edit this project.'})
|
||||
|
||||
project.user_id = target_user.uuid
|
||||
project.shared_user_ids.push(req.session.auth.uuid)
|
||||
|
||||
if ( project.shared_user_ids.includes(req.session.auth.uuid) ){
|
||||
if ( project.shared_user_ids.includes(target_user.uuid) ){
|
||||
project.shared_user_ids.splice(project.shared_user_ids.indexOf(target_user.uuid), 1)
|
||||
}
|
||||
|
||||
if ( project.edit_user_ids.includes(target_user.uuid) ){
|
||||
project.edit_user_ids.splice(project.edit_user_ids.indexOf(target_user.uuid), 1)
|
||||
}
|
||||
|
||||
await project.save()
|
||||
|
||||
@ -274,7 +352,7 @@ class v1 {
|
||||
const project = await Project.findById(req.params.id)
|
||||
if ( !project ) return _flitter.error(res, 404, {reason: 'Project not found with the specified ID.'})
|
||||
|
||||
if ( !project.user_id === req.session.auth.uuid ) return _flitter.error(res, 401, {reason: 'You do not have permission to edit this project.'})
|
||||
if ( !devbug.permission.project.owns(project, req.session.auth.user) ) return _flitter.error(res, 401, {reason: 'You do not have permission to edit this project.'})
|
||||
|
||||
let share_data = {
|
||||
project_id: project.id,
|
||||
|
@ -10,6 +10,7 @@ const Project = {
|
||||
archived: { type: Boolean, default: false },
|
||||
data: String,
|
||||
shared_user_ids: [String],
|
||||
edit_user_ids: [String],
|
||||
uuid: { type: String, default: uuid }
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,9 @@ const v1 = {
|
||||
'/project/edit/:id': [ _flitter.controller('dash:v1').project_edit_show ],
|
||||
'/project/share/:id': [ _flitter.controller('dash:v1').project_share_show ],
|
||||
'/project/share/:id/share/:user': [ _flitter.controller('dash:v1').project_share_do ],
|
||||
'/project/share/:id/share/:user/edit': [ _flitter.controller('dash:v1').project_share_edit_do ],
|
||||
'/project/share/:id/revoke/:user': [ _flitter.controller('dash:v1').project_share_revoke ],
|
||||
'/project/share/:id/revoke/:user/edit': [ _flitter.controller('dash:v1').project_share_revoke_edit ],
|
||||
'/project/share/:id/transfer/:user': [ _flitter.controller('dash:v1').project_share_transfer ],
|
||||
'/project/share/:id/invite': [ _flitter.controller('dash:v1').project_share_invite ],
|
||||
|
||||
|
@ -17,11 +17,8 @@ block content
|
||||
| function.
|
||||
pre
|
||||
code #{devbug.code.php}
|
||||
h2 JavaScript (Web)
|
||||
p
|
||||
| This snippet works by loading jQuery via a script tag when a breakpoint is triggered.
|
||||
pre
|
||||
code #{devbug.code.js}
|
||||
h2
|
||||
a(href="/assets/agents/web.js" target="_blank") JavaScript (Web)
|
||||
h2 Using the API
|
||||
p You can post output to DevBug projects from anywhere using the DevBug API. Here's how:
|
||||
pre
|
||||
|
@ -24,7 +24,7 @@ block content
|
||||
li
|
||||
a.action(href='/dash/v1/project/edit/'+project.id) Edit
|
||||
|
||||
if shared_projects
|
||||
if shared_projects.view || shared_projects.edit
|
||||
h3 Projects Shared With Me
|
||||
table
|
||||
thead
|
||||
@ -32,7 +32,18 @@ block content
|
||||
th(scope='col' style='min-width: 250px') Name
|
||||
th(scope='col') Actions
|
||||
tbody
|
||||
each project in shared_projects
|
||||
each project in shared_projects.edit
|
||||
tr
|
||||
td #{project.name}
|
||||
td
|
||||
ul(style='list-style-type: none; margin: 0; padding: 0;')
|
||||
li
|
||||
a.action(href='/dash/v1/project/view/'+project.id) View
|
||||
li
|
||||
a.action(href='/dash/v1/project/share/'+project.id+'/revoke/'+user.uuid+'/edit') Remove
|
||||
li
|
||||
a.action(href='/dash/v1/project/edit/'+project.id) Edit
|
||||
each project in shared_projects.view
|
||||
tr
|
||||
td #{project.name}
|
||||
td
|
||||
|
@ -1,48 +1,88 @@
|
||||
extends ./template
|
||||
block content
|
||||
h2 Shared With
|
||||
h2 Owned By
|
||||
table
|
||||
thead
|
||||
tr
|
||||
th(scope='col' style='min-width: 250px') Username
|
||||
th(scope='col') Actions
|
||||
tbody
|
||||
each user in sharing.shared
|
||||
tr
|
||||
td #{(sharing.current_owns ? `You (${sharing.owner.username})` : sharing.owner.username)}
|
||||
|
||||
if sharing.read.length > 0
|
||||
br
|
||||
h2 Shared With (Read-Only)
|
||||
table
|
||||
thead
|
||||
tr
|
||||
td #{(user.uuid === project.user_id ? user.username + " (Owner)" : user.username)}
|
||||
td
|
||||
ul(style='list-style-type: none; margin: 0; padding: 0;')
|
||||
if !(user.uuid === project.user_id)
|
||||
li
|
||||
a.action(href='/dash/v1/project/share/'+project.id+'/revoke/'+user.uuid) Revoke
|
||||
li
|
||||
a.action(href='/dash/v1/project/share/'+project.id+'/transfer/'+user.uuid) Transfer Ownership
|
||||
else
|
||||
li
|
||||
strike Revoke
|
||||
li
|
||||
strike Transfer Ownership
|
||||
th(scope='col' style='min-width: 250px') Username
|
||||
th(scope='col') Actions
|
||||
tbody
|
||||
each user in sharing.read
|
||||
tr
|
||||
td #{(user.uuid === project.user_id ? user.username + " (Owner)" : user.username)}
|
||||
td
|
||||
ul(style='list-style-type: none; margin: 0; padding: 0;')
|
||||
if !(user.uuid === project.user_id)
|
||||
li
|
||||
a.action(href='/dash/v1/project/share/'+project.id+'/revoke/'+user.uuid) Revoke
|
||||
li
|
||||
a.action(href='/dash/v1/project/share/'+project.id+'/transfer/'+user.uuid) Transfer Ownership
|
||||
else
|
||||
li
|
||||
strike Revoke
|
||||
li
|
||||
strike Transfer Ownership
|
||||
|
||||
if sharing.edit.length > 0
|
||||
br
|
||||
h2 Shared With (Edit)
|
||||
table
|
||||
thead
|
||||
tr
|
||||
th(scope='col' style='min-width: 250px') Username
|
||||
th(scope='col') Actions
|
||||
tbody
|
||||
each user in sharing.edit
|
||||
tr
|
||||
td #{(user.uuid === project.user_id ? user.username + " (Owner)" : user.username)}
|
||||
td
|
||||
ul(style='list-style-type: none; margin: 0; padding: 0;')
|
||||
if !(user.uuid === project.user_id)
|
||||
li
|
||||
a.action(href='/dash/v1/project/share/'+project.id+'/revoke/'+user.uuid+'/edit') Revoke
|
||||
li
|
||||
a.action(href='/dash/v1/project/share/'+project.id+'/transfer/'+user.uuid) Transfer Ownership
|
||||
else
|
||||
li
|
||||
strike Revoke
|
||||
li
|
||||
strike Transfer Ownership
|
||||
br
|
||||
h2 Share With New User
|
||||
a.btn(href='/dash/v1/project/share/'+project.id+'/invite') Generate Sharing Link
|
||||
br
|
||||
br
|
||||
table
|
||||
thead
|
||||
tr
|
||||
th(scope='col' style='min-width: 250px') Username
|
||||
th(scope='col') Actions
|
||||
tbody
|
||||
each user in sharing.to_share
|
||||
|
||||
if sharing.other.length > 0
|
||||
br
|
||||
br
|
||||
table
|
||||
thead
|
||||
tr
|
||||
td #{(user.uuid === project.user_id ? user.username + " (Owner)" : user.username)}
|
||||
td
|
||||
ul(style='list-style-type: none; margin: 0; padding: 0;')
|
||||
if !(user.uuid === project.user_id)
|
||||
th(scope='col' style='min-width: 250px') Username
|
||||
th(scope='col') Actions
|
||||
tbody
|
||||
each user in sharing.other
|
||||
tr
|
||||
td #{(user.uuid === project.user_id ? user.username + " (Owner)" : user.username)}
|
||||
td
|
||||
ul(style='list-style-type: none; margin: 0; padding: 0;')
|
||||
if !(user.uuid === project.user_id)
|
||||
li
|
||||
a.action(href='/dash/v1/project/share/' + project.id + '/share/'+user.uuid) Share (View)
|
||||
li
|
||||
a.action(href='/dash/v1/project/share/' + project.id + '/share/'+user.uuid+'/edit') Share (Edit)
|
||||
else
|
||||
li
|
||||
strike Share
|
||||
li
|
||||
a.action(href='/dash/v1/project/share/' + project.id + '/share/'+user.uuid) Share
|
||||
else
|
||||
li
|
||||
strike Share
|
||||
li
|
||||
a.action(href='/dash/v1/project/share/' + project.id + '/transfer/' + user.uuid) Transfer Ownership
|
||||
a.action(href='/dash/v1/project/share/' + project.id + '/transfer/' + user.uuid) Transfer Ownership
|
||||
|
@ -16,5 +16,6 @@ block content
|
||||
ul(style='list-style-type: none; margin: 0; padding: 0;')
|
||||
li
|
||||
a.action(href='/dash/v1/out/view/'+out.id) View
|
||||
li
|
||||
a.action(href='/dash/v1/out/delete/'+out.id+'/'+project.id) Delete
|
||||
if ( devbug.permission.project.edit(project, user) )
|
||||
li
|
||||
a.action(href='/dash/v1/out/delete/'+out.id+'/'+project.id) Delete
|
||||
|
Loading…
Reference in New Issue
Block a user