Upgrade sandstorm integration

Both sandstorm and LibreBoard have significantly evolved since the
last release of LibreBoard on sandstorm. This commit:

* adds some more attributes on the sandstorm manifest
* introduces support with the sandstorm sharing box
* uses a server redirection to point to the board document
* hides the top shortcut bar on sandstorm

Fixes #163.
This commit is contained in:
Maxime Quandalle 2015-05-25 21:49:06 +02:00
parent fc2435b042
commit 1b4fcc67f4
7 changed files with 142 additions and 82 deletions

View file

@ -70,7 +70,7 @@ BlazeComponent.extendComponent({
}
};
if (! Meteor.user().isBoardMember())
if (! Meteor.userId() || ! Meteor.user().isBoardMember())
return;
self.$(lists).sortable({

View file

@ -5,26 +5,27 @@ template(name="header")
list all starred boards with a link to go there. This is inspired by the
Reddit "subreddit" bar.
The first link goes to the boards page.
if currentUser
#header-quick-access
ul
li
+linkTo(route="Boards")
span.fa.fa-home
| All boards
each currentUser.starredBoards
li.separator -
li(class="{{#if $.Session.equals 'currentBoard' _id}}current{{/if}}")
+linkTo(route="Board" data=this)
= title
else
li.current Star a board to add a shortcut in this bar.
unless isSandstorm
if currentUser
#header-quick-access
ul
li
+linkTo(route="Boards")
span.fa.fa-home
| All boards
each currentUser.starredBoards
li.separator -
li(class="{{#if $.Session.equals 'currentBoard' _id}}current{{/if}}")
+linkTo(route="Board" data=this)
= title
else
li.current Star a board to add a shortcut in this bar.
li
a.js-create-board
i.fa.fa-plus(title="Create a new board")
li
a.js-create-board
i.fa.fa-plus(title="Create a new board")
+headerUserBar
+headerUserBar
//-
The main bar is a colorful bar that provide all the meta-data for the

View file

@ -48,7 +48,7 @@ BlazeComponent.extendComponent({
onRendered: function() {
var self = this;
if (! Meteor.user().isBoardMember())
if (! Meteor.userId() || ! Meteor.user().isBoardMember())
return;
$(document).on('mouseover', function() {

View file

@ -139,7 +139,7 @@ Boards.before.insert(function(userId, doc) {
// In some cases (Chinese and Japanese for instance) the `getSlug` function
// return an empty string. This is causes bugs in our application so we set
// a default slug in this case.
doc.slug = getSlug(doc.title) || 'board';
doc.slug = doc.slug || getSlug(doc.title) || 'board';
doc.createdAt = new Date();
doc.archived = false;
doc.members = [{
@ -153,22 +153,13 @@ Boards.before.insert(function(userId, doc) {
// Handle labels
var colors = Boards.simpleSchema()._schema['labels.$.color'].allowedValues;
var defaultLabelsColors = _.clone(colors).splice(0, 6);
doc.labels = [];
_.each(defaultLabelsColors, function(val) {
doc.labels.push({
doc.labels = _.map(defaultLabelsColors, function(val) {
return {
_id: Random.id(6),
name: '',
color: val
});
});
// We randomly chose one of the default background colors for the board
if (Meteor.isClient) {
doc.background = {
type: 'color',
color: Random.choice(Boards.simpleSchema()._schema.color.allowedValues)
};
}
});
});
Boards.before.update(function(userId, doc, fieldNames, modifier) {

View file

@ -33,13 +33,10 @@ Users.helpers({
});
Users.before.insert(function(userId, doc) {
doc.profile = {};
doc.profile = doc.profile || {};
// connect profile.status default
doc.profile.status = 'offline';
// slugify to username
//doc.username = getSlug(doc.profile.name, '');
});
if (Meteor.isServer) {

View file

@ -1,3 +1,5 @@
# Use use the meteor-spk tool to generate a sandstorm package (spk) from this
# meteor application source code. https://github.com/sandstorm-io/meteor-spk
@0xa5275bd3ad124e12;
using Spk = import "/sandstorm/package.capnp";
@ -10,18 +12,32 @@ const pkgdef :Spk.PackageDefinition = (
# "pkgdef" constant.
id = "m86q05rdvj14yvn78ghaxynqz7u2svw6rnttptxx49g1785cdv1h",
# Your app ID is actually its public key. The private key was placed in your
# The app ID is actually its public key. The private key was placed in your
# keyring. All updates must be signed with the same key.
manifest = (
# This manifest is included in your app package to tell Sandstorm
# about your app.
# This manifest is included in our app package to tell Sandstorm about our
# app.
appVersion = 1, # Increment this for every release.
appTitle = (defaultText = "LibreBoard"),
# The name of the app as it is displayed to the user.
appVersion = 2,
# Increment this for every release.
appMarketingVersion = (defaultText = "0.9.0"),
# Human-readable presentation of the app version.
minUpgradableAppVersion = 0,
# The minimum version of the app which can be safely replaced by this app
# package without data loss. This might be non-zero if the app's data store
# format changed drastically in the past and the app is no longer able to
# read the old format.
actions = [
# Define your "new document" handlers here.
( title = (defaultText = "New board"),
(
title = (defaultText = "New board"),
command = .myCommand
# The command to run when starting for the first time. (".myCommand" is
# just a constant defined at the bottom of the file.)
@ -43,11 +59,43 @@ const pkgdef :Spk.PackageDefinition = (
]
),
alwaysInclude = [ "." ]
alwaysInclude = [ "." ],
# This says that we always want to include all files from the source map. (An
# alternative is to automatically detect dependencies by watching what the app
# opens while running in dev mode. To see what that looks like, run `spk init`
# without the -A option.)
bridgeConfig = (
viewInfo = (
permissions = [(
name = "participate",
title = (defaultText = "participate"),
description = (defaultText = "allows participating in the board")
), (
name = "configure",
title = (defaultText = "configure"),
description = (defaultText = "allows configuring the board")
)],
roles = [(
title = (defaultText = "observer"),
permissions = [false, false],
verbPhrase = (defaultText = "can read")
), (
title = (defaultText = "member"),
permissions = [true, false],
verbPhrase = (defaultText = "can edit"),
default = true
# ), (
# title = (defaultText = "administrator"),
# permissions = [true, true],
# verbPhrase = (defaultText = "can configure")
#
# XXX Administrators configuration options arent implemented yet, so this
# role is currently useless.
)]
)
)
);
const myCommand :Spk.Manifest.Command = (

View file

@ -8,71 +8,94 @@ var isSandstorm = Meteor.settings && Meteor.settings.public &&
// redirect the user to this particular board.
var sandstormBoard = {
_id: 'sandstorm',
slug: 'board',
// XXX Should be shared with the grain instance name.
title: 'LibreBoard',
permission: 'public',
background: {
type: 'color',
color: '#16A085'
},
slug: 'libreboard',
// XXX Not certain this is a bug, but we except these fields to get inserted
// by the `Lists.before.insert` collection-hook. Since this hook is not called
// in this case, we have to duplicate the logic and set them here.
archived: false,
createdAt: new Date()
// Board access security is handled by sandstorm, so in our point of view we
// can alway assume that the board is public (unauthorized users wont be able
// to access it anyway).
permission: 'public'
};
// The list of permissions a user have is provided by sandstorm accounts
// package.
var userHasPermission = function(user, permission) {
var userPermissions = user.services.sandstorm.permissions;
return userPermissions.indexOf(permission) > -1;
};
// On the first launch of the instance a user is automatically created thanks to
// the `accounts-sandstorm` package. After its creation we insert the unique
// board document. Note that when the `Users.after.insert` hook is called, the
// user is inserted into the database but not connected. So despite the
// appearances `userId` is null in this block.
//
// If the hard-coded board already exists and we are inserting a new user, we
// assume that the owner of the board want to share write privileges with the
// new user.
// XXX Improve that when the Sandstorm sharing model (“Powerbox”) arrives.
if (isSandstorm && Meteor.isServer) {
// Redirect the user to the hard-coded board. On the first launch the user
// will be redirected to the board before its creation. But thats not a
// problem thanks to the reactive board publication. We used to do this
// redirection on the client side but that was sometime visible on loading,
// and the home page was accessible by pressing the back button of the
// browser, a server-side redirection solves both of these issues.
//
// XXX Maybe sandstorm manifest could provide some kind of "home url"?
Router.route('/', function() {
var base = this.request.headers['x-sandstorm-base-path'];
// XXX If this routing scheme changes, this will break. We should generation
// the location url using the router, but at the time of writting, the
// router is only accessible on the client.
var path = '/boards/' + sandstormBoard._id + '/' + sandstormBoard.slug;
this.response.writeHead(301, {
Location: base + path
});
this.response.end();
}, { where: 'server' });
// On the first launch of the instance a user is automatically created thanks
// to the `accounts-sandstorm` package. After its creation we insert the
// unique board document. Note that when the `Users.after.insert` hook is
// called, the user is inserted into the database but not connected. So
// despite the appearances `userId` is null in this block.
Users.after.insert(function(userId, doc) {
if (! Boards.findOne(sandstormBoard._id)) {
Boards.insert(_.extend(sandstormBoard, { userId: doc._id }));
Boards.insert(sandstormBoard, {validate: false});
Boards.update(sandstormBoard._id, {
$set: {
'members.0.userId': doc._id
// The first member (the grain creator) has all rights
'members.0': {
userId: doc._id,
isActive: true,
isAdmin: true
}
}
});
Activities.update({
activityTypeId: sandstormBoard._id
}, {
$set: {
userId: doc._id
}
Activities.update(
{ activityTypeId: sandstormBoard._id }, {
$set: { userId: doc._id }
});
} else {
}
// If the hard-coded board already exists and we are inserting a new user,
// we need to update our user collection.
else if (userHasPermission(doc, 'participate')) {
Boards.update({
_id: sandstormBoard._id,
permission: 'public'
}, {
$push: {
members: doc._id
members: {
userId: doc._id,
isActive: true,
isAdmin: userHasPermission(doc, 'configure')
}
}
});
}
// The sandstom user package put the username in `profile.name`. We need to
// move this field value to follow our schema.
Users.update(doc._id, { $rename: { 'profile.name': 'username' }});
});
}
// On the client, redirect the user to the hard-coded board. On the first launch
// the user will be redirected to the board before its creation. But thats not
// a problem thanks to the reactive board publication.
if (isSandstorm && Meteor.isClient) {
Router.go('Board', {
boardId: sandstormBoard._id,
slug: getSlug(sandstormBoard.title)
});
// XXX Hack. `Meteor.absoluteUrl` doesn't work in Sandstorm, since every
// session has a different URL whereas Meteor computes absoluteUrl based on
// the ROOT_URL environment variable. So we overwrite this function on a