remove old models; update README
This commit is contained in:
parent
012a76ee1f
commit
4012ee0c1c
13
README.md
13
README.md
@ -35,7 +35,9 @@ It also has some optional binary dependencies for advanced media conversion:
|
|||||||
|
|
||||||
By default, media files are uploaded to the ```storage``` folder.
|
By default, media files are uploaded to the ```storage``` folder.
|
||||||
|
|
||||||
To run Spacedeck, you only need Node.JS 9.x. Then, to install all node dependencies, run
|
To use Spacedeck, you only need Node.JS 9.x.
|
||||||
|
|
||||||
|
Then, to install all node dependencies, run
|
||||||
|
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
@ -47,13 +49,16 @@ To rebuild the frontend CSS styles (you need to do this at least once):
|
|||||||
|
|
||||||
See [config/default.json](config/default.json)
|
See [config/default.json](config/default.json)
|
||||||
|
|
||||||
# Run
|
# Run (web server)
|
||||||
|
|
||||||
export NODE_ENV=development
|
node spacedeck.js
|
||||||
npm start
|
|
||||||
|
|
||||||
Then open http://localhost:9666 in a web browser.
|
Then open http://localhost:9666 in a web browser.
|
||||||
|
|
||||||
|
# Run (desktop app with integrated web server)
|
||||||
|
|
||||||
|
electron .
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
The Spacedeck logo and brand assets are registered trademarks of Spacedeck GmbH. All rights reserved.
|
The Spacedeck logo and brand assets are registered trademarks of Spacedeck GmbH. All rights reserved.
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
// FIXME port this last model
|
||||||
|
|
||||||
var mongoose = require('mongoose');
|
var mongoose = require('mongoose');
|
||||||
var Schema = mongoose.Schema;
|
var Schema = mongoose.Schema;
|
||||||
|
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
var mongoose = require('mongoose');
|
|
||||||
var Schema = mongoose.Schema;
|
|
||||||
|
|
||||||
module.exports.artifactSchema = Schema({
|
|
||||||
mime: String,
|
|
||||||
thumbnail_uri: String,
|
|
||||||
space_id: Schema.Types.ObjectId,
|
|
||||||
user_id: {type: Schema.Types.ObjectId, ref: 'User' },
|
|
||||||
last_update_user_id: {type: Schema.Types.ObjectId, ref: 'User' },
|
|
||||||
editor_name: String,
|
|
||||||
last_update_editor_name: String,
|
|
||||||
description: String,
|
|
||||||
state: {type: String, default: "idle"},
|
|
||||||
meta: {
|
|
||||||
linked_to: [String],
|
|
||||||
title: String,
|
|
||||||
tags: [String],
|
|
||||||
search_text: String,
|
|
||||||
link_uri: String,
|
|
||||||
play_from: Number,
|
|
||||||
play_to: Number,
|
|
||||||
},
|
|
||||||
board: {
|
|
||||||
x: {type: Number, default: 0.0},
|
|
||||||
y: {type: Number, default: 0.0},
|
|
||||||
z: {type: Number, default: 0.0},
|
|
||||||
r: {type: Number, default: 0.0},
|
|
||||||
w: {type: Number, default: 100},
|
|
||||||
h: {type: Number, default: 100},
|
|
||||||
},
|
|
||||||
control_points: [{
|
|
||||||
dx: Number, dy: Number
|
|
||||||
}],
|
|
||||||
group:{type: String, default: ""},
|
|
||||||
locked: {type: Boolean, default: false},
|
|
||||||
payload_uri: String,
|
|
||||||
payload_thumbnail_web_uri: String,
|
|
||||||
payload_thumbnail_medium_uri: String,
|
|
||||||
payload_thumbnail_big_uri: String,
|
|
||||||
payload_size: Number, // file size in bytes
|
|
||||||
style: {
|
|
||||||
fill_color: {type: String, default: "transparent"},
|
|
||||||
stroke_color:{type: String, default: "#000000"},
|
|
||||||
text_color: String,
|
|
||||||
stroke: {type: Number, default: 0.0},
|
|
||||||
stroke_style: {type: String, default: "solid"},
|
|
||||||
alpha: {type: Number, default: 1.0},
|
|
||||||
order: {type: Number, default: 0},
|
|
||||||
crop: {
|
|
||||||
x: Number,
|
|
||||||
y: Number,
|
|
||||||
w: Number,
|
|
||||||
h: Number
|
|
||||||
},
|
|
||||||
shape: String,
|
|
||||||
shape_svg: String,
|
|
||||||
padding_left: Number,
|
|
||||||
padding_right: Number,
|
|
||||||
padding_top: Number,
|
|
||||||
padding_bottom: Number,
|
|
||||||
margin_left: Number,
|
|
||||||
margin_right: Number,
|
|
||||||
margin_top: Number,
|
|
||||||
margin_bottom: Number,
|
|
||||||
border_radius: Number,
|
|
||||||
align: {type: String, default: "left"},
|
|
||||||
valign: {type: String, default: "top"},
|
|
||||||
brightness: Number,
|
|
||||||
contrast: Number,
|
|
||||||
saturation: Number,
|
|
||||||
blur: Number,
|
|
||||||
hue: Number,
|
|
||||||
opacity: Number
|
|
||||||
},
|
|
||||||
payload_alternatives: [{
|
|
||||||
mime: String,
|
|
||||||
payload_uri: String,
|
|
||||||
payload_thumbnail_web_uri: String,
|
|
||||||
payload_thumbnail_medium_uri: String,
|
|
||||||
payload_thumbnail_big_uri: String,
|
|
||||||
payload_size: Number
|
|
||||||
}],
|
|
||||||
created_at: {type: Date, default: Date.now},
|
|
||||||
created_from_ip: {type: String},
|
|
||||||
updated_at: {type: Date, default: Date.now}
|
|
||||||
});
|
|
@ -1,45 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
var mongoose = require('mongoose');
|
|
||||||
var Schema = mongoose.Schema;
|
|
||||||
|
|
||||||
module.exports.membershipSchema = mongoose.Schema({
|
|
||||||
user: {
|
|
||||||
type: Schema.Types.ObjectId,
|
|
||||||
ref: 'User'
|
|
||||||
},
|
|
||||||
space: {
|
|
||||||
type: Schema.Types.ObjectId,
|
|
||||||
ref: 'Space'
|
|
||||||
},
|
|
||||||
team: {
|
|
||||||
type: Schema.Types.ObjectId,
|
|
||||||
ref: 'Team'
|
|
||||||
},
|
|
||||||
role: {
|
|
||||||
type: String,
|
|
||||||
default: "viewer"
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
type: String,
|
|
||||||
default: "active"
|
|
||||||
},
|
|
||||||
email_invited: String,
|
|
||||||
code: String,
|
|
||||||
created_at: {
|
|
||||||
type: Date,
|
|
||||||
default: Date.now
|
|
||||||
},
|
|
||||||
updated_at: {
|
|
||||||
type: Date,
|
|
||||||
default: Date.now
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports.membershipSchema.index({
|
|
||||||
user: 1,
|
|
||||||
space: 1,
|
|
||||||
team: 1,
|
|
||||||
code: 1
|
|
||||||
});
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
var mongoose = require('mongoose');
|
|
||||||
var Schema = mongoose.Schema;
|
|
||||||
|
|
||||||
module.exports.messageSchema = mongoose.Schema({
|
|
||||||
user: {
|
|
||||||
type: Schema.Types.ObjectId,
|
|
||||||
ref: 'User'
|
|
||||||
},
|
|
||||||
editor_name: String,
|
|
||||||
space: {
|
|
||||||
type: Schema.Types.ObjectId,
|
|
||||||
ref: 'Space'
|
|
||||||
},
|
|
||||||
message: String,
|
|
||||||
created_from_ip: {type: String},
|
|
||||||
created_at: {
|
|
||||||
type: Date,
|
|
||||||
default: Date.now
|
|
||||||
},
|
|
||||||
updated_at: {
|
|
||||||
type: Date,
|
|
||||||
default: Date.now
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports.messageSchema.index({
|
|
||||||
space: 1,
|
|
||||||
user: 1
|
|
||||||
});
|
|
273
models/space.js
273
models/space.js
@ -1,273 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
var mongoose = require('mongoose');
|
|
||||||
var Schema = mongoose.Schema;
|
|
||||||
var async = require('async');
|
|
||||||
var _ = require("underscore");
|
|
||||||
var crypto = require('crypto');
|
|
||||||
|
|
||||||
module.exports.spaceSchema = Schema({
|
|
||||||
name: {type: String, default: "New Space"},
|
|
||||||
space_type: {type: String, default: "space"},
|
|
||||||
|
|
||||||
creator : { type: Schema.Types.ObjectId, ref: 'User' },
|
|
||||||
parent_space_id: Schema.Types.ObjectId,
|
|
||||||
|
|
||||||
access_mode: {type: String, default: "private"}, // "public" || "private"
|
|
||||||
password: String,
|
|
||||||
edit_hash: String,
|
|
||||||
edit_slug: String,
|
|
||||||
editors_locking: Boolean,
|
|
||||||
|
|
||||||
thumbnail_uri: String,
|
|
||||||
stats: {
|
|
||||||
num_children: Number,
|
|
||||||
total_spaces: Number,
|
|
||||||
total_folders: Number,
|
|
||||||
storage_bytes: Number,
|
|
||||||
},
|
|
||||||
|
|
||||||
advanced: {
|
|
||||||
type: {
|
|
||||||
width: Number,
|
|
||||||
height: Number,
|
|
||||||
margin: Number,
|
|
||||||
background_color: String,
|
|
||||||
background_uri: String,
|
|
||||||
background_repeat: Boolean,
|
|
||||||
grid_size: Number,
|
|
||||||
grid_divisions: Number,
|
|
||||||
gutter: Number,
|
|
||||||
columns: Number,
|
|
||||||
column_max_width: Number,
|
|
||||||
columns_responsive: Number,
|
|
||||||
row_max_height: Number,
|
|
||||||
padding_horz: Number,
|
|
||||||
padding_vert: Number
|
|
||||||
},
|
|
||||||
default: {
|
|
||||||
width: 200,
|
|
||||||
height: 400,
|
|
||||||
margin: 0,
|
|
||||||
background_color: "rgba(255,255,255,1)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
blocked_at: {type: Date, default: Date.now},
|
|
||||||
created_at: {type: Date, default: Date.now},
|
|
||||||
updated_at: {type: Date, default: Date.now},
|
|
||||||
thumbnail_updated_at: {type: Date},
|
|
||||||
thumbnail_url: String
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports.spaceSchema.index({ creator: 1, parent_space_id: 1, created_at: 1, updated_at: 1, edit_hash: 1});
|
|
||||||
module.exports.spaceSchema.statics.allForUser = function (user, callback) {
|
|
||||||
return this.find({user_id: user_id}, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports.spaceSchema.statics.getMemberships = function (err, callback) {
|
|
||||||
callback(null, {});
|
|
||||||
};
|
|
||||||
|
|
||||||
var getRecursiveSubspacesForSpace = (parentSpace, cb) => {
|
|
||||||
if (parentSpace.space_type == "folder") {
|
|
||||||
Space.find({
|
|
||||||
"parent_space_id": parentSpace._id
|
|
||||||
}).exec((err, subspaces) => {
|
|
||||||
async.map(subspaces, (space, innerCb) => {
|
|
||||||
getRecursiveSubspacesForSpace(space, (err, spaces) => {
|
|
||||||
innerCb(err, spaces);
|
|
||||||
});
|
|
||||||
}, (err, subspaces) => {
|
|
||||||
var flattenSubspaces = _.flatten(subspaces);
|
|
||||||
flattenSubspaces.push(parentSpace);
|
|
||||||
cb(null, flattenSubspaces);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
cb(null, [parentSpace]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports.spaceSchema.statics.getRecursiveSubspacesForSpace = getRecursiveSubspacesForSpace;
|
|
||||||
|
|
||||||
var roleMapping = {
|
|
||||||
"none": 0,
|
|
||||||
"viewer": 1,
|
|
||||||
"editor": 2,
|
|
||||||
"admin": 3
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.spaceSchema.statics.roleInSpace = (originalSpace, user, cb) => {
|
|
||||||
if (user.home_folder_id.toString() === originalSpace._id.toString()) {
|
|
||||||
cb(null, "admin");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (originalSpace.creator) {
|
|
||||||
if (originalSpace.creator._id.toString() === user._id.toString()) {
|
|
||||||
cb(null, "admin");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var findMembershipsForSpace = function(space, allMemberships, prevRole) {
|
|
||||||
Membership.find({
|
|
||||||
"space": space._id
|
|
||||||
}, (err, parentMemberships) => {
|
|
||||||
var currentMemberships = parentMemberships.concat(allMemberships);
|
|
||||||
|
|
||||||
if (space.parent_space_id) {
|
|
||||||
Space.findOne({
|
|
||||||
"_id": space.parent_space_id
|
|
||||||
}, function(err, parentSpace) {
|
|
||||||
|
|
||||||
var role = prevRole;
|
|
||||||
if(role == "none"){
|
|
||||||
if(originalSpace.access_mode == "public") {
|
|
||||||
role = "viewer";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
findMembershipsForSpace(parentSpace, currentMemberships, role);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// reached the top
|
|
||||||
var role = prevRole;
|
|
||||||
space.memberships = currentMemberships;
|
|
||||||
currentMemberships.forEach(function(m, i) {
|
|
||||||
if (m.user && m.user.equals(user._id)) {
|
|
||||||
if (m.role != null) {
|
|
||||||
if (roleMapping[m.role] > roleMapping[role]) {
|
|
||||||
role = m.role;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
cb(err, role);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
findMembershipsForSpace(originalSpace, [], "none");
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.spaceSchema.statics.recursiveDelete = (space, cb) => {
|
|
||||||
space.remove(function(err) {
|
|
||||||
|
|
||||||
Action.remove({
|
|
||||||
space: space
|
|
||||||
}, function(err) {
|
|
||||||
if (err)
|
|
||||||
console.error("removed actions for space: ", err);
|
|
||||||
});
|
|
||||||
|
|
||||||
Membership.remove({
|
|
||||||
space: space
|
|
||||||
}, function(err) {
|
|
||||||
if (err)
|
|
||||||
console.error("removed memberships for space: ", err);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (space.space_type === "folder") {
|
|
||||||
Space
|
|
||||||
.find({
|
|
||||||
parent_space_id: space._id
|
|
||||||
})
|
|
||||||
.exec(function(err, spaces) {
|
|
||||||
async.eachLimit(spaces, 10, function(subSpace, innerCb) {
|
|
||||||
module.exports.spaceSchema.statics.recursiveDelete(subSpace, function(err) {
|
|
||||||
innerCb(err);
|
|
||||||
});
|
|
||||||
}, function(err) {
|
|
||||||
cb(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
Artifact.find({
|
|
||||||
space_id: space._id
|
|
||||||
}, function(err, artifacts) {
|
|
||||||
if (err) cb(err);
|
|
||||||
else {
|
|
||||||
async.eachLimit(artifacts, 20, function(a, innerCb) {
|
|
||||||
a.remove(function(err) {
|
|
||||||
innerCb(null, a);
|
|
||||||
});
|
|
||||||
}, function(err) {
|
|
||||||
cb(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var duplicateRecursiveSpace = (space, user, depth, cb, newParentSpace) => {
|
|
||||||
var newSpace = new Space(space);
|
|
||||||
newSpace._id = mongoose.Types.ObjectId();
|
|
||||||
|
|
||||||
if (newParentSpace) {
|
|
||||||
newSpace.parent_space_id = newParentSpace._id;
|
|
||||||
} else {
|
|
||||||
newSpace.name = newSpace.name + " (b)";
|
|
||||||
}
|
|
||||||
|
|
||||||
newSpace.creator = user;
|
|
||||||
newSpace.created_at = new Date();
|
|
||||||
newSpace.updated_at = new Date();
|
|
||||||
|
|
||||||
if (newSpace.space_type === "space") {
|
|
||||||
newSpace.edit_hash = crypto.randomBytes(64).toString('hex').substring(0, 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
newSpace.save(function(err) {
|
|
||||||
|
|
||||||
if (newSpace.space_type === "folder" && depth < 10) {
|
|
||||||
|
|
||||||
Space
|
|
||||||
.find({
|
|
||||||
parent_space_id: space._id
|
|
||||||
})
|
|
||||||
.exec(function(err, spaces) {
|
|
||||||
async.eachLimit(spaces, 10, function(subSpace, innerCb) {
|
|
||||||
|
|
||||||
duplicateRecursiveSpace(subSpace, user, ++depth, function(err, newSubSpace) {
|
|
||||||
innerCb(err, newSubSpace);
|
|
||||||
}, newSpace);
|
|
||||||
|
|
||||||
}, function(err, allNewSubspaces) {
|
|
||||||
cb(err, newSpace);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
Artifact.find({
|
|
||||||
space_id: space._id
|
|
||||||
}, function(err, artifacts) {
|
|
||||||
if (err) innerCb(err);
|
|
||||||
else {
|
|
||||||
async.eachLimit(artifacts, 20, function(a, innerCb) {
|
|
||||||
var newArtifact = new Artifact(a);
|
|
||||||
newArtifact._id = mongoose.Types.ObjectId();
|
|
||||||
newArtifact.space_id = newSpace._id;
|
|
||||||
newArtifact.created_at = new Date();
|
|
||||||
newArtifact.updated_at = new Date();
|
|
||||||
|
|
||||||
newArtifact.save(function(err) {
|
|
||||||
innerCb(null, newArtifact);
|
|
||||||
});
|
|
||||||
|
|
||||||
}, function(err, allNewArtifacts) {
|
|
||||||
cb(err, newSpace);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports.spaceSchema.statics.duplicateSpace = duplicateRecursiveSpace;
|
|
@ -1,53 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
var mongoose = require('mongoose');
|
|
||||||
var Schema = mongoose.Schema;
|
|
||||||
|
|
||||||
module.exports.userSchema = mongoose.Schema({
|
|
||||||
email: String,
|
|
||||||
password_hash: String,
|
|
||||||
nickname: String,
|
|
||||||
account_type: {type: String, default: "email"},
|
|
||||||
created_at: {type: Date, default: Date.now},
|
|
||||||
updated_at: {type: Date, default: Date.now},
|
|
||||||
avatar_original_uri: String,
|
|
||||||
avatar_thumb_uri: String,
|
|
||||||
src: String,
|
|
||||||
confirmation_token: String,
|
|
||||||
confirmed_at: Date,
|
|
||||||
password_reset_token: String,
|
|
||||||
home_folder_id: Schema.Types.ObjectId,
|
|
||||||
team : { type: Schema.Types.ObjectId, ref: 'Team' },
|
|
||||||
preferences: {
|
|
||||||
language: String,
|
|
||||||
email_notifications: {type: Boolean, default: true},
|
|
||||||
daily_digest_last_send: Date,
|
|
||||||
daily_digest: {type: Boolean, default: true}
|
|
||||||
},
|
|
||||||
sessions: [
|
|
||||||
{
|
|
||||||
token: String,
|
|
||||||
expires: Date,
|
|
||||||
device: String,
|
|
||||||
ip: String,
|
|
||||||
created_at: Date
|
|
||||||
}
|
|
||||||
],
|
|
||||||
payment_info: String,
|
|
||||||
payment_plan_key: {type: String, default: "free"},
|
|
||||||
payment_customer_id: String,
|
|
||||||
payment_subscription_id: String,
|
|
||||||
payment_notification_state: Number
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports.userSchema.index({
|
|
||||||
email: 1,
|
|
||||||
"sessions.token": 1,
|
|
||||||
team: 1,
|
|
||||||
created_at: 1,
|
|
||||||
home_folder_id: 1
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports.userSchema.statics.findBySessionToken = function (token, cb) {
|
|
||||||
return this.findOne({ "sessions.token": token}, cb);
|
|
||||||
};
|
|
Loading…
Reference in New Issue
Block a user