Commit b85aa245 authored by Wolfgang Knopki's avatar Wolfgang Knopki
Browse files

Merge branch 'mnt' into 'master'

Mnt

See merge request !2
parents 2fc14e1e fff0340f
......@@ -11,4 +11,4 @@ coverage
.grunt
.lock-wscript
build/Release
node_modules
\ No newline at end of file
node_modules
node_modules
javascripts/maps
javascripts/spacedeck.js
public/stylesheets/*.css
database.sqlite
*.swp
*~
FROM spacedeck/docker-baseimage:latest
ENV NODE_ENV production
FROM node:10-alpine3.11
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
WORKDIR /app
COPY package.json /usr/src/app/
RUN npm install
RUN npm install gulp-rev-replace gulp-clean gulp-fingerprint gulp-rev gulp-rev-all gulp-rev-replace
RUN npm install -g --save-dev gulp
# build audiowaveform from source
RUN apk add git make cmake gcc g++ libmad-dev libid3tag-dev libsndfile-dev gd-dev boost-dev libgd libpng-dev zlib-dev
RUN apk add zlib-static libpng-static boost-static
RUN apk add autoconf automake libtool gettext
RUN wget https://github.com/xiph/flac/archive/1.3.3.tar.gz
RUN tar xzf 1.3.3.tar.gz
RUN cd flac-1.3.3/ && ./autogen.sh
RUN cd flac-1.3.3/ && ./configure --enable-shared=no
RUN cd flac-1.3.3/ && make
RUN cd flac-1.3.3/ && make install
RUN git clone https://github.com/bbc/audiowaveform.git
RUN mkdir audiowaveform/build/
RUN cd audiowaveform/build/ && cmake -D ENABLE_TESTS=0 -D BUILD_STATIC=1 ..
RUN cd audiowaveform/build/ && make
RUN cd audiowaveform/build/ && make install
COPY app.js Dockerfile Gulpfile.js LICENSE /usr/src/app/
COPY config /usr/src/app/config
COPY helpers /usr/src/app/helpers
COPY locales /usr/src/app/locales
COPY middlewares /usr/src/app/middlewares
COPY models /usr/src/app/models
COPY public /usr/src/app/public
COPY routes /usr/src/app/routes
COPY styles /usr/src/app/styles
COPY views /usr/src/app/views
# install other requirements
RUN gulp all
RUN npm cache clean
RUN apk add graphicsmagick ffmpeg ffmpeg-dev ghostscript
# install node package
COPY package*.json ./
RUN npm install
COPY . .
CMD [ "node", "app.js" ]
# start app
EXPOSE 9666
CMD ["node", "spacedeck.js"]
var gulp = require('gulp');
var sass = require('gulp-sass');
var concat = require('gulp-concat');
const gulp = require('gulp')
const sass = require('gulp-sass')
const concat = require('gulp-concat')
gulp.task('styles', function() {
gulp.task('styles', function(done) {
gulp.src('styles/**/*.scss')
.pipe(sass({
errLogToConsole: true
}))
.pipe(gulp.dest('./public/stylesheets/'))
.pipe(concat('style.css'));
});
.pipe(concat('style.css'))
done()
})
# Spacedeck Open
![Spacedeck 6.0 Screenshot](/public/images/sd6-screenshot.png)
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).
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.
[MNT Research GmbH](https://mntre.com) has restarted development of Spacedeck Open in 2020.
We appreciate filed issues, pull requests and general discussion.
# Features
......@@ -13,9 +17,9 @@ We appreciate filed issues, pull requests and general discussion.
- 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
- Collaborate in realtime with teammates, students or friends
- Share Spaces on the web or via email
- Export your work as printable PDF or ZIP
- Export your work as printable PDF or ZIP (currently being fixed, stay tuned)
# Use Cases
......@@ -23,23 +27,15 @@ We appreciate filed issues, pull requests and general discussion.
- Creative: Mood boards, Brainstorming, Design Thinking
- Visual note taking and planning
# 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:
- Node.js 9.x: Web Server / API. Download: https://nodejs.org
- Node.js 10.x: Web Server / API. Download: https://nodejs.org
- Graphicsmagick. On non-Linux, Download: http://www.graphicsmagick.org/ On Linux, install via package manager.
- Optionally ffmpeg, audiowaveform and ghostscript. See "Optional Dependencies" below.
To run Spacedeck, you only need Node.JS 9.x.
To run Spacedeck, you only need Node.JS 10.x.
To install all node dependencies, run (do this once):
......@@ -47,7 +43,7 @@ To install all node dependencies, run (do this once):
# Configuration
See [config/default.json](config/default.json)
See [config/default.json](config/default.json). Set `storage_local_path` for a local sqlite database or `storage_region`, `storage_bucket`, `storage_cdn` and `storage_endpoint` for AWS S3. `mail_provider` may be one of `console` or `smtp`. Also, omit a trailing `/` for the `endpoint`.
# Run (web server)
......@@ -55,10 +51,6 @@ See [config/default.json](config/default.json)
Then open http://localhost:9666 in a web browser.
# Run (desktop app with integrated web server)
electron .
# Optional Dependencies
For advanced media conversion:
......@@ -72,6 +64,16 @@ For advanced media conversion:
By default, media files are uploaded to the ```storage``` folder.
The database is stored in ```database.sqlite``` by default.
# Run with Docker
- configure `config/default.json`
- configure `volumes` section inside `docker-compose.yml`
- point to `database.sqlite` on the host system
- `touch database.sqlite` if it not exists
- point to `storage/` on the host system
- `mkdir storage/` if it not exists
- start the container with `sudo docker-compose up -f docker-compose.yml -d --build`
# Hacking
To rebuild the frontend CSS styles:
......
const spacedeck = require('./spacedeck')
const electron = require('electron')
const electronApp = electron.app
const BrowserWindow = electron.BrowserWindow
let mainWindow
function createWindow () {
mainWindow = new BrowserWindow({width: 1200, height: 700})
mainWindow.loadURL("http://localhost:9666")
mainWindow.on('closed', function () {
mainWindow = null
})
}
electronApp.on('ready', createWindow)
// Quit when all windows are closed.
electronApp.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
electronApp.quit()
}
})
electronApp.on('activate', function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
#!/usr/bin/env node
var app = require('../app');
var http = require('http');
var server = http.createServer(app);
......@@ -2,16 +2,17 @@
"team_name": "My Open Spacedeck",
"contact_email": "support@example.org",
"host": "::",
"port": 9666,
"endpoint": "http://localhost:9666",
"invite_code": "top-sekrit",
"storage_region": "eu-central-1",
//"storage_bucket": "sdeck-development",
//"storage_cdn": "http://localhost:9123/sdeck-development",
//"storage_endpoint": "http://storage:9000",
"storage_bucket": "my_spacedeck_bucket",
"storage_cdn": "/storage",
"storage_local_path": "./storage",
"storage_local_db": "./database.sqlite",
"redis_mock": true,
"mongodb_host": "localhost",
......@@ -22,12 +23,15 @@
"admin_pass": "very_secret_admin_password",
"phantom_api_secret": "very_secret_phantom_password",
// Choose "console" or "smtp"
"mail_provider": "smtp",
"mail_smtp_host": "your.smtp.host",
"mail_smtp_port": 465,
"mail_smtp_secure": true,
"mail_smtp_require_tls": true,
"mail_smtp_user": "your.smtp.user",
"mail_smtp_pass": "your.secret.smtp.password"
"mail_smtp_pass": "your.secret.smtp.password",
"path" : "http://localhost:9666/saml/SSO",
"entryPoint" : "https://m4lab.hft-stuttgart.de/idp/saml2/idp/SSOService.php",
"issuer" : "spacedeck.m4lab.hft-stuttgart.de"
}
version: "2.0"
services:
spacedeck:
build: .
container_name: spacedeck
ports:
- "9666:9666"
volumes:
- /absolute/path/to/storage:/app/storage
- /absolute/path/to/database.sqlite:/app/database.sqlite
To add fonts to Spacedeck Open, follow these steps:
1. Find the googleapis link for the font and add it to [./styles/type.scss](https://github.com/spacedeck/spacedeck-open/blob/docs/styles/type.scss#L4) after the `Inter` font that is already there. Here is a good reference to using [Google Font API](https://www.webfx.com/blog/web-design/google-font-api-guide/).
2. Add the name of the font to the file [./public/javascripts/spacedeck_sections.js](https://github.com/spacedeck/spacedeck-open/blob/docs/public/javascripts/spacedeck_sections.js#L150) in the `fonts` section found around line 150. The order of the list here is the order in which fonts will be displayed in the user interface.
3. From the root of your install, do `gulp styles` to recompile the SCSS.
4. Restart your server.
## Adding a new language to Spacedeck Open
To add a new language to Spacedeck Open, follow these steps:
*The steps are illustrated with Spanish (locale 'es') as the new language*
- Include the new locale ('es') in the locale list (./spacedeck.js):
```
locales: ["en",..., "es"],
```
- Create the new translation file (/locales/**es.js**, a copy of /locales/en.js) and translate the entries.
- Include the javascript for the new translation at the end of /views/spacedeck.ejs:
```
...
window.locales.es = {};
...
window.locales.es.translation = <%- include "./../locales/es.js" %>;
</script>
```
- Include a radio button for users to select the new language (/views/partials/account.html)
```
<label class="radio" v-bind:class="{checked: user.prefs_language=='es'}" v-on:click="save_user_language('es')">
<input type="radio" id="user-preferences_language" name="language" value="es"><span>Español</span>
</label>
```
# 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 ..\..
````
......@@ -2,8 +2,6 @@
const config = require('config');
const nodemailer = require('nodemailer');
const swig = require('swig');
//var AWS = require('aws-sdk');
module.exports = {
sendMail: (to_email, subject, body, options) => {
......@@ -24,35 +22,38 @@ module.exports = {
plaintext+="\n"+options.action.link+"\n\n";
}
const htmlText = swig.renderFile('./views/emails/action.html', {
text: body.replace(/(?:\n)/g, '<br />'),
options: options
});
if (config.get('mail_provider') === 'console') {
console.log("Email: to " + to_email + " in production.\nreply_to: " + reply_to + "\nsubject: " + subject + "\nbody: \n" + htmlText + "\n\n plaintext:\n" + plaintext);
console.log("Email: to " + to_email + " in production.\nreply_to: " + reply_to + "\nsubject: " + subject + "\nbody: \n" + plaintext + "\n\n plaintext:\n" + plaintext);
} else if (config.get('mail_provider') === 'smtp') {
const transporter = nodemailer.createTransport({
host: config.get('mail_smtp_host'),
port: config.get('mail_smtp_port'),
secure: config.get('mail_smtp_secure'),
requireTLS: config.get('mail_smtp_require_tls'),
auth: {
user: config.get('mail_smtp_user'),
pass: config.get('mail_smtp_pass'),
}
});
let transporter;
if (config.has('mail_smtp_user')) {
transporter = nodemailer.createTransport({
host: config.get('mail_smtp_host'),
port: config.get('mail_smtp_port'),
secure: config.get('mail_smtp_secure'),
requireTLS: config.get('mail_smtp_require_tls'),
auth: {
user: config.get('mail_smtp_user'),
pass: config.get('mail_smtp_pass'),
}
});
} else {
transporter = nodemailer.createTransport({
host: config.get('mail_smtp_host'),
port: config.get('mail_smtp_port'),
secure: config.get('mail_smtp_secure'),
requireTLS: config.get('mail_smtp_require_tls'),
});
}
transporter.sendMail({
from: from,
replyTo: reply_to,
to: to_email,
subject: subject,
text: plaintext,
html: htmlText,
text: plaintext
}, function(err, info) {
if (err) {
console.error("Error sending email:", err);
......@@ -61,33 +62,6 @@ module.exports = {
}
});
} else if (config.get('mail_provider') === 'aws') {
/*
AWS.config.update({region: 'eu-west-1'});
var ses = new AWS.SES();
ses.sendEmail( {
Source: from,
Destination: { ToAddresses: [to_email] },
ReplyToAddresses: reply_to,
Message: {
Subject: {
Data: subject
},
Body: {
Text: {
Data: plaintext,
},
Html: {
Data: htmlText
}
}
}
}, function(err, data) {
if (err) console.error("Error sending email:", err);
else console.log("Email sent.");
});
*/
}
}
};
<?php
/*
Plugin Name: Spacedeck
Plugin URI: https://spacedeck.com
description: Embed Spacedeck Whiteboards in Wordpress Posts
Version: 1.0
Author: MNT Research GmbH
Author URI: https://mntre.com
License: GPLv3+
*/
add_option("spacedeck_settings");
function spacedeck_apicall($method, $path, $data) {
$spacedeck_api_base_uri = get_option("spacedeck_settings")[spacedeck_api_base_uri];
$spacedeck_api_key = get_option("spacedeck_settings")[spacedeck_api_key];
$data_string = json_encode($data);
$url = $spacedeck_api_base_uri . $path;
$headers = array(
'Content-Type' => 'application/json',
'X-Spacedeck-API-Token' => $spacedeck_api_key
);
$payload = array(
'method' => $method,
'timeout' => 10,
'blocking' => true,
'headers' => $headers,
'body' => $data_string
);
// echo("<p>payload:</p><pre>");
// print_r($payload);
// echo("</pre>");
$result = wp_remote_post($url, $payload);
if (is_wp_error($result)) {
return $result;
}
$result = json_decode($result[body], true);
// echo("<p>decoded:</p><pre>");
// print_r($result);
// echo("</pre>");
return $result;
}
function spacedeck_embed_space($slug, $width = '90%', $height = '800', $parent_space_id = null) {
$spacedeck_frontend_base_uri = get_option("spacedeck_settings")[spacedeck_frontend_base_uri];
// try to find the space identified by slug
$space = spacedeck_apicall("GET", "/spaces/" . $slug, array());
if (is_wp_error($space)) {
$error = $response->get_error_message();
return("<p><b>Spacedeck: WP Error looking up Space: $error</b></p>");
} else if ($space[error] && $space[error]!="space_not_found") {
return("<p><b>Spacedeck: Error looking up Space: $space[error]</b></p>");
}
// if it doesn't exist, create it:
if ($space[error]=="space_not_found") {
$data = array(
"name" => $slug,
"edit_slug" => $slug
);
if ($parent_space_id) {
$data[parent_space_id] = $parent_space_id;
}
$space = spacedeck_apicall("POST", "/spaces", $data);
if (is_wp_error($space)) {
$error = $response->get_error_message();
return("<p><b>Spacedeck: WP Error creating Space: $error</b></p>");
} else if ($space[error]) {
return("<p><b>Spacedeck: Error creating Space: $space[error]</b></p>");
}
}
if (is_wp_error($space)) {
$error = $response->get_error_message();
return("<p><b>Spacedeck: WP Error embedding Space: $error</b></p>");
} else if (!$space || $space[error]) {
return("<p><b>Spacedeck: Error embedding Space. Is your API key set up correctly?</b></p>");
}
$space_auth = $space[edit_hash];
// return a piece of html (iframe) embedding the space
$uri = $spacedeck_frontend_base_uri . '/spaces/' . $slug . '?embedded=1&spaceAuth=' . $space_auth;
$html = "<iframe src='$uri' class='spacedeck' width='$width' height='$height' style='max-width:100%' frameborder='0' allowFullScreen='true'></iframe>";
return $html;
}
function spacedeck_shortcode($attrs) {
extract(shortcode_atts(array(
'id' => 'none',
'parent_space_id' => null,
'width' => '100%',
'height' => '800'
), $attrs));
$w = $attrs[width];
$h = $attrs[height];
if (!$w) $w = '100%';
if (!$h) $h = 800;
return spacedeck_embed_space($attrs[id],$w,$h,$attrs[parent_space_id]);
}
add_shortcode('spacedeck_space', 'spacedeck_shortcode');
add_action('admin_menu', 'spacedeck_add_admin_menu');
add_action('admin_init', 'spacedeck_settings_init');
function spacedeck_add_admin_menu() {
add_options_page('spacedeck', 'Spacedeck', 'manage_options', 'spacedeck', 'spacedeck_options_page');
}
function spacedeck_settings_init() {
register_setting('pluginPage', 'spacedeck_settings');
add_settings_section(
'spacedeck_pluginPage_section',
'Spacedeck Settings',
'spacedeck_settings_section_callback',
'pluginPage'
);
add_settings_field(
'spacedeck_text_field_0',
'API key',
'spacedeck_text_field_0_render',
'pluginPage',
'spacedeck_pluginPage_section'
);
add_settings_field(
'spacedeck_text_field_1',
'API base URL',
'spacedeck_text_field_1_render',
'pluginPage',
'spacedeck_pluginPage_section'
);
add_settings_field(
'spacedeck_text_field_2',
'Frontend base URL',
'spacedeck_text_field_2_render',
'pluginPage',
'spacedeck_pluginPage_section'
);
}
function spacedeck_text_field_0_render() {
$opts = get_option('spacedeck_settings');
?>
<input type='text' name='spacedeck_settings[spacedeck_api_key]' value='<?php echo $opts[spacedeck_api_key]; ?>'>
<?php
}
function spacedeck_text_field_1_render() {
$opts = get_option('spacedeck_settings');
?>
<input type='text' name='spacedeck_settings[spacedeck_api_base_uri]' value='<?php echo $opts[spacedeck_api_base_uri]; ?>'>
<?php
}
function spacedeck_text_field_2_render() {
$opts