Skip to content

Commit

Permalink
initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
mntmn committed Apr 6, 2017
0 parents commit 7ff2926
Show file tree
Hide file tree
Showing 258 changed files with 83,743 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
public/stylesheets/*
javascripts/maps
javascripts/spacedeck.js

62 changes: 62 additions & 0 deletions Gulpfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
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', () => {
var revAll = new RevAll();
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')
.pipe(sass({
errLogToConsole: true
}))
.pipe(gulp.dest('./public/stylesheets/'))
.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'));
});
});
661 changes: 661 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# 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). All icons and large parts of the CSS were designed by Thomas Helbig (dergraph).

As we plan to retire the subscription based service at spacedeck.com in late 2017, we decided to open-source Spacedeck to allow educational and other organizations who currently rely on Spacedeck to migrate to a self-hosted version.

Data migration features will be added soon.

We appreciate filed issues, pull requests and general discussion.

# Features

- Create virtual whiteboards called "Spaces" with virtually unlimited size
- Drag & drop images, videos and audio from your computer or the web
- Write and format text with full control over fonts, colors and style
- Draw, annotate and highlight with included graphical shapes
- Turn your Space into a zooming presentation
- Collaborate and chat in realtime with teammates, students or friends
- Share Spaces on the web or via email
- Export your work as printable PDF or ZIP

# Requirements, Installation

Spacedeck uses the following major building blocks:

- Node.js 4.x (Backend / API)
- MongoDB 3.x (Datastore)
- Redis 3.x (Datastore for realtime channels)
- Vue.js (Frontend)

It also has some binary dependencies for media conversion and PDF export:

- imagemagick

Currently, media files are stored in Amazon S3, so you need an Amazon AWS account and have the ```AWS_ACCESS_KEY_ID``` and ```AWS_SECRET_ACCESS_KEY``` environment variables defined. For sending emails, Amazon SES is required.

To install Spacedeck, you need node.js 4.x and a running MongoDB instance. 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

# Run

export NODE_ENV=development
npm start

# License

Spacedeck Open is released under the GNU Affero General Public License Version 3 (GNU AGPLv3).

Spacedeck Open - Web-based Collaborative Whiteboard For Rich Media
Copyright (C) 2011-2017 Lukas F. Hartmann, Martin Güther, Thomas Helbig

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
173 changes: 173 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
"use strict";

require('./models/schema');
require("log-timestamp");

const config = require('config');
const redis = require('./helpers/redis');
const websockets = require('./helpers/websockets');

const http = require('http');
const path = require('path');

const _ = require('underscore');
const favicon = require('serve-favicon');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const swig = require('swig');
const i18n = require('i18n-2');
const helmet = require('helmet');

const express = require('express');
const app = express();

const isProduction = app.get('env') === 'production';

console.log("Booting Spacedeck Open… (environment: " + app.get('env') + ")");

app.use(logger(isProduction ? 'combined' : 'dev'));

i18n.expressBind(app, {
locales: ["en", "de", "fr"],
defaultLocale: "en",
cookieName: "spacedeck_locale",
devMode: (app.get('env') == 'development')
});

swig.setDefaults({
varControls: ["[[", "]]"] // otherwise it's not compatible with vue.js
});

swig.setFilter('cdn', function(input, idx) {
return input;
});

app.engine('html', swig.renderFile);
app.set('view engine', 'html');

if (app.get('env') != 'development') {
app.set('views', path.join(__dirname, 'build', 'views'));
app.use(favicon(path.join(__dirname, 'build', 'assets', 'images', 'favicon.png')));
app.use(express.static(path.join(__dirname, 'build', 'assets')));
} else {
app.set('views', path.join(__dirname, 'views'));
app.use(favicon(path.join(__dirname, 'public', 'images', 'favicon.png')));
app.use(express.static(path.join(__dirname, 'public')));
}

app.use(bodyParser.json({
limit: '50mb'
}));

app.use(bodyParser.urlencoded({
extended: false,
limit: '50mb'
}));

app.use(cookieParser());
app.use(helmet.noCache())
app.use(helmet.frameguard())
app.use(helmet.xssFilter())
app.use(helmet.hsts({
maxAge: 7776000000,
includeSubdomains: true
}))
app.disable('x-powered-by');
app.use(helmet.noSniff())

// CUSTOM MIDDLEWARES

app.use(require("./middlewares/templates"));
app.use(require("./middlewares/error_helpers"));
app.use(require("./middlewares/setuser"));
app.use(require("./middlewares/subdomain"));
app.use(require("./middlewares/cors"));
app.use(require("./middlewares/i18n"));
app.use("/api", require("./middlewares/api_helpers"));
app.use('/api/spaces/:id', require("./middlewares/space_helpers"));
app.use('/api/spaces/:id/artifacts/:artifact_id', require("./middlewares/artifact_helpers"));
app.use('/api/teams', require("./middlewares/team_helpers"));

// REAL ROUTES

app.use('/api/users', require('./routes/api/users'));
app.use('/api/memberships', require('./routes/api/memberships'));

const spaceRouter = require('./routes/api/spaces');
app.use('/api/spaces', spaceRouter);

spaceRouter.use('/:id/artifacts', require('./routes/api/space_artifacts'));
spaceRouter.use('/:id/memberships', require('./routes/api/space_memberships'));
spaceRouter.use('/:id/messages', require('./routes/api/space_messages'));
spaceRouter.use('/:id/digest', require('./routes/api/space_digest'));
spaceRouter.use('/:id', require('./routes/api/space_exports'));

app.use('/api/sessions', require('./routes/api/sessions'));
app.use('/api/teams', require('./routes/api/teams'));
app.use('/api/webgrabber', require('./routes/api/webgrabber'));
app.use('/', require('./routes/root'));

// catch 404 and forward to error handler
app.use(require('./middlewares/404'));
if (app.get('env') == 'development') {
app.set('view cache', false);
swig.setDefaults({cache: false});
} else {
app.use(require('./middlewares/500'));
}

module.exports = app;

// CONNECT TO DATABASE
const mongoHost = process.env.MONGO_PORT_27017_TCP_ADDR || 'localhost';
mongoose.connect('mongodb://' + mongoHost + '/spacedeck');

// START WEBSERVER
const port = 9000;

const server = http.Server(app).listen(port, () => {

if ("send" in process) {
process.send('online');
}

}).on('listening', () => {

const host = server.address().address;
const port = server.address().port;
console.log('Spacedeck Open listening at http://%s:%s', host, port);

}).on('error', (error) => {

if (error.syscall !== 'listen') {
throw error;
}

const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
});

//WEBSOCKETS & WORKER
websockets.startWebsockets(server);
redis.connectRedis();

process.on('message', (message) => {
console.log("Process message:", message);
if (message === 'shutdown') {
console.log("Exiting spacedeck.");
process.exit(0);
}
});
5 changes: 5 additions & 0 deletions bin/www
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env node

var app = require('../app');
var http = require('http');
var server = http.createServer(app);
9 changes: 9 additions & 0 deletions config/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"endpoint": "http://localhost:9000",
"storage_bucket": "my_spacedeck_s3_bucket",
"storage_cdn": "xyz.cloudfront.net",
"google_access" : "",
"google_secret" : "",
"admin_pass": "very_secret_admin_password",
"phantom_api_secret": "very_secret_phantom_password"
}
Loading

0 comments on commit 7ff2926

Please sign in to comment.