|  | @@ -3,49 +3,90 @@
 | 
	
		
			
				|  |  |  const isSandstorm = Meteor.settings && Meteor.settings.public &&
 | 
	
		
			
				|  |  |                      Meteor.settings.public.sandstorm;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -// In sandstorm we only have one board per sandstorm instance. Since we want to
 | 
	
		
			
				|  |  | -// keep most of our code unchanged, we simply hard-code a board `_id` and
 | 
	
		
			
				|  |  | -// redirect the user to this particular board.
 | 
	
		
			
				|  |  | -const sandstormBoard = {
 | 
	
		
			
				|  |  | -  _id: 'sandstorm',
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // XXX Should be shared with the grain instance name.
 | 
	
		
			
				|  |  | -  title: 'Wekan',
 | 
	
		
			
				|  |  | -  slug: 'libreboard',
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // Board access security is handled by sandstorm, so in our point of view we
 | 
	
		
			
				|  |  | -  // can alway assume that the board is public (unauthorized users won’t be able
 | 
	
		
			
				|  |  | -  // to access it anyway).
 | 
	
		
			
				|  |  | -  permission: 'public',
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// The list of permissions a user have is provided by sandstorm accounts
 | 
	
		
			
				|  |  | -// package.
 | 
	
		
			
				|  |  | -function userHasPermission(user, permission) {
 | 
	
		
			
				|  |  | -  const userPermissions = user.services.sandstorm.permissions;
 | 
	
		
			
				|  |  | -  return userPermissions.indexOf(permission) > -1;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  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 that’s not a
 | 
	
		
			
				|  |  | -  // problem thanks to the reactive board publication. We used to do this
 | 
	
		
			
				|  |  | -  // redirection on the client side but that was sometimes 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"?
 | 
	
		
			
				|  |  | -  Picker.route('/', (params, request, response) => {
 | 
	
		
			
				|  |  | -    const base = 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.
 | 
	
		
			
				|  |  | +  // In sandstorm we only have one board per sandstorm instance. Since we want
 | 
	
		
			
				|  |  | +  // to keep most of our code unchanged, we simply hard-code a board `_id` and
 | 
	
		
			
				|  |  | +  // redirect the user to this particular board.
 | 
	
		
			
				|  |  | +  const sandstormBoard = {
 | 
	
		
			
				|  |  | +    _id: 'sandstorm',
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // XXX Should be shared with the grain instance name.
 | 
	
		
			
				|  |  | +    title: 'Wekan',
 | 
	
		
			
				|  |  | +    slug: 'libreboard',
 | 
	
		
			
				|  |  | +    members: [],
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Board access security is handled by sandstorm, so in our point of view we
 | 
	
		
			
				|  |  | +    // can alway assume that the board is public (unauthorized users won't be
 | 
	
		
			
				|  |  | +    // able to access it anyway).
 | 
	
		
			
				|  |  | +    permission: 'public',
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // This function should probably be handled by `accounts-sandstorm` but
 | 
	
		
			
				|  |  | +  // apparently meteor-core misses an API to handle that cleanly, cf.
 | 
	
		
			
				|  |  | +  // https://github.com/meteor/meteor/blob/ff783e9a12ffa04af6fd163843a563c9f4bbe8c1/packages/accounts-base/accounts_server.js#L1143
 | 
	
		
			
				|  |  | +  function updateUserAvatar(userId, avatarUrl) {
 | 
	
		
			
				|  |  | +    Users.update(userId, {
 | 
	
		
			
				|  |  | +      $set: {
 | 
	
		
			
				|  |  | +        'profile.avatarUrl': avatarUrl,
 | 
	
		
			
				|  |  | +      },
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  function updateUserPermissions(userId, permissions) {
 | 
	
		
			
				|  |  | +    const isActive = permissions.indexOf('participate') > -1;
 | 
	
		
			
				|  |  | +    const isAdmin = permissions.indexOf('configure') > -1;
 | 
	
		
			
				|  |  | +    const permissionDoc = { userId, isActive, isAdmin };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const boardMembers = Boards.findOne(sandstormBoard._id).members;
 | 
	
		
			
				|  |  | +    const memberIndex = _.indexOf(_.pluck(boardMembers, 'userId'), userId);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    let modifier;
 | 
	
		
			
				|  |  | +    if (memberIndex > -1)
 | 
	
		
			
				|  |  | +      modifier = { $set: { [`members.${memberIndex}`]: permissionDoc }};
 | 
	
		
			
				|  |  | +    else if (!isActive)
 | 
	
		
			
				|  |  | +      modifier = {};
 | 
	
		
			
				|  |  | +    else
 | 
	
		
			
				|  |  | +      modifier = { $push: { members: permissionDoc }};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    Boards.update(sandstormBoard._id, modifier);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  Picker.route('/', (params, req, res) => {
 | 
	
		
			
				|  |  | +    // Redirect the user to the hard-coded board. On the first launch the user
 | 
	
		
			
				|  |  | +    // will be redirected to the board before its creation. But that's not a
 | 
	
		
			
				|  |  | +    // problem thanks to the reactive board publication. We used to do this
 | 
	
		
			
				|  |  | +    // redirection on the client side but that was sometimes 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"?
 | 
	
		
			
				|  |  | +    const base = req.headers['x-sandstorm-base-path'];
 | 
	
		
			
				|  |  | +    // XXX If this routing scheme changes, this will break. We should generate
 | 
	
		
			
				|  |  | +    // the location URL using the router, but at the time of writing, the
 | 
	
		
			
				|  |  | +    // it is only accessible on the client.
 | 
	
		
			
				|  |  |      const path = `/boards/${sandstormBoard._id}/${sandstormBoard.slug}`;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    response.writeHead(301, {
 | 
	
		
			
				|  |  | +    res.writeHead(301, {
 | 
	
		
			
				|  |  |        Location: base + path,
 | 
	
		
			
				|  |  |      });
 | 
	
		
			
				|  |  | -    response.end();
 | 
	
		
			
				|  |  | +    res.end();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // `accounts-sandstorm` populate the Users collection when new users
 | 
	
		
			
				|  |  | +    // accesses the document, but in case a already known user come back, we
 | 
	
		
			
				|  |  | +    // need to update his associated document to match the request HTTP headers
 | 
	
		
			
				|  |  | +    // informations.
 | 
	
		
			
				|  |  | +    const user = Users.findOne({
 | 
	
		
			
				|  |  | +      'services.sandstorm.id': req.headers['x-sandstorm-user-id'],
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +    if (user) {
 | 
	
		
			
				|  |  | +      const userId = user._id;
 | 
	
		
			
				|  |  | +      const avatarUrl = req.headers['x-sandstorm-user-picture'];
 | 
	
		
			
				|  |  | +      const permissions = req.headers['x-sandstorm-permissions'].split(',') || [];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // XXX The user may also change his name, we should handle it.
 | 
	
		
			
				|  |  | +      updateUserAvatar(userId, avatarUrl);
 | 
	
		
			
				|  |  | +      updateUserPermissions(userId, permissions);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // On the first launch of the instance a user is automatically created thanks
 | 
	
	
		
			
				|  | @@ -56,38 +97,13 @@ if (isSandstorm && Meteor.isServer) {
 | 
	
		
			
				|  |  |    Users.after.insert((userId, doc) => {
 | 
	
		
			
				|  |  |      if (!Boards.findOne(sandstormBoard._id)) {
 | 
	
		
			
				|  |  |        Boards.insert(sandstormBoard, {validate: false});
 | 
	
		
			
				|  |  | -      Boards.update(sandstormBoard._id, {
 | 
	
		
			
				|  |  | -        $set: {
 | 
	
		
			
				|  |  | -          // 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 }}
 | 
	
		
			
				|  |  |        );
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    // 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: {
 | 
	
		
			
				|  |  | -            userId: doc._id,
 | 
	
		
			
				|  |  | -            isActive: true,
 | 
	
		
			
				|  |  | -            isAdmin: userHasPermission(doc, 'configure'),
 | 
	
		
			
				|  |  | -          },
 | 
	
		
			
				|  |  | -        },
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +    updateUserPermissions(doc._id, doc.services.sandstorm.permissions);
 | 
	
		
			
				|  |  |    });
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -108,4 +124,4 @@ if (isSandstorm && Meteor.isClient) {
 | 
	
		
			
				|  |  |  // We use this blaze helper in the UI to hide some templates that does not make
 | 
	
		
			
				|  |  |  // sense in the context of sandstorm, like board staring, board archiving, user
 | 
	
		
			
				|  |  |  // name edition, etc.
 | 
	
		
			
				|  |  | -Blaze.registerHelper('isSandstorm', () => isSandstorm);
 | 
	
		
			
				|  |  | +Blaze.registerHelper('isSandstorm', isSandstorm);
 |