Compare commits
9 Commits
kaleidos-i
...
monolith
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4012ee0c1c | ||
|
|
012a76ee1f | ||
|
|
86bd276d21 | ||
|
|
76f85aa538 | ||
|
|
08b81d5ff4 | ||
|
|
8dc48a84ba | ||
|
|
c549fcf9ec | ||
|
|
9ff1c39e89 | ||
|
|
960a4d6866 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,6 +1,5 @@
|
||||
node_modules
|
||||
public/stylesheets/*
|
||||
javascripts/maps
|
||||
javascripts/spacedeck.js
|
||||
*.swp
|
||||
*~
|
||||
|
||||
|
||||
48
Gulpfile.js
48
Gulpfile.js
@@ -1,6 +1,42 @@
|
||||
var gulp = require('gulp');
|
||||
var sass = require('gulp-sass');
|
||||
var concat = require('gulp-concat');
|
||||
var server = require('gulp-express');
|
||||
var nodemon = require('gulp-nodemon');
|
||||
var revReplace = require("gulp-rev-replace");
|
||||
var clean = require('gulp-clean');
|
||||
|
||||
var child_process = require('child_process');
|
||||
var path = require('path');
|
||||
var uglify = require('gulp-uglify');
|
||||
var fingerprint = require('gulp-fingerprint');
|
||||
var rev = require('gulp-rev');
|
||||
|
||||
var revAll = require('gulp-rev-all');
|
||||
|
||||
gulp.task('rev', () => {
|
||||
return gulp.src(['public/**'])
|
||||
.pipe(gulp.dest('build/assets'))
|
||||
.pipe(revAll.revision())
|
||||
.pipe(gulp.dest('build/assets'))
|
||||
.pipe(revAll.manifestFile())
|
||||
.pipe(gulp.dest('build/assets'));
|
||||
});
|
||||
|
||||
gulp.task("all", ["styles", "uglify", "rev", "copylocales"], function(){
|
||||
var manifest = gulp.src("./build/assets/rev-manifest.json");
|
||||
return gulp.src("./views/**/*")
|
||||
.pipe(revReplace({manifest: manifest}))
|
||||
.pipe(gulp.dest("./build/views"));
|
||||
});
|
||||
|
||||
gulp.task('copylocales', function(){
|
||||
return gulp.src('./locales/*.js').pipe(gulp.dest('./build/locales'));
|
||||
});
|
||||
|
||||
gulp.task('clean', function () {
|
||||
return gulp.src('./build').pipe(clean());
|
||||
});
|
||||
|
||||
gulp.task('styles', function() {
|
||||
gulp.src('styles/**/*.scss')
|
||||
@@ -11,3 +47,15 @@ gulp.task('styles', function() {
|
||||
.pipe(concat('style.css'));
|
||||
});
|
||||
|
||||
gulp.task('uglify', () => {
|
||||
child_process.exec('sed -n \'s/.*script minify src="\\(.*\\)".*/.\\/public\\/\\1/p\' views/spacedeck.html',
|
||||
function (error, stdout, stderr) {
|
||||
var scripts = stdout.split('\n').map(function(p){return path.normalize(p)}).filter(function(p){return p!='.'});
|
||||
console.log("scripts: ",scripts);
|
||||
|
||||
gulp.src(scripts)
|
||||
.pipe(uglify({output:{beautify:true}}))
|
||||
.pipe(concat('spacedeck.js'))
|
||||
.pipe(gulp.dest('public/javascripts'));
|
||||
});
|
||||
});
|
||||
|
||||
61
README.md
61
README.md
@@ -1,15 +1,13 @@
|
||||
# Spacedeck Open
|
||||
|
||||
This is the free and open source version of Spacedeck, a web based, real time, collaborative whiteboard application with rich media support. Spacedeck was developed in 6 major releases during Autumn 2011 until the end of 2016 and was originally a commercial SaaS. The developers were Lukas F. Hartmann (mntmn) and Martin GĂĽther (magegu).
|
||||
This is the free and open source version of Spacedeck, a web based, real time, collaborative whiteboard application with rich media support. Spacedeck was developed in 6 major releases during Autumn 2011 until the end of 2016 and was originally a commercial SaaS. The developers were Lukas F. Hartmann (mntmn) and Martin GĂĽther (magegu). All icons and large parts of the CSS were designed by Thomas Helbig (dergraph).
|
||||
|
||||
The spacedeck.com online service was shut down on May 1st 2018. We decided to open-source Spacedeck to allow educational and other organizations who currently rely on Spacedeck to migrate to a self-hosted or local version.
|
||||
As we plan to retire the subscription based service at spacedeck.com in May 2018, we decided to open-source Spacedeck to allow educational and other organizations who currently rely on Spacedeck to migrate to a self-hosted or local version.
|
||||
|
||||
Data migration features will be added soon.
|
||||
|
||||
We appreciate filed issues, pull requests and general discussion.
|
||||
|
||||
**Windows users:** Try the one-click release at https://github.com/spacedeck/spacedeck-open/releases/tag/v0.9
|
||||
|
||||
Desktop releases for Linux and Mac will be published here soon. In the meantime, you have to install Node.JS to run Spacedeck.
|
||||
|
||||
# Features
|
||||
|
||||
- Create virtual whiteboards called *Spaces* with virtually unlimited size
|
||||
@@ -21,28 +19,32 @@ Desktop releases for Linux and Mac will be published here soon. In the meantime,
|
||||
- Share Spaces on the web or via email
|
||||
- Export your work as printable PDF or ZIP
|
||||
|
||||
# Data Import from Spacedeck.com
|
||||
|
||||
Spacedeck Open has a data import feature that you can use to migrate your ZIP export from Spacedeck.com.
|
||||
|
||||
1. Just copy your downloaded ZIP file into the spacedeck root folder. Don't extract it.
|
||||
2. Start your local Spacedeck.
|
||||
3. Navigate to *Account / Profile* (person icon in the top right corner).
|
||||
4. Click the *Import* button next to the ZIP file name. It is on the bottom of the page.
|
||||
5. Wait until console output has finished and you're done.
|
||||
|
||||
# Requirements, Installation
|
||||
|
||||
Spacedeck requires:
|
||||
Spacedeck uses the following major building blocks:
|
||||
|
||||
- Node.js 9.x: Web Server / API. Download: https://nodejs.org
|
||||
- Node.js 9.x: Web Server / API
|
||||
- Vue.js: Frontend UI Framework (included)
|
||||
- SQLite (included)
|
||||
|
||||
To run Spacedeck, you only need Node.JS 9.x.
|
||||
It also has some optional binary dependencies for advanced media conversion:
|
||||
|
||||
To install all node dependencies, run (do this once):
|
||||
- ffmpeg and ffprobe (for video/audio conversion)
|
||||
- audiowaveform (for audio waveform rendering) (https://github.com/bbcrd/audiowaveform)
|
||||
- ghostscript (gs, for PDF import)
|
||||
|
||||
By default, media files are uploaded to the ```storage``` folder.
|
||||
|
||||
To use Spacedeck, you only need Node.JS 9.x.
|
||||
|
||||
Then, to install all node dependencies, run
|
||||
|
||||
npm install
|
||||
|
||||
To rebuild the frontend CSS styles (you need to do this at least once):
|
||||
|
||||
gulp styles
|
||||
|
||||
# Configuration
|
||||
|
||||
See [config/default.json](config/default.json)
|
||||
@@ -57,25 +59,6 @@ Then open http://localhost:9666 in a web browser.
|
||||
|
||||
electron .
|
||||
|
||||
# Optional Dependencies
|
||||
|
||||
For advanced media conversion:
|
||||
|
||||
- ffmpeg and ffprobe for video/audio conversion. Download: https://www.ffmpeg.org/download.html
|
||||
- audiowaveform for audio waveform rendering. Download: https://github.com/bbcrd/audiowaveform
|
||||
- ghostscript for PDF import. Download: https://www.ghostscript.com/download/gsdnld.html
|
||||
|
||||
# Data Storage
|
||||
|
||||
By default, media files are uploaded to the ```storage``` folder.
|
||||
The database is stored in ```database.sqlite``` by default.
|
||||
|
||||
# Hacking
|
||||
|
||||
To rebuild the frontend CSS styles:
|
||||
|
||||
gulp styles
|
||||
|
||||
# License
|
||||
|
||||
The Spacedeck logo and brand assets are registered trademarks of Spacedeck GmbH. All rights reserved.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
# Windows Electron Build
|
||||
|
||||
sqlite3 needs to be manually built for the iojs version that electron ships. The following code assumes electron v1.8.4.
|
||||
|
||||
````
|
||||
npm -g install windows-build-tools
|
||||
|
||||
cd node_modules\sqlite3
|
||||
|
||||
node-gyp configure --module_name=node_sqlite3 --module_path=../lib/binding/electron-v1.8-win32-x64
|
||||
|
||||
node-gyp rebuild --target=1.8.4 --target_platform=win32 --dist-url=https://atom.io/download/atom-shell --module_name=node_sqlite3 --module_path=../lib/binding/electron-v1.8-win32-x64 --msvs_version=2015
|
||||
|
||||
cd ..\..
|
||||
````
|
||||
|
||||
@@ -37,7 +37,7 @@ const convertableAudioTypes = [
|
||||
"application/ogg",
|
||||
"audio/amr",
|
||||
"audio/3ga",
|
||||
"audio/wave",
|
||||
"audio/wav",
|
||||
"audio/3gpp",
|
||||
"audio/x-wav",
|
||||
"audio/aiff",
|
||||
@@ -92,14 +92,14 @@ function createWaveform(fileName, localFilePath, callback){
|
||||
});
|
||||
}
|
||||
|
||||
function convertVideo(fileName, filePath, codec, callback, progressCallback) {
|
||||
function convertVideo(fileName, filePath, codec, callback, progress_callback) {
|
||||
var ext = path.extname(fileName);
|
||||
var presetMime = mime.lookup(fileName);
|
||||
|
||||
var newExt = codec == "mp4" ? "mp4" : "ogv";
|
||||
var convertedPath = filePath + "." + newExt;
|
||||
|
||||
console.log("converting", filePath, "to", convertedPath);
|
||||
console.log("converting", filePath, "to", convertedPath, "progress_cb:",progress_callback);
|
||||
|
||||
var convertArgs = (codec == "mp4") ? [
|
||||
"-i", filePath,
|
||||
@@ -134,8 +134,8 @@ function convertVideo(fileName, filePath, codec, callback, progressCallback) {
|
||||
|
||||
ff.stderr.on('data', function (data) {
|
||||
console.log('[ffmpeg-video] stderr: ' + data);
|
||||
if (progressCallback) {
|
||||
progressCallback(data);
|
||||
if (progress_callback) {
|
||||
progress_callback(data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -263,8 +263,6 @@ var resizeAndUploadImage = function(a, mimeType, size, fileName, fileNameOrg, im
|
||||
a.h = Math.round(size.height*factor);
|
||||
|
||||
a.updated_at = new Date();
|
||||
db.packArtifact(a);
|
||||
|
||||
a.save().then(function() {
|
||||
fs.unlink(originalFilePath, function (err) {
|
||||
if (err){
|
||||
@@ -280,7 +278,7 @@ var resizeAndUploadImage = function(a, mimeType, size, fileName, fileNameOrg, im
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
convert: function(a, fileName, localFilePath, payloadCallback, progressCallback) {
|
||||
convert: function(a, fileName, localFilePath, payloadCallback, progress_callback) {
|
||||
getMime(fileName, localFilePath, function(err, mimeType){
|
||||
console.log("[convert] fn: "+fileName+" local: "+localFilePath+" mimeType:", mimeType);
|
||||
|
||||
@@ -311,8 +309,8 @@ module.exports = {
|
||||
var s3Key = "s"+ a.space_id.toString() + "/a" + a._id.toString() + "/" + fileName;
|
||||
|
||||
uploader.uploadFile(s3Key, "image/gif", localFilePath, function(err, url) {
|
||||
if (err) payloadCallback(err);
|
||||
else {
|
||||
if(err)callback(err);
|
||||
else{
|
||||
console.log(localFilePath);
|
||||
var stats = fs.statSync(localFilePath);
|
||||
|
||||
@@ -330,8 +328,6 @@ module.exports = {
|
||||
a.h = Math.round(size.height*factor);
|
||||
|
||||
a.updated_at = new Date();
|
||||
db.packArtifact(a);
|
||||
|
||||
a.save().then(function() {
|
||||
fs.unlink(localFilePath, function (err) {
|
||||
if (err){
|
||||
@@ -357,8 +353,8 @@ module.exports = {
|
||||
thumbnail: function(callback) {
|
||||
createThumbnailForVideo(fileName, localFilePath, function(err, created){
|
||||
console.log("thumbnail created: ", err, created);
|
||||
if (err) callback(err);
|
||||
else {
|
||||
if(err) callback(err);
|
||||
else{
|
||||
var keyName = "s" + a.space_id.toString() + "/a" + a._id.toString() + "/" + fileName + ".jpg" ;
|
||||
uploader.uploadFile(keyName, "image/jpeg", created, function(err, url){
|
||||
if (err) callback(err);
|
||||
@@ -380,7 +376,7 @@ module.exports = {
|
||||
else callback(null, url);
|
||||
});
|
||||
}
|
||||
}, progressCallback);
|
||||
}, progress_callback);
|
||||
}
|
||||
},
|
||||
mp4: function(callback) {
|
||||
@@ -396,7 +392,7 @@ module.exports = {
|
||||
else callback(null, url);
|
||||
});
|
||||
}
|
||||
}, progressCallback);
|
||||
}, progress_callback);
|
||||
}
|
||||
},
|
||||
original: function(callback){
|
||||
@@ -404,7 +400,7 @@ module.exports = {
|
||||
callback(null, url);
|
||||
});
|
||||
}
|
||||
}, function(err, results) {
|
||||
}, function(err, results){
|
||||
console.log(err, results);
|
||||
|
||||
if (err) payloadCallback(err, a);
|
||||
@@ -438,16 +434,19 @@ module.exports = {
|
||||
db.packArtifact(a);
|
||||
|
||||
a.updated_at = new Date();
|
||||
a.save().then(function() {
|
||||
fs.unlink(localFilePath, function (err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
payloadCallback(err, null);
|
||||
} else {
|
||||
console.log('successfully deleted ' + localFilePath);
|
||||
payloadCallback(null, a);
|
||||
}
|
||||
});
|
||||
a.save(function(err) {
|
||||
if (err) payloadCallback(err, null);
|
||||
else {
|
||||
fs.unlink(localFilePath, function (err) {
|
||||
if (err){
|
||||
console.error(err);
|
||||
payloadCallback(err, null);
|
||||
} else {
|
||||
console.log('successfully deleted ' + localFilePath);
|
||||
payloadCallback(null, a);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
"specify": "Bitte spezifiziere",
|
||||
"confirm": "Bitte bestätige",
|
||||
"signup_google": "Mit Google anmelden",
|
||||
"error_unknown_email": "Unbekannte Kombination von Email und Passwort.",
|
||||
"error_unknown_email": "Unbekannte Kombination von Email und Passwort. Oder versuche dich mit Google anzumelden.",
|
||||
"error_password_confirmation": "Die beiden Passwörter stimmen nicht überein.",
|
||||
"error_domain_blocked": "Diese Domain ist gesperrt.",
|
||||
"error_user_email_already_used": "Diese Email-Adresse ist bereits registriert.",
|
||||
|
||||
@@ -44,7 +44,8 @@
|
||||
"sure": "Are you sure?",
|
||||
"specify": "Please Specify",
|
||||
"confirm": "Please Confirm",
|
||||
"error_unknown_email": "This email/password combination is unknown.",
|
||||
"signup_google": "Sign In with Google",
|
||||
"error_unknown_email": "This email/password combination is unknown. Try login with Google.",
|
||||
"error_password_confirmation": "The entered passwords don't match.",
|
||||
"error_domain_blocked": "Your domain is blocked.",
|
||||
"error_user_email_already_used": "This email address is already in use.",
|
||||
@@ -321,4 +322,4 @@
|
||||
"mute_present": "Unfollow",
|
||||
"follow_present_help": "If someone else is presenting this Space, the other members automatically follow the presentation. Switch following on or off with this button.",
|
||||
"export": "export"
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@
|
||||
"specify": "Veuillez préciser:",
|
||||
"confirm": "Veuillez confirmer",
|
||||
"signup_google": "S'inscrire avec Google",
|
||||
"error_unknown_email": "Combinaison inconnue de l'email et mot de passe.",
|
||||
"error_unknown_email": "Combinaison inconnue de l'email et mot de passe. Ou essayer de signer avec Google.",
|
||||
"error_password_confirmation": "Les deux mots de passe ne correspondent pas.",
|
||||
"error_domain_blocked": "Ce domaine a été désactivé.",
|
||||
"error_user_email_already_used": "Cette adresse email est déjà enregistré.",
|
||||
@@ -315,4 +315,4 @@
|
||||
"follow_present": "Suivre",
|
||||
"mute_present": "Pas suivre",
|
||||
"follow_present_help": "follow_present_help"
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,7 @@ module.exports = (req, res, next) => {
|
||||
else db.User.findOne({where: {_id: session.user_id}})
|
||||
.then(user => {
|
||||
if (!user) {
|
||||
var domain = (process.env.NODE_ENV == "production") ? new URL(config.get('endpoint')).hostname : req.headers.hostname;
|
||||
res.clearCookie('sdsession', { domain: domain });
|
||||
res.clearCookie('sdsession');
|
||||
|
||||
if (req.accepts("text/html")) {
|
||||
res.send("Please clear your cookies and try again.");
|
||||
|
||||
79
models/db.js
79
models/db.js
@@ -1,4 +1,7 @@
|
||||
const Umzug = require('umzug');
|
||||
//'use strict';
|
||||
|
||||
//var mongoose = require('mongoose');
|
||||
//const sqlite3 = require('sqlite3').verbose();
|
||||
|
||||
function sequel_log(a,b,c) {
|
||||
console.log(a);
|
||||
@@ -78,13 +81,13 @@ module.exports = {
|
||||
height: Sequelize.INTEGER,
|
||||
background_color: Sequelize.STRING,
|
||||
background_uri: Sequelize.STRING,
|
||||
|
||||
|
||||
created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW},
|
||||
updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW},
|
||||
thumbnail_url: Sequelize.STRING,
|
||||
thumbnail_updated_at: {type: Sequelize.DATE}
|
||||
}),
|
||||
|
||||
|
||||
Membership: sequelize.define('membership', {
|
||||
_id: {type: Sequelize.STRING, primaryKey: true},
|
||||
space_id: Sequelize.STRING,
|
||||
@@ -95,7 +98,7 @@ module.exports = {
|
||||
created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW},
|
||||
updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}
|
||||
}),
|
||||
|
||||
|
||||
Message: sequelize.define('message', {
|
||||
_id: {type: Sequelize.STRING, primaryKey: true},
|
||||
space_id: Sequelize.STRING,
|
||||
@@ -105,7 +108,7 @@ module.exports = {
|
||||
created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW},
|
||||
updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}
|
||||
}),
|
||||
|
||||
|
||||
Artifact: sequelize.define('artifact', {
|
||||
_id: {type: Sequelize.STRING, primaryKey: true},
|
||||
space_id: Sequelize.STRING,
|
||||
@@ -118,7 +121,7 @@ module.exports = {
|
||||
last_update_editor_name: Sequelize.STRING,
|
||||
description: Sequelize.TEXT,
|
||||
state: {type: Sequelize.STRING, default: "idle"},
|
||||
|
||||
|
||||
//linked_to: Sequelize.STRING,
|
||||
title: Sequelize.STRING,
|
||||
tags: Sequelize.TEXT,
|
||||
@@ -139,16 +142,16 @@ module.exports = {
|
||||
//}],
|
||||
|
||||
control_points: Sequelize.TEXT,
|
||||
|
||||
|
||||
group: Sequelize.STRING,
|
||||
locked: {type: Sequelize.BOOLEAN, default: false},
|
||||
|
||||
|
||||
payload_uri: Sequelize.STRING,
|
||||
payload_thumbnail_web_uri: Sequelize.STRING,
|
||||
payload_thumbnail_medium_uri: Sequelize.STRING,
|
||||
payload_thumbnail_big_uri: Sequelize.STRING,
|
||||
payload_size: Sequelize.INTEGER, // file size in bytes
|
||||
|
||||
|
||||
fill_color: {type: Sequelize.STRING, default: "transparent"},
|
||||
stroke_color: {type: Sequelize.STRING, default: "#000000"},
|
||||
text_color: Sequelize.STRING,
|
||||
@@ -173,7 +176,7 @@ module.exports = {
|
||||
border_radius: Sequelize.INTEGER,
|
||||
align: {type: Sequelize.STRING, default: "left"},
|
||||
valign: {type: Sequelize.STRING, default: "top"},
|
||||
|
||||
|
||||
brightness: Sequelize.DECIMAL,
|
||||
contrast: Sequelize.DECIMAL,
|
||||
saturation: Sequelize.DECIMAL,
|
||||
@@ -182,7 +185,7 @@ module.exports = {
|
||||
opacity: Sequelize.DECIMAL,
|
||||
|
||||
payload_alternatives: Sequelize.TEXT,
|
||||
|
||||
|
||||
/*payload_alternatives: [{
|
||||
mime: String,
|
||||
payload_uri: String,
|
||||
@@ -191,12 +194,12 @@ module.exports = {
|
||||
payload_thumbnail_big_uri: String,
|
||||
payload_size: Number
|
||||
}],*/
|
||||
|
||||
|
||||
created_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW},
|
||||
updated_at: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}
|
||||
}),
|
||||
|
||||
init: async function() {
|
||||
|
||||
init: function() {
|
||||
User = this.User;
|
||||
Session = this.Session;
|
||||
Space = this.Space;
|
||||
@@ -217,69 +220,49 @@ module.exports = {
|
||||
},
|
||||
as: 'user'
|
||||
});
|
||||
|
||||
|
||||
Membership.belongsTo(Space, {
|
||||
foreignKey: {
|
||||
name: 'space_id'
|
||||
},
|
||||
as: 'space'
|
||||
});
|
||||
|
||||
|
||||
Artifact.belongsTo(User, {
|
||||
foreignKey: {
|
||||
name: 'user_id'
|
||||
},
|
||||
as: 'user'
|
||||
});
|
||||
|
||||
|
||||
Artifact.belongsTo(Space, {
|
||||
foreignKey: {
|
||||
name: 'space_id'
|
||||
},
|
||||
as: 'space'
|
||||
});
|
||||
|
||||
|
||||
Message.belongsTo(User, {
|
||||
foreignKey: {
|
||||
name: 'user_id'
|
||||
},
|
||||
as: 'user'
|
||||
});
|
||||
|
||||
|
||||
Message.belongsTo(Space, {
|
||||
foreignKey: {
|
||||
name: 'space_id'
|
||||
},
|
||||
as: 'space'
|
||||
});
|
||||
|
||||
await sequelize.sync();
|
||||
|
||||
var umzug = new Umzug({
|
||||
storage: 'sequelize',
|
||||
storageOptions: {
|
||||
sequelize: sequelize
|
||||
},
|
||||
migrations: {
|
||||
params: [
|
||||
sequelize.getQueryInterface(),
|
||||
Sequelize
|
||||
],
|
||||
path: './models/migrations',
|
||||
pattern: /\.js$/
|
||||
}
|
||||
});
|
||||
|
||||
umzug.up().then(function(migrations) {
|
||||
console.log('Migration complete up!');
|
||||
});
|
||||
|
||||
|
||||
sequelize.sync();
|
||||
},
|
||||
|
||||
getUserRoleInSpace: (originalSpace, user, cb) => {
|
||||
originalSpace.path = [];
|
||||
console.log("getUserRoleInSpace",originalSpace._id,user._id,user.home_folder_id);
|
||||
|
||||
|
||||
if (originalSpace._id == user.home_folder_id || (originalSpace.creator_id && originalSpace.creator_id == user._id)) {
|
||||
cb("admin");
|
||||
} else {
|
||||
@@ -337,26 +320,26 @@ module.exports = {
|
||||
},
|
||||
|
||||
unpackArtifact: (a) => {
|
||||
if (a.tags && (typeof a.tags)=="string") {
|
||||
if (a.tags) {
|
||||
a.tags = JSON.parse(a.tags);
|
||||
}
|
||||
if (a.control_points && (typeof a.control_points)=="string") {
|
||||
if (a.control_points) {
|
||||
a.control_points = JSON.parse(a.control_points);
|
||||
}
|
||||
if (a.payload_alternatives && (typeof a.payload_alternatives)=="string") {
|
||||
if (a.payload_alternatives) {
|
||||
a.payload_alternatives = JSON.parse(a.payload_alternatives);
|
||||
}
|
||||
return a;
|
||||
},
|
||||
|
||||
packArtifact: (a) => {
|
||||
if (a.tags && (typeof a.tags)!="string") {
|
||||
if (a.tags) {
|
||||
a.tags = JSON.stringify(a.tags);
|
||||
}
|
||||
if (a.control_points && (typeof a.control_points)!="string") {
|
||||
if (a.control_points) {
|
||||
a.control_points = JSON.stringify(a.control_points);
|
||||
}
|
||||
if (a.payload_alternatives && (typeof a.payload_alternatives)!="string") {
|
||||
if (a.payload_alternatives) {
|
||||
a.payload_alternatives = JSON.stringify(a.payload_alternatives);
|
||||
}
|
||||
return a;
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: function(migration, DataTypes) {
|
||||
return [
|
||||
migration.changeColumn('memberships', 'space_id',
|
||||
{
|
||||
type: DataTypes.STRING,
|
||||
references: {
|
||||
model: 'spaces',
|
||||
key: '_id'
|
||||
},
|
||||
onDelete: 'CASCADE',
|
||||
onUpdate: 'CASCADE'
|
||||
}
|
||||
),
|
||||
migration.changeColumn('artifacts', 'space_id',
|
||||
{
|
||||
type: DataTypes.STRING,
|
||||
references: {
|
||||
model: 'spaces',
|
||||
key: '_id'
|
||||
},
|
||||
onDelete: 'CASCADE',
|
||||
onUpdate: 'CASCADE'
|
||||
}
|
||||
),
|
||||
migration.changeColumn('messages', 'space_id',
|
||||
{
|
||||
type: DataTypes.STRING,
|
||||
references: {
|
||||
model: 'spaces',
|
||||
key: '_id'
|
||||
},
|
||||
onDelete: 'CASCADE',
|
||||
onUpdate: 'CASCADE'
|
||||
}
|
||||
)
|
||||
]
|
||||
},
|
||||
|
||||
down: function(migration, DataTypes) {
|
||||
return [
|
||||
migration.changeColumn('memberships', 'space_id',
|
||||
{
|
||||
type: DataTypes.STRING,
|
||||
references: {
|
||||
model: 'spaces',
|
||||
key: '_id'
|
||||
},
|
||||
onDelete: 'CASCADE',
|
||||
onUpdate: 'NO ACTION'
|
||||
}
|
||||
),
|
||||
,
|
||||
migration.changeColumn('artifacts', 'space_id',
|
||||
{
|
||||
type: DataTypes.STRING,
|
||||
references: {
|
||||
model: 'spaces',
|
||||
key: '_id'
|
||||
},
|
||||
onDelete: 'CASCADE',
|
||||
onUpdate: 'NO ACTION'
|
||||
}
|
||||
),
|
||||
migration.changeColumn('messages', 'space_id',
|
||||
{
|
||||
type: DataTypes.STRING,
|
||||
references: {
|
||||
model: 'spaces',
|
||||
key: '_id'
|
||||
},
|
||||
onDelete: 'CASCADE',
|
||||
onUpdate: 'NO ACTION'
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -26,9 +26,9 @@
|
||||
"helmet": "^3.5.0",
|
||||
"i18n-2": "0.6.3",
|
||||
"log-timestamp": "latest",
|
||||
"morgan": "1.8.1",
|
||||
"mock-aws-s3": "^2.6.0",
|
||||
"moment": "^2.19.3",
|
||||
"morgan": "1.8.1",
|
||||
"node-phantom-simple": "2.2.4",
|
||||
"phantomjs-prebuilt": "2.1.14",
|
||||
"read-chunk": "^2.1.0",
|
||||
@@ -40,7 +40,6 @@
|
||||
"slug": "0.9.1",
|
||||
"sqlite3": "^4.0.0",
|
||||
"swig": "1.4.2",
|
||||
"umzug": "^2.1.0",
|
||||
"underscore": "1.8.3",
|
||||
"uuid": "^3.2.1",
|
||||
"validator": "7.0.0",
|
||||
|
||||
15931
public/javascripts/spacedeck.js
Normal file
15931
public/javascripts/spacedeck.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -41,7 +41,7 @@ var SpacedeckBoardArtifacts = {
|
||||
if ("medium_for_object" in this) {
|
||||
var medium = this.medium_for_object[a._id];
|
||||
if (medium && a._id != this.editing_artifact_id) {
|
||||
medium.value(a.description.toString());
|
||||
medium.value(a.description);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -88,11 +88,10 @@ var SpacedeckBoardArtifacts = {
|
||||
},
|
||||
|
||||
artifact_is_text_blank: function(a) {
|
||||
if (a.description) {
|
||||
desc = a.description.toString();
|
||||
var filtered = desc.replace(/<[^>]+>/g,"").replace(/\s/g,"");
|
||||
if(a.description){
|
||||
var filtered = a.description.replace(/<[^>]+>/g,"").replace(/\s/g,"");
|
||||
return (filtered.length<1);
|
||||
} else {
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
},
|
||||
@@ -587,7 +586,7 @@ var SpacedeckBoardArtifacts = {
|
||||
var selected = this.selected_artifacts();
|
||||
if (selected.length<2) return;
|
||||
|
||||
var sorted = _.sortBy(selected, function(a) { return a.x+a.y*this.active_space.width }.bind(this));
|
||||
var sorted = _.sortBy(selected, function(a) { return a.x+a.y*this.active_space.advanced.width }.bind(this));
|
||||
|
||||
var minx = sorted[0].x;
|
||||
var miny = sorted[0].y;
|
||||
@@ -596,13 +595,11 @@ var SpacedeckBoardArtifacts = {
|
||||
|
||||
var blocks = [];
|
||||
|
||||
var padding = 10;
|
||||
|
||||
for (var i=0; i<sorted.length; i++) {
|
||||
var a = sorted[i];
|
||||
blocks.push({
|
||||
w: a.w+padding,
|
||||
h: a.h+padding,
|
||||
w: a.w,
|
||||
h: a.h,
|
||||
a: a
|
||||
});
|
||||
}
|
||||
|
||||
@@ -252,6 +252,8 @@ var SpacedeckRoutes = {
|
||||
// #hash
|
||||
if (event.currentTarget.hash && event.currentTarget.hash.length>1) return;
|
||||
|
||||
console.log("clicked", event.currentTarget.pathname);
|
||||
|
||||
// external link?
|
||||
if (event.currentTarget.host != location.host) return;
|
||||
|
||||
@@ -267,6 +269,35 @@ var SpacedeckRoutes = {
|
||||
event.preventDefault();
|
||||
}.bind(this));
|
||||
|
||||
if (location.host!=ENV.webHost) {
|
||||
if (!subdomainTeam) {
|
||||
location.href = ENV.webEndpoint;
|
||||
return;
|
||||
} else {
|
||||
if(subdomainTeam.subdomain) {
|
||||
var realHost = (subdomainTeam.subdomain + "." + ENV.webHost);
|
||||
if (location.host != realHost) {
|
||||
location.href = realHost;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
location.href = ENV.webEndpoint;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.logged_in) {
|
||||
if (this.user.team) {
|
||||
if (this.user.team.subdomain && this.user.team.subdomain.length > 0) {
|
||||
var realHost = (this.user.team.subdomain + "." + ENV.webHost);
|
||||
if (location.host != realHost) {
|
||||
location.href = location.protocol + "//" + realHost + location.pathname;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.internal_route(location.pathname);
|
||||
},
|
||||
|
||||
|
||||
@@ -71,7 +71,9 @@ var SpacedeckSpaces = {
|
||||
methods: {
|
||||
search_spaces: function() {
|
||||
var query = this.folder_spaces_search;
|
||||
console.log("search query: ",query);
|
||||
load_spaces_search(query, function(spaces) {
|
||||
console.log("results: ",spaces);
|
||||
this.active_profile_spaces = spaces;
|
||||
}.bind(this));
|
||||
},
|
||||
@@ -83,7 +85,14 @@ var SpacedeckSpaces = {
|
||||
location.reload();
|
||||
},
|
||||
ask_guestname: function(dft, cb) {
|
||||
smoke.prompt(__('what_is_your_name', "Spacedeck") , function(content) {
|
||||
console.log("ask_guestname");
|
||||
|
||||
var team_name = "Spacedeck";
|
||||
|
||||
if(subdomainTeam) {
|
||||
team_name = subdomainTeam.name;
|
||||
}
|
||||
smoke.prompt(__('what_is_your_name', team_name) , function(content) {
|
||||
if (!content || (content.length === 0)) {
|
||||
this.ask_guestname(dft, cb);
|
||||
} else {
|
||||
@@ -92,7 +101,7 @@ var SpacedeckSpaces = {
|
||||
if ("localStorage" in window && localStorage) {
|
||||
try {
|
||||
localStorage['guest_nickname'] = this.guest_nickname;
|
||||
} catch(e) {
|
||||
}catch(e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
@@ -163,6 +172,7 @@ var SpacedeckSpaces = {
|
||||
this.space_embed_html = "<iframe width=\"1024\" height=\"768\" seamless src=\""+ENV.webEndpoint+"/spaces/"+space._id+"?embedded=1\"></iframe>";
|
||||
|
||||
if (!is_home) {
|
||||
//console.log(space);
|
||||
load_members(space, function(members) {
|
||||
this.active_space_memberships = members;
|
||||
}.bind(this));
|
||||
|
||||
@@ -48,6 +48,10 @@ SpacedeckUsers = {
|
||||
},
|
||||
|
||||
finalize_login: function(session_token, on_success) {
|
||||
if(!window.socket_auth || window.socket_auth == '' || window.socket_auth == 'null') {
|
||||
window.socket_auth = session_token;
|
||||
}
|
||||
|
||||
this.load_user(function(user) {
|
||||
if (this.invitation_token) {
|
||||
accept_invitation(this.invitation_token, function(memberships){
|
||||
|
||||
@@ -59,13 +59,13 @@ SpacedeckWebsockets = {
|
||||
else if (msg.action == "delete" && msg.object) {
|
||||
if (this.active_space) {
|
||||
var o = msg.object;
|
||||
if (o._id){
|
||||
if(o._id){
|
||||
var existing_artifact = this.find_artifact_by_id(o._id);
|
||||
if (existing_artifact) {
|
||||
var idx = this.active_space_artifacts.indexOf(existing_artifact);
|
||||
this.active_space_artifacts.splice(idx, 1);
|
||||
} else console.log("existing artifact to delete not found");
|
||||
} else console.error("object without _id");
|
||||
}else console.error("object without _id");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,13 +101,11 @@ SpacedeckWebsockets = {
|
||||
}
|
||||
|
||||
if (this.websocket && this.websocket.readyState==1) {
|
||||
var token = "";
|
||||
if (this.user) token = this.user.token;
|
||||
var auth_params = {
|
||||
action: "auth",
|
||||
editor_auth: space_auth,
|
||||
editor_name: this.guest_nickname,
|
||||
auth_token: token,
|
||||
auth_token: window.socket_auth,
|
||||
space_id: space._id
|
||||
};
|
||||
console.log("[websocket] auth space");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,14 +23,15 @@ router.post('/', function(req, res) {
|
||||
db.User.findOne({where: {email: email}})
|
||||
.error(err => {
|
||||
res.sendStatus(404);
|
||||
//res.status(400).json({"error":"session.users"});
|
||||
})
|
||||
.then(user => {
|
||||
if (!user) {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
else if (bcrypt.compareSync(password, user.password_hash)) {
|
||||
console.log("!!! user: ",user.password_hash);
|
||||
|
||||
if (bcrypt.compareSync(password, user.password_hash)) {
|
||||
crypto.randomBytes(48, function(ex, buf) {
|
||||
var token = buf.toString('hex');
|
||||
console.log("!!! token: ",token);
|
||||
|
||||
var session = {
|
||||
user_id: user._id,
|
||||
@@ -46,7 +47,7 @@ router.post('/', function(req, res) {
|
||||
res.sendStatus(500);
|
||||
})
|
||||
.then(() => {
|
||||
var domain = (process.env.NODE_ENV == "production") ? new URL(config.get('endpoint')).hostname : req.headers.hostname;
|
||||
var domain = (process.env.NODE_ENV == "production") ? new URL(config.get('endpoint')).hostname : "localhost";
|
||||
res.cookie('sdsession', token, { domain: domain, httpOnly: true });
|
||||
res.status(201).json(session);
|
||||
});
|
||||
@@ -59,14 +60,16 @@ router.post('/', function(req, res) {
|
||||
|
||||
router.delete('/current', function(req, res, next) {
|
||||
if (req.user) {
|
||||
var token = req.cookies['sdsession'];
|
||||
db.Session.findOne({where: {token: token}})
|
||||
.then(session => {
|
||||
session.destroy();
|
||||
});
|
||||
var domain = (process.env.NODE_ENV == "production") ? new URL(config.get('endpoint')).hostname : req.headers.hostname;
|
||||
res.clearCookie('sdsession', { domain: domain });
|
||||
res.sendStatus(204);
|
||||
/*var user = req.user;
|
||||
var newSessions = user.sessions.filter( function(session){
|
||||
return session.token != req.token;
|
||||
});*/
|
||||
//user.sessions = newSessions;
|
||||
//user.save(function(err, result) {
|
||||
var domain = new URL(config.get('endpoint')).hostname;
|
||||
res.clearCookie('sdsession', { domain: domain });
|
||||
res.sendStatus(204);
|
||||
//});
|
||||
} else {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
|
||||
@@ -53,8 +53,15 @@ router.get('/', (req, res) => {
|
||||
space_id: req.space._id
|
||||
}}).then(artifacts => {
|
||||
async.map(artifacts, (a, cb) => {
|
||||
db.unpackArtifact(a);
|
||||
//a = a.toObject(); TODO
|
||||
|
||||
if (a.control_points) {
|
||||
a.control_points = JSON.parse(a.control_points);
|
||||
}
|
||||
if (a.payload_alternatives) {
|
||||
a.payload_alternatives = JSON.parse(a.payload_alternatives);
|
||||
}
|
||||
|
||||
if (a.user_id) {
|
||||
// FIXME JOIN
|
||||
/*User.findOne({where: {
|
||||
@@ -123,11 +130,10 @@ router.post('/:artifact_id/payload', function(req, res, next) {
|
||||
var writeStream = fs.createWriteStream(localFilePath);
|
||||
var stream = req.pipe(writeStream);
|
||||
|
||||
var progressCallback = function(progressMsg) {
|
||||
a.description = progressMsg.toString();
|
||||
db.packArtifact(a);
|
||||
var progress_callback = function(progress_msg) {
|
||||
a.description = progress_msg;
|
||||
a.save();
|
||||
redis.sendMessage("update", "Artifact", a, req.channelId);
|
||||
redis.sendMessage("update", a, a.toJSON(), req.channelId);
|
||||
};
|
||||
|
||||
stream.on('finish', function() {
|
||||
@@ -137,7 +143,7 @@ router.post('/:artifact_id/payload', function(req, res, next) {
|
||||
db.Space.update({ updated_at: new Date() }, {where: {_id: req.space._id}});
|
||||
res.distributeUpdate("Artifact", artifact);
|
||||
}
|
||||
}, progressCallback);
|
||||
}, progress_callback);
|
||||
});
|
||||
} else {
|
||||
res.status(401).json({
|
||||
@@ -165,7 +171,6 @@ router.put('/:artifact_id', function(req, res, next) {
|
||||
}}).then(rows => {
|
||||
db.unpackArtifact(newAttr);
|
||||
db.Space.update({ updated_at: new Date() }, {where: {_id: req.space._id} });
|
||||
newAttr._id = a._id;
|
||||
res.distributeUpdate("Artifact", newAttr);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -240,6 +240,7 @@ router.get('/zip', function(req, res, next) {
|
||||
});
|
||||
|
||||
router.get('/html', function(req, res) {
|
||||
console.log("!!!!! hello ");
|
||||
db.Artifact.findAll({where: {
|
||||
space_id: req.space._id
|
||||
}}).then(function(artifacts) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"use strict";
|
||||
var config = require('config');
|
||||
const os = require('os');
|
||||
const db = require('../../models/db');
|
||||
const Sequelize = require('sequelize');
|
||||
const Op = Sequelize.Op;
|
||||
@@ -423,16 +422,17 @@ router.post('/:id/artifacts-pdf', function(req, res, next) {
|
||||
|
||||
var withZones = (req.query.zones) ? req.query.zones == "true" : false;
|
||||
var fileName = (req.query.filename || "upload.bin").replace(/[^a-zA-Z0-9\.]/g, '');
|
||||
var localFilePath = os.tmpdir() + "/" + fileName;
|
||||
var localFilePath = "/tmp/" + fileName;
|
||||
var writeStream = fs.createWriteStream(localFilePath);
|
||||
var stream = req.pipe(writeStream);
|
||||
|
||||
req.on('end', function() {
|
||||
|
||||
var rawName = fileName.slice(0, fileName.length - 4);
|
||||
var outputFolder = os.tmpdir() + "/" + rawName;
|
||||
|
||||
fs.mkdir(outputFolder, function(err) {
|
||||
var outputFolder = "/tmp/" + rawName;
|
||||
var rights = 777;
|
||||
|
||||
fs.mkdir(outputFolder, function(db) {
|
||||
var images = outputFolder + "/" + rawName + "-page-%03d.jpeg";
|
||||
|
||||
// FIXME not portable
|
||||
@@ -455,7 +455,7 @@ router.post('/:id/artifacts-pdf', function(req, res, next) {
|
||||
|
||||
var number = parseInt(baseName.slice(baseName.length - 3, baseName.length), 10);
|
||||
|
||||
gm(localFilePath).size((err, size) => {
|
||||
gm(localFilePath).size(function(err, size) {
|
||||
var w = 350;
|
||||
var h = w;
|
||||
|
||||
@@ -463,51 +463,56 @@ router.post('/:id/artifacts-pdf', function(req, res, next) {
|
||||
var y = startY + ((parseInt(((number - 1) / limitPerRow), 10) + 1) * w);
|
||||
|
||||
var userId;
|
||||
if (req.user) userId = req.user._id;
|
||||
if (req.user)
|
||||
userId = req.user._id;
|
||||
|
||||
var a = db.Artifact.create({
|
||||
_id: uuidv4(),
|
||||
var a = new Artifact({
|
||||
mime: "image/jpg",
|
||||
space_id: req.space._id,
|
||||
user_id: userId,
|
||||
editor_name: req.guest_name,
|
||||
w: w,
|
||||
h: h,
|
||||
x: x,
|
||||
y: y,
|
||||
z: (number + (count + 100))
|
||||
}).then(a => {
|
||||
payloadConverter.convert(a, fileName, localfilePath, (error, artifact) => {
|
||||
if (error) res.status(400).json(error);
|
||||
else {
|
||||
if (withZones) {
|
||||
var zone = {
|
||||
_id: uuidv4(),
|
||||
mime: "x-spacedeck/zone",
|
||||
description: "Zone " + (number),
|
||||
space_id: req.space._id,
|
||||
user_id: userId,
|
||||
editor_name: req.guest_name,
|
||||
w: artifact.w + 20,
|
||||
h: artifact.h + 40,
|
||||
board: {
|
||||
w: w,
|
||||
h: h,
|
||||
x: x,
|
||||
y: y,
|
||||
z: (number + (count + 100))
|
||||
}
|
||||
});
|
||||
|
||||
payloadConverter.convert(a, fileName, localfilePath, (error, artifact) => {
|
||||
if (error) res.status(400).json(error);
|
||||
else {
|
||||
if (withZones) {
|
||||
var zone = new Artifact({
|
||||
mime: "x-spacedeck/zone",
|
||||
description: "Zone " + (number),
|
||||
space_id: req.space._id,
|
||||
user_id: userId,
|
||||
editor_name: req.guest_name,
|
||||
board: {
|
||||
w: artifact.board.w + 20,
|
||||
h: artifact.board.h + 40,
|
||||
x: x - 10,
|
||||
y: y - 30,
|
||||
z: number,
|
||||
z: number
|
||||
},
|
||||
style: {
|
||||
order: number,
|
||||
valign: "middle",
|
||||
align: "center"
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
db.Artifact.create(zone).then((z) => {
|
||||
redis.sendMessage("create", "Artifact", z.toJSON(), req.channelId);
|
||||
cb(null, [artifact, zone]);
|
||||
});
|
||||
zone.save((err) => {
|
||||
redis.sendMessage("create", "Artifact", zone.toJSON(), req.channelId);
|
||||
cb(null, [artifact, zone]);
|
||||
});
|
||||
|
||||
} else {
|
||||
cb(null, [artifact]);
|
||||
}
|
||||
} else {
|
||||
cb(null, [artifact]);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -522,10 +527,10 @@ router.post('/:id/artifacts-pdf', function(req, res, next) {
|
||||
|
||||
if (artifact_or_artifacts instanceof Array) {
|
||||
_.each(artifact_or_artifacts, (a) => {
|
||||
redis.sendMessage("create", "Artifact", JSON.stringify(a), req.channelId);
|
||||
redis.sendMessage("create", "Artifact", a.toJSON(), req.channelId);
|
||||
});
|
||||
} else {
|
||||
redis.sendMessage("create", "Artifact", JSON.stringify(artifact_or_artifacts), req.channelId);
|
||||
redis.sendMessage("create", "Artifact", artifact_or_artifacts.toJSON(), req.channelId);
|
||||
}
|
||||
cb(null);
|
||||
});
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
var config = require('config');
|
||||
const db = require('../../models/db');
|
||||
const uuidv4 = require('uuid/v4');
|
||||
const os = require('os');
|
||||
|
||||
var mailer = require('../../helpers/mailer');
|
||||
var uploader = require('../../helpers/uploader');
|
||||
@@ -26,15 +25,8 @@ var glob = require('glob');
|
||||
|
||||
router.get('/current', function(req, res, next) {
|
||||
if (req.user) {
|
||||
var u = _.clone(req.user.dataValues);
|
||||
delete u.password_hash;
|
||||
delete u.password_reset_token;
|
||||
delete u.confirmation_token;
|
||||
u.token = req.cookies['sdsession'];
|
||||
|
||||
console.log(u);
|
||||
|
||||
res.status(200).json(u);
|
||||
console.log(req.user.team);
|
||||
res.status(200).json(req.user);
|
||||
} else {
|
||||
res.status(401).json({"error":"user_not_found"});
|
||||
}
|
||||
@@ -223,8 +215,8 @@ router.post('/:user_id/avatar', (req, res, next) => {
|
||||
const user = req.user;
|
||||
const filename = "u"+req.user._id+"_"+(new Date().getTime())+".jpeg"
|
||||
|
||||
const localFilePath = os.tmpdir()+"/"+filename;
|
||||
const localResizedFilePath = os.tmpdir()+"/resized_"+filename;
|
||||
const localFilePath = "/tmp/"+filename;
|
||||
const localResizedFilePath = "/tmp/resized_"+filename;
|
||||
const writeStream = fs.createWriteStream(localFilePath);
|
||||
const stream = req.pipe(writeStream);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
const config = require('config');
|
||||
require('../models/db');
|
||||
|
||||
const redis = require('../helpers/redis');
|
||||
const express = require('express');
|
||||
@@ -9,11 +10,6 @@ const router = express.Router();
|
||||
const mailer = require('../helpers/mailer');
|
||||
const _ = require('underscore');
|
||||
|
||||
const db = require('../models/db');
|
||||
const Sequelize = require('sequelize');
|
||||
const Op = Sequelize.Op;
|
||||
const uuidv4 = require('uuid/v4');
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
res.render('index', { title: 'Spaces' });
|
||||
});
|
||||
@@ -124,30 +120,79 @@ router.get('/t/:id', (req, res) => {
|
||||
});
|
||||
|
||||
router.get('/s/:token', (req, res) => {
|
||||
var token = req.params.token;
|
||||
if (token.split("-").length > 0) {
|
||||
token = token.split("-")[0];
|
||||
}
|
||||
redis.rateLimit(req.real_ip, "token", function(ok) {
|
||||
if (ok) {
|
||||
var token = req.params.token;
|
||||
if (token.split("-").length > 0) {
|
||||
token = token.split("-")[0];
|
||||
}
|
||||
|
||||
db.Space.findOne({where: {"edit_hash": token}}).then(function (space) {
|
||||
if (space) {
|
||||
if (req.accepts('text/html')){
|
||||
res.redirect("/spaces/"+space._id + "?spaceAuth=" + token);
|
||||
} else {
|
||||
res.status(200).json(space);
|
||||
}
|
||||
Space.findOne({"edit_hash": token}).exec(function (err, space) {
|
||||
if (err) {
|
||||
res.status(404).render('not_found', { title: 'Page Not Found.' });
|
||||
} else {
|
||||
if (space) {
|
||||
if(req.accepts('text/html')){
|
||||
res.redirect("/spaces/"+space._id + "?spaceAuth=" + token);
|
||||
}else{
|
||||
res.status(200).json(space);
|
||||
}
|
||||
} else {
|
||||
if(req.accepts('text/html')){
|
||||
res.status(404).render('not_found', { title: 'Page Not Found.' });
|
||||
} else {
|
||||
res.status(404).json({});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (req.accepts('text/html')) {
|
||||
res.status(404).render('not_found', { title: 'Page Not Found.' });
|
||||
} else {
|
||||
res.status(404).json({});
|
||||
}
|
||||
res.status(429).json({"error": "Too Many Requests"});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/spaces/:id', (req, res) => {
|
||||
res.render('spacedeck', { title: 'Space' });
|
||||
if (req.headers['user-agent']) {
|
||||
if (req.headers['user-agent'].match(/facebook/)) {
|
||||
Space.findOne({"_id": req.params.id }).exec(function (err, space) {
|
||||
if (err) {
|
||||
res.status(400).json(err);
|
||||
} else {
|
||||
if (space) {
|
||||
if (space.access_mode == "public") {
|
||||
Artifact.find({"space_id": req.params.id }).populate("creator").exec(function(err, artifacts) {
|
||||
space.artifacts = artifacts;
|
||||
res.render('facebook', { space: space });
|
||||
});
|
||||
} else {
|
||||
res.redirect("/?error=space_not_accessible");
|
||||
}
|
||||
} else {
|
||||
res.render('not_found', { title: 'Spaces' });
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// not facebook, render javascript
|
||||
res.render('spacedeck', { title: 'Space' });
|
||||
}
|
||||
} else res.render('spacedeck', { title: 'Space' });
|
||||
});
|
||||
|
||||
router.get('/qrcode/:id', function(req, res) {
|
||||
Space.findOne({"_id": req.params.id}).exec(function(err, space) {
|
||||
if (space) {
|
||||
const url = config.get("endpoint") + "/s/"+space.edit_hash;
|
||||
const code = qr.image(url, { type: 'svg' });
|
||||
res.type('svg');
|
||||
code.pipe(res);
|
||||
} else {
|
||||
res.status(404).json({
|
||||
"error": "not_found"
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -22,13 +22,29 @@
|
||||
window.browser_lang = '[[locale]]';
|
||||
window.csrf_token = '[[csrf_token]]';
|
||||
|
||||
var ENV = {
|
||||
name: 'development',
|
||||
webHost: location.host,
|
||||
webEndpoint: location.origin,
|
||||
apiEndpoint: location.origin,
|
||||
websocketsEndpoint: location.origin.replace("https:","wss:").replace("http:","ws:")
|
||||
};
|
||||
{% if process.env.NODE_ENV != "production" %}
|
||||
var ENV = {
|
||||
name: 'development',
|
||||
webHost: "localhost:9666",
|
||||
webEndpoint:"http://localhost:9666",
|
||||
apiEndpoint: "http://localhost:9666",
|
||||
websocketsEndpoint: "ws://localhost:9666"
|
||||
};
|
||||
{% else %}
|
||||
var ENV = {
|
||||
name: 'production',
|
||||
webHost: location.host,
|
||||
webEndpoint: location.origin,
|
||||
apiEndpoint: location.origin,
|
||||
websocketsEndpoint: location.origin.replace("https:","wss:").replace("http:","ws:")
|
||||
};
|
||||
{% endif %}
|
||||
|
||||
{% if subdomain_team %}
|
||||
var subdomainTeam = [[ subdomain_team | json | safe ]];
|
||||
{% else %}
|
||||
var subdomainTeam = null;
|
||||
{% endif %}
|
||||
</script>
|
||||
|
||||
{% if process.env.NODE_ENV == "production" %}
|
||||
|
||||
Reference in New Issue
Block a user