mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-05-14 11:06:55 -04:00
teampad feature
This commit is contained in:
parent
0f2d542bbe
commit
9212a39cff
14 changed files with 871 additions and 4 deletions
|
@ -23,6 +23,9 @@
|
|||
{ "name": "adminsettings", "hooks": {
|
||||
"expressCreateServer": "ep_etherpad-lite/node/hooks/express/adminsettings:expressCreateServer",
|
||||
"socketio": "ep_etherpad-lite/node/hooks/express/adminsettings:socketio" }
|
||||
},
|
||||
{ "name": "teampad", "hooks": {
|
||||
"expressCreateServer": "ep_etherpad-lite/node/hooks/express/teampad:expressCreateServer" }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ var Pad = function Pad(id) {
|
|||
this.head = -1;
|
||||
this.chatHead = -1;
|
||||
this.publicStatus = false;
|
||||
this.teamStatus = false;
|
||||
this.passwordHash = null;
|
||||
this.id = id;
|
||||
this.savedRevisions = [];
|
||||
|
@ -551,6 +552,15 @@ Pad.prototype.getSavedRevisions = function getSavedRevisions() {
|
|||
return this.savedRevisions;
|
||||
};
|
||||
|
||||
Pad.prototype.getTeamStatus = function getTeamStatus() {
|
||||
return this.teamStatus;
|
||||
};
|
||||
|
||||
Pad.prototype.setTeamStatus = function setTeamStatus(teamStatus) {
|
||||
this.teamStatus = teamStatus;
|
||||
this.saveToDatabase();
|
||||
};
|
||||
|
||||
/* Crypto helper methods */
|
||||
|
||||
function hash(password, salt)
|
||||
|
|
|
@ -236,3 +236,23 @@ exports.unloadPad = function(padId)
|
|||
if(globalPads.get(padId))
|
||||
globalPads.remove(padId);
|
||||
}
|
||||
|
||||
//checks if a pad is a "team pad"
|
||||
exports.isTeamPad = function(padId)
|
||||
{
|
||||
var isTeamPad = false;
|
||||
db.get("pad:"+padId, function(err, value)
|
||||
{
|
||||
if(ERR(err)) return;
|
||||
|
||||
if(value != null && value.atext && value.teamStatus){
|
||||
isTeamPad = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isTeamPad = false;
|
||||
}
|
||||
});
|
||||
|
||||
return isTeamPad;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,27 @@ exports.checkAccess = function (padID, sessionCookie, token, password, callback)
|
|||
callback(null, {accessStatus: "deny"});
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(padManager.isTeamPad(padID))
|
||||
{
|
||||
authorManager.getAuthor4Token(token, function(err, author)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
// TODO check session
|
||||
console.log('sessionCookie: ' + sessionCookie);
|
||||
sessionManager.getSessionInfo(sessionCookie, function(err, result) {
|
||||
if (err) {
|
||||
statusObject = {accessStatus: "denyTeamPad", authorID: author};
|
||||
callback(null, statusObject);
|
||||
} else {
|
||||
// TODO figure out how to force authorID to match account name...
|
||||
statusObject = {accessStatus: "grant", authorID: author};
|
||||
callback(null, statusObject);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
// a session is not required, so we'll check if it's a public pad
|
||||
else
|
||||
|
|
|
@ -360,6 +360,66 @@ function listSessionsWithDBKey (dbkey, callback)
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new session based on an externally-verified account (e.g. persona)
|
||||
*/
|
||||
exports.createVerifiedSession = function(sessionID, account, validUntil, callback)
|
||||
{
|
||||
async.series([
|
||||
|
||||
//check validUntil and create the session db entry
|
||||
function(callback)
|
||||
{
|
||||
//check if rev is a number
|
||||
if(typeof validUntil != "number")
|
||||
{
|
||||
//try to parse the number
|
||||
if(!isNaN(parseInt(validUntil)))
|
||||
{
|
||||
validUntil = parseInt(validUntil);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(new customError("validUntil is not a number","apierror"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//ensure this is not a negativ number
|
||||
if(validUntil < 0)
|
||||
{
|
||||
callback(new customError("validUntil is a negativ number","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
//ensure this is not a float value
|
||||
if(!is_int(validUntil))
|
||||
{
|
||||
callback(new customError("validUntil is a float value","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
//check if validUntil is in the future
|
||||
if(Math.floor(new Date().getTime()/1000) > validUntil)
|
||||
{
|
||||
callback(new customError("validUntil is in the past","apierror"));
|
||||
return;
|
||||
}
|
||||
|
||||
//set the session into the database
|
||||
db.set("session:" + sessionID, {"account": account, "validUntil": validUntil});
|
||||
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//return error and sessionID
|
||||
callback(null, {sessionID: sessionID});
|
||||
})
|
||||
}
|
||||
|
||||
//checks if a number is an int
|
||||
function is_int(value)
|
||||
{
|
||||
|
|
211
src/node/db/TeamManager.js
Normal file
211
src/node/db/TeamManager.js
Normal file
|
@ -0,0 +1,211 @@
|
|||
/**
|
||||
* The Team Manager provides functions to manage teams in the database
|
||||
*/
|
||||
|
||||
/*
|
||||
* 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
var ERR = require("async-stacktrace");
|
||||
var customError = require("../utils/customError");
|
||||
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
||||
var db = require("./DB").db;
|
||||
var async = require("async");
|
||||
var padManager = require("./PadManager");
|
||||
var sessionManager = require("./SessionManager");
|
||||
|
||||
exports.listAllTeams = function(callback) {
|
||||
db.get("teams", function (err, teams) {
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
// there are no teams
|
||||
if(teams == null) {
|
||||
callback(null, {teamIDs: []});
|
||||
return;
|
||||
}
|
||||
|
||||
var teamIDs = [];
|
||||
for ( var teamID in teams) {
|
||||
teamIDs.push(teamID);
|
||||
}
|
||||
callback(null, {teamIDs: teamIDs});
|
||||
});
|
||||
}
|
||||
|
||||
exports.doesTeamExist = function(teamID, callback)
|
||||
{
|
||||
//try to get the team entry
|
||||
db.get("team:" + teamID, function (err, team)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, team != null);
|
||||
});
|
||||
}
|
||||
|
||||
exports.createTeam = function(teamName, pads, accounts, admins, callback)
|
||||
{
|
||||
//search for non existing teamID
|
||||
var teamID = "t." + randomString(16);
|
||||
|
||||
//create the team
|
||||
db.set("team:" + teamID, {name: teamName, pads: pads, accounts: accounts,
|
||||
admins: admins});
|
||||
|
||||
//list the team
|
||||
exports.listAllTeams(function(err, teams) {
|
||||
if(ERR(err, callback)) return;
|
||||
teams = teams? teams.teamIDs : [];
|
||||
|
||||
teams.push(teamID);
|
||||
|
||||
// regenerate team list
|
||||
var newTeams = {};
|
||||
async.forEach(teams, function(team, cb) {
|
||||
newTeams[team] = 1;
|
||||
cb();
|
||||
},function() {
|
||||
db.set("teams", newTeams);
|
||||
callback(null, {teamID: teamID});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
exports.createTeamPad = function(teamName, teamID, padName, text, callback)
|
||||
{
|
||||
//create the padID
|
||||
var padID = teamName + "+" + padName;
|
||||
|
||||
async.series([
|
||||
//ensure team exists
|
||||
function (callback)
|
||||
{
|
||||
exports.doesTeamExist(teamID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//team does not exist
|
||||
if(exists == false)
|
||||
{
|
||||
callback(new customError("teamID does not exist","apierror"));
|
||||
}
|
||||
//team exists, everything is fine
|
||||
else
|
||||
{
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
//ensure pad does not exists
|
||||
function (callback)
|
||||
{
|
||||
padManager.doesPadExists(padID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//pad exists already
|
||||
if(exists == true)
|
||||
{
|
||||
callback(new customError("padName does already exist","apierror"));
|
||||
}
|
||||
//pad does not exist, everything is fine
|
||||
else
|
||||
{
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
//create the pad
|
||||
function (callback)
|
||||
{
|
||||
padManager.getPad(padID, text, function(err, pad)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
pad.setTeamStatus(true);
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
//add to DB
|
||||
function (callback)
|
||||
{
|
||||
db.get("team:" + teamID, function(err, result)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
result.pads.push(padID);
|
||||
db.set('team:' + teamID, result);
|
||||
});
|
||||
callback();
|
||||
}
|
||||
], function(err)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
callback(null, {padID: padID});
|
||||
});
|
||||
}
|
||||
|
||||
exports.listInfo = function(teamID, callback)
|
||||
{
|
||||
exports.doesTeamExist(teamID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//team does not exist
|
||||
if(exists == false)
|
||||
{
|
||||
callback(new customError("teamID does not exist","apierror"));
|
||||
}
|
||||
//team exists, let's get the info
|
||||
else
|
||||
{
|
||||
db.get("team:" + teamID, function(err, result)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
callback(null, result);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
exports.addAccountToTeam = function(teamID, account, callback)
|
||||
{
|
||||
exports.doesTeamExist(teamID, function(err, exists)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//team does not exist
|
||||
if(exists == false)
|
||||
{
|
||||
console.log('debug1: ' + teamID);
|
||||
callback(new customError("teamID does not exist","apierror"));
|
||||
}
|
||||
//team exists, let's get the info
|
||||
else
|
||||
{
|
||||
db.get("team:" + teamID, function(err, result)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
result.accounts.push(account);
|
||||
console.log('setting team to: ' + result);
|
||||
db.set("team:" + teamID, result);
|
||||
callback(null, result);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
|
@ -238,7 +238,14 @@ exports.handleMessage = function(client, message)
|
|||
// our "sessions" "connections".
|
||||
// FIXME: Use a hook instead
|
||||
// FIXME: Allow to override readwrite access with readonly
|
||||
securityManager.checkAccess(message.padId, message.sessionID, message.token, message.password, function(err, statusObject)
|
||||
// FIXME: always use httponly session cookies
|
||||
var sessionID = null;
|
||||
if (padManager.isTeamPad(message.padID)) {
|
||||
sessionID = message.sessionid;
|
||||
} else {
|
||||
sessionID = client.handshake.sessionID;
|
||||
}
|
||||
securityManager.checkAccess(message.padId, sessionID, message.token, message.password, function(err, statusObject)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
@ -874,7 +881,14 @@ function handleClientReady(client, message)
|
|||
// our "sessions" "connections".
|
||||
// FIXME: Use a hook instead
|
||||
// FIXME: Allow to override readwrite access with readonly
|
||||
securityManager.checkAccess (padIds.padId, message.sessionID, message.token, message.password, function(err, statusObject)
|
||||
// FIXME: always use httponly session cookies
|
||||
var sessionID = null;
|
||||
if (padManager.isTeamPad(message.padID)) {
|
||||
sessionID = message.sessionid;
|
||||
} else {
|
||||
sessionID = client.handshake.sessionID;
|
||||
}
|
||||
securityManager.checkAccess (padIds.padId, sessionID, message.token, message.password, function(err, statusObject)
|
||||
{
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ var ERR = require("async-stacktrace");
|
|||
var log4js = require('log4js');
|
||||
var messageLogger = log4js.getLogger("message");
|
||||
var securityManager = require("../db/SecurityManager");
|
||||
var padManager = require("../db/PadManager");
|
||||
|
||||
/**
|
||||
* Saves all components
|
||||
|
@ -108,7 +109,14 @@ exports.setSocketIO = function(_socket)
|
|||
//this message has everything to try an authorization
|
||||
if(message.padId !== undefined && message.sessionID !== undefined && message.token !== undefined && message.password !== undefined)
|
||||
{
|
||||
securityManager.checkAccess (message.padId, message.sessionID, message.token, message.password, function(err, statusObject)
|
||||
// FIXME: always use httponly session cookies
|
||||
var sessionID = null;
|
||||
if (padManager.isTeamPad(message.padID)) {
|
||||
sessionID = message.sessionid;
|
||||
} else {
|
||||
sessionID = client.handshake.sessionID;
|
||||
}
|
||||
securityManager.checkAccess (message.padId, sessionID, message.token, message.password, function(err, statusObject)
|
||||
{
|
||||
ERR(err);
|
||||
|
||||
|
|
276
src/node/hooks/express/teampad.js
Normal file
276
src/node/hooks/express/teampad.js
Normal file
|
@ -0,0 +1,276 @@
|
|||
var express = require('express'),
|
||||
async = require('async'),
|
||||
eejs = require('ep_etherpad-lite/node/eejs'),
|
||||
teamManager = require('ep_etherpad-lite/node/db/TeamManager'),
|
||||
sessionManager = require('ep_etherpad-lite/node/db/SessionManager'),
|
||||
padManager = require('ep_etherpad-lite/node/db/PadManager'),
|
||||
https = require('https');
|
||||
|
||||
exports.expressCreateServer = function (hook_name, args, cb) {
|
||||
args.app.use(express.bodyParser());
|
||||
|
||||
// TODO use more generic, pluggable auth, hardcoded to persona for now
|
||||
args.app.post('/teampad/verify', function(req, res) {
|
||||
console.log('sign in attempt');
|
||||
var body = JSON.stringify({
|
||||
assertion: req.param('assertion', null),
|
||||
audience: 'http://' + req.headers.host
|
||||
});
|
||||
|
||||
var vreq = https.request({
|
||||
host: 'persona.org',
|
||||
path: '/verify',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Length': body.length,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, function(vres) {
|
||||
var body = '';
|
||||
vres.on('data', function(chunk) { body += chunk; });
|
||||
vres.on('end', function() {
|
||||
try {
|
||||
account = JSON.parse(body).email;
|
||||
validUntil = JSON.parse(body).expires;
|
||||
console.log(body);
|
||||
var sessionID = req.signedCookies.express_sid;
|
||||
sessionManager.createVerifiedSession(
|
||||
sessionID, account, validUntil, function(err, result) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
console.log(account + ' logged in');
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
res.redirect('/teampad');
|
||||
});
|
||||
vreq.write(body);
|
||||
vreq.end();
|
||||
});
|
||||
|
||||
args.app.post('/teampad/createteam', function(req, res) {
|
||||
var sessionID = req.cookies.express_sid,
|
||||
currentUser = null,
|
||||
signedIn = false,
|
||||
teamName = null,
|
||||
rawTeamName = req.param('teamname', null);
|
||||
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
sessionManager.getSessionInfo(sessionID, callback);
|
||||
},
|
||||
function(result, callback) {
|
||||
currentUser = result.account;
|
||||
signedIn = true;
|
||||
callback();
|
||||
},
|
||||
function(callback) {
|
||||
console.log('about to sanitize ' + rawTeamName);
|
||||
padManager.sanitizePadId(rawTeamName, function(teamName) {
|
||||
callback(null, teamName);
|
||||
})
|
||||
},
|
||||
function(result, callback) {
|
||||
teamName = result;
|
||||
console.log('sanitized ' + teamName);
|
||||
teamManager.createTeam(teamName, [], [currentUser], [currentUser],
|
||||
callback);
|
||||
},
|
||||
function(teamID, callback) {
|
||||
console.log(teamID + ' created for ' + teamName);
|
||||
res.redirect('/teampad');
|
||||
}
|
||||
], function(err) {
|
||||
console.log('error: ' + err);
|
||||
res.redirect('/teampad');
|
||||
});
|
||||
});
|
||||
|
||||
args.app.post('/teampad/createpad', function(req, res) {
|
||||
var sessionID = req.cookies.express_sid;
|
||||
|
||||
var teamName = null,
|
||||
padName = null,
|
||||
currentUser = null,
|
||||
signedIn = false,
|
||||
teamID = req.param('teamID', null),
|
||||
rawTeamName = req.param('teamname', null),
|
||||
rawPadName = req.param('padname', null);
|
||||
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
sessionManager.getSessionInfo(sessionID, callback);
|
||||
},
|
||||
function(result, callback) {
|
||||
currentUser = result.account;
|
||||
signedIn = true;
|
||||
padManager.sanitizePadId(rawTeamName, function(teamName) {
|
||||
callback(null, teamName);
|
||||
});
|
||||
},
|
||||
function(result, callback) {
|
||||
teamName = result;
|
||||
padManager.sanitizePadId(rawPadName, function(padName) {
|
||||
callback(null, padName);
|
||||
});
|
||||
},
|
||||
function(result, callback) {
|
||||
padName = result;
|
||||
teamManager.createTeamPad(teamName, teamID, padName, 'super sekrit!',
|
||||
callback);
|
||||
},
|
||||
function(callback) {
|
||||
console.log(padName + ' created for ' + teamName);
|
||||
res.redirect('/teampad/' + teamName);
|
||||
}
|
||||
], function(err) {
|
||||
console.log(err);
|
||||
res.redirect('/teampad');
|
||||
});
|
||||
});
|
||||
|
||||
args.app.post('/teampad/addaccount', function(req, res) {
|
||||
var sessionID = req.cookies.express_sid,
|
||||
currentUser = null,
|
||||
signedIn = false,
|
||||
teamName = null,
|
||||
teamID = req.param('teamID', null),
|
||||
rawTeamName = req.param('teamname', null),
|
||||
account = req.param('accountname', null);
|
||||
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
sessionManager.getSessionInfo(sessionID, callback);
|
||||
},
|
||||
function(result, callback) {
|
||||
currentUser = result.account;
|
||||
padManager.sanitizePadId(rawTeamName, function(teamName) {
|
||||
callback(null, teamName);
|
||||
});
|
||||
},
|
||||
function(result, callback) {
|
||||
teamName = result;
|
||||
console.log('teamID: ' + teamID);
|
||||
teamManager.addAccountToTeam(teamID, account, callback);
|
||||
},
|
||||
function(result, callback) {
|
||||
teamID = result;
|
||||
console.log(account+ ' added to ' + teamID);
|
||||
res.redirect('/teampad/' + teamName);
|
||||
},
|
||||
], function(err) {
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
|
||||
args.app.get('/teampad', function(req, res) {
|
||||
var sessionID = req.cookies.express_sid;
|
||||
var currentUser = null;
|
||||
var signedIn = false;
|
||||
|
||||
sessionManager.getSessionInfo(sessionID, function(err, result) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
currentUser = result.account;
|
||||
signedIn = true;
|
||||
}
|
||||
});
|
||||
|
||||
var teamsInfo = [];
|
||||
|
||||
// TODO an index for finding teams by account would make this
|
||||
// *way* faster and easier...
|
||||
teamManager.listAllTeams(function(err, teams) {
|
||||
for (var team in teams.teamIDs) {
|
||||
teamID = teams.teamIDs[team];
|
||||
teamManager.listInfo(teamID, function(err, info) {
|
||||
if (info.accounts) {
|
||||
if (info.accounts.indexOf(currentUser) != -1) {
|
||||
teamsInfo.push(info);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');
|
||||
|
||||
res.send(eejs.require('ep_etherpad-lite/templates/teampad/index.html',
|
||||
{ teamsInfo: teamsInfo,
|
||||
signedIn: signedIn,
|
||||
currentUser: currentUser}));
|
||||
});
|
||||
});
|
||||
|
||||
args.app.get('/teampad/:teamName', function(req, res) {
|
||||
var sessionID = req.cookies.express_sid;
|
||||
var currentUser = null;
|
||||
var signedIn = false;
|
||||
|
||||
sessionManager.getSessionInfo(sessionID, function(err, result) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
res.redirect('/teampad');
|
||||
} else {
|
||||
currentUser = result.account;
|
||||
signedIn = true;
|
||||
|
||||
var teamName = req.path.split('/')[2];
|
||||
var teamInfo = {
|
||||
pads: [],
|
||||
accounts: [],
|
||||
name: [],
|
||||
teamID: []
|
||||
};
|
||||
|
||||
// TODO an index for finding pads/accounts by team would make this
|
||||
// *way* faster and easier...
|
||||
teamManager.listAllTeams(function(err, teams) {
|
||||
for (var team in teams.teamIDs) {
|
||||
teamID = teams.teamIDs[team];
|
||||
teamManager.listInfo(teamID, function(err, info) {
|
||||
if (info.name) {
|
||||
if (teamName === info.name) {
|
||||
teamInfo = info;
|
||||
teamInfo.teamID = teamID;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');
|
||||
|
||||
res.send(eejs.require('ep_etherpad-lite/templates/teampad/team.html',
|
||||
{teamInfo: teamInfo,
|
||||
signedIn: false}));
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// TODO implement, for now we are linking to normal pads via templates
|
||||
args.app.get('/teampad/:teamName/:padName', function(req, res) {
|
||||
var sessionID = req.cookies.express_sid;
|
||||
var currentUser = null;
|
||||
var signedIn = false;
|
||||
|
||||
sessionManager.getSessionInfo(sessionID, function(err, result) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
res.redirect('/teampad');
|
||||
} else {
|
||||
currentUser = result.account;
|
||||
signedIn = true;
|
||||
}
|
||||
});
|
||||
|
||||
var padName = req.path.split('/')[3];
|
||||
|
||||
res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');
|
||||
|
||||
res.send(eejs.require('ep_etherpad-lite/templates/teampad/pad.html'));
|
||||
});
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
var ERR = require("async-stacktrace");
|
||||
var securityManager = require('./db/SecurityManager');
|
||||
var padManager = require("./db/PadManager");
|
||||
|
||||
//checks for padAccess
|
||||
module.exports = function (req, res, callback) {
|
||||
|
@ -7,7 +8,14 @@ module.exports = function (req, res, callback) {
|
|||
// FIXME: Why is this ever undefined??
|
||||
if (req.cookies === undefined) req.cookies = {};
|
||||
|
||||
securityManager.checkAccess(req.params.pad, req.cookies.sessionID, req.cookies.token, req.cookies.password, function(err, accessObj) {
|
||||
// FIXME: always use httponly session cookies
|
||||
var sessionID = null;
|
||||
if (padManager.isTeamPad(req.params.pad)) {
|
||||
sessionID = req.cookies.sessionid;
|
||||
} else {
|
||||
sessionID = req.cookies.express_sid;
|
||||
}
|
||||
securityManager.checkAccess(req.params.pad, sessionID, req.cookies.token, req.cookies.password, function(err, accessObj) {
|
||||
if(ERR(err, callback)) return;
|
||||
|
||||
//there is access, continue
|
||||
|
|
86
src/static/css/teampad.css
Normal file
86
src/static/css/teampad.css
Normal file
|
@ -0,0 +1,86 @@
|
|||
body {
|
||||
margin: 0;
|
||||
color: #333;
|
||||
font: 14px helvetica, sans-serif;
|
||||
background: #ddd;
|
||||
background: -webkit-radial-gradient(circle,#aaa,#eee 60%) center fixed;
|
||||
background: -moz-radial-gradient(circle,#aaa,#eee 60%) center fixed;
|
||||
background: -ms-radial-gradient(circle,#aaa,#eee 60%) center fixed;
|
||||
background: -o-radial-gradient(circle,#aaa,#eee 60%) center fixed;
|
||||
border-top: 8px solid rgba(51,51,51,.8);
|
||||
}
|
||||
#wrapper {
|
||||
margin-top: 160px;
|
||||
padding: 15px;
|
||||
background: #fff;
|
||||
opacity: .9;
|
||||
box-shadow: 0px 1px 8px rgba(0,0,0,0.3);
|
||||
max-width: 700px;
|
||||
margin: auto;
|
||||
border-radius: 0 0 7px 7px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 29px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
}
|
||||
.separator {
|
||||
margin: 10px 0;
|
||||
height: 1px;
|
||||
background: #aaa;
|
||||
background: -webkit-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff);
|
||||
background: -moz-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff);
|
||||
background: -ms-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff);
|
||||
background: -o-linear-gradient(left, #fff, #aaa 20%, #aaa 80%, #fff);
|
||||
}
|
||||
form {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
#inner {
|
||||
width: 300px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
input {
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
}
|
||||
input[type="button"] {
|
||||
padding: 4px 6px;
|
||||
margin: 0;
|
||||
}
|
||||
input[type="button"].do-install, input[type="button"].do-uninstall {
|
||||
float: right;
|
||||
width: 100px;
|
||||
}
|
||||
input[type="button"]#do-search {
|
||||
display: block;
|
||||
}
|
||||
input[type="text"] {
|
||||
border-radius: 3px;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
padding: 10px;
|
||||
*padding: 0; /* IE7 hack */
|
||||
width: 100%;
|
||||
outline: none;
|
||||
border: 1px solid #ddd;
|
||||
margin: 0 0 5px 0;
|
||||
max-width: 500px;
|
||||
}
|
||||
table {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 3px;
|
||||
border-spacing: 0;
|
||||
width: 100%;
|
||||
margin: 20px 0;
|
||||
}
|
||||
table thead tr {
|
||||
background: #eee;
|
||||
}
|
||||
td, th {
|
||||
padding: 5px;
|
||||
}
|
||||
.template {
|
||||
display: none;
|
||||
}
|
|
@ -146,6 +146,9 @@
|
|||
text-align: center;
|
||||
}
|
||||
}
|
||||
#teampads {
|
||||
font: 32px verdana,arial,sans-serif;
|
||||
}
|
||||
</style>
|
||||
<link href="static/custom/index.css" rel="stylesheet">
|
||||
|
||||
|
@ -162,6 +165,12 @@
|
|||
<% e.end_block(); %>
|
||||
</div>
|
||||
|
||||
<div id="wrapper">
|
||||
<div id="inner">
|
||||
<a id="teampads" href="/teampad">Manage TeamPads</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="static/custom/index.js"></script>
|
||||
<script>
|
||||
|
||||
|
|
72
src/templates/teampad/index.html
Normal file
72
src/templates/teampad/index.html
Normal file
|
@ -0,0 +1,72 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Teampad</title>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
|
||||
<link rel="stylesheet" href="../../static/css/teampad.css">
|
||||
</head>
|
||||
|
||||
<div id="wrapper">
|
||||
<h1>Etherpad Lite</h1>
|
||||
<% if (signedIn) { %>
|
||||
<div class="separator"></div>
|
||||
|
||||
<h2>Teams you are a member of</h2>
|
||||
<% if (teamsInfo.length == 0) { %>
|
||||
None yet!
|
||||
<% } else { %>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td id="name">Team name</td>
|
||||
<td id="controls"></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% for (var i=0; i < teamsInfo.length; i++) { %>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/teampad/<%= teamsInfo[i].name %>"><%= teamsInfo[i].name %></a>
|
||||
</td>
|
||||
<td>
|
||||
<% if (teamsInfo[i].admins.indexOf(currentUser) != undefined) { %>
|
||||
[admin]
|
||||
<% } %>
|
||||
</td>
|
||||
</tr>
|
||||
<% } %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% } %>
|
||||
<div class="separator"></div>
|
||||
<form action="/teampad/createteam" method="post">
|
||||
<h2>Create new team:<h2>
|
||||
<input name="teamname" placeholder="Team name" type="text">
|
||||
<input type="submit" name="create" value="Create">
|
||||
</form>
|
||||
|
||||
<% } else { %>
|
||||
|
||||
<span>Sign in to create, manage and see your team pads →</span>
|
||||
|
||||
<form action="/teampad/verify" method="post" style="display:none;">
|
||||
<input type="text" name="assertion"/>
|
||||
</form>
|
||||
|
||||
<img src="https://browserid.org/i/sign_in_red.png" id="browserid"/>
|
||||
<script src="https://login.persona.org/include.js" type="text/javascript"></script>
|
||||
<script>
|
||||
$('#browserid').click(function(){
|
||||
navigator.id.getVerifiedEmail(function(assertion) {
|
||||
if (assertion) {
|
||||
$('input').val(assertion);
|
||||
$('form').submit();
|
||||
} else {
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<% } %>
|
||||
</div>
|
||||
</html>
|
69
src/templates/teampad/team.html
Normal file
69
src/templates/teampad/team.html
Normal file
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><%= teamInfo.name %></title>
|
||||
<link rel="stylesheet" href="../../static/css/teampad.css">
|
||||
</head>
|
||||
<div id="wrapper">
|
||||
<h1>Etherpad Lite</h1>
|
||||
<div class="separator"></div>
|
||||
<h2>Pads belonging to this team:</h2>
|
||||
<% if (teamInfo.pads.length == 0) { %>
|
||||
None yet!
|
||||
<% } else { %>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td id="name">Pad name</td>
|
||||
<td id="controls"></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% for (var i=0; i < teamInfo.pads.length; i++) { %>
|
||||
<tr>
|
||||
<td>
|
||||
<% var teamName = teamInfo.pads[i].split('+')[1]; %>
|
||||
<a href="/p/<%= teamInfo.pads[i] %>"><%= teamName %></a>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<% } %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% } %>
|
||||
<form action="/teampad/createpad" method="post">
|
||||
<h2>Create pad:</h2>
|
||||
<input name="padname" placeholder="Pad name" type="text">
|
||||
<input name="teamname" type="hidden" value="<%= teamInfo.name %>">
|
||||
<input name="teamID" type="hidden" value="<%= teamInfo.teamID %>">
|
||||
<input type="submit" value="Create">
|
||||
</form>
|
||||
<div class="separator"></div>
|
||||
<h2>Authors belonging to this team:</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td id="name">Account name</td>
|
||||
<td id="controls"></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% for (var i=0; i < teamInfo.accounts.length; i++) { %>
|
||||
<tr>
|
||||
<td>
|
||||
<%= teamInfo.accounts[i] %>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<% } %>
|
||||
</tbody>
|
||||
</table>
|
||||
<form action="/teampad/addaccount" method="post">
|
||||
<h2>Add account to team:</h2>
|
||||
<input name="accountname" placeholder="Account name" type="email">
|
||||
<input name="teamname" type="hidden" value="<%= teamInfo.name %>">
|
||||
<input name="teamID" type="hidden" value="<%= teamInfo.teamID %>">
|
||||
<input type="submit" value="Add">
|
||||
</form>
|
||||
</div>
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue