mirror of https://github.com/xwiki-labs/cryptpad
Share calendar with a team
This commit is contained in:
parent
1a3ab6fed8
commit
9ae482b744
|
@ -1,6 +1,7 @@
|
|||
@import (reference) '../../customize/src/less2/include/framework.less';
|
||||
@import (reference) '../../customize/src/less2/include/sidebar-layout.less';
|
||||
@import (reference) '../../customize/src/less2/include/tools.less';
|
||||
@import (reference) '../../customize/src/less2/include/avatar.less';
|
||||
|
||||
&.cp-app-calendar {
|
||||
|
||||
|
@ -104,6 +105,22 @@
|
|||
}
|
||||
|
||||
.cp-calendar-list {
|
||||
.cp-calendar-team {
|
||||
height: 30px;
|
||||
.avatar_main(30px);
|
||||
.cp-avatar {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.cp-name {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 5px 0;
|
||||
}
|
||||
.cp-calendar-entry {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
@ -16,6 +16,10 @@ define([
|
|||
'/customize/application_config.js',
|
||||
'/lib/calendar/tui-calendar.min.js',
|
||||
|
||||
'/common/inner/share.js',
|
||||
'/common/inner/access.js',
|
||||
'/common/inner/properties.js',
|
||||
|
||||
'/common/jscolor.js',
|
||||
'css!/lib/calendar/tui-calendar.min.css',
|
||||
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||
|
@ -36,7 +40,8 @@ define([
|
|||
h,
|
||||
Messages,
|
||||
AppConfig,
|
||||
Calendar
|
||||
Calendar,
|
||||
Share, Access, Properties
|
||||
)
|
||||
{
|
||||
var APP = window.APP = {
|
||||
|
@ -57,6 +62,7 @@ Messages.calendar_deleteConfirm = "Are you sure you want to delete this calendar
|
|||
Messages.calendar_deleteTeamConfirm = "Are you sure you want to delete this calendar from this team?";
|
||||
Messages.calendar_deleteOwned = " It will still be visible for the users it has been shared with.";
|
||||
Messages.calendar_errorNoCalendar = "No editable calendar selected!";
|
||||
Messages.calendar_myCalendars = "My calendars";
|
||||
|
||||
var onCalendarsUpdate = Util.mkEvent();
|
||||
|
||||
|
@ -310,6 +316,36 @@ Messages.calendar_errorNoCalendar = "No editable calendar selected!";
|
|||
action: function (e) {
|
||||
e.stopPropagation();
|
||||
editCalendar(id);
|
||||
return true;
|
||||
}
|
||||
}, {
|
||||
tag: 'a',
|
||||
attributes: {
|
||||
'class': 'fa fa-shhare-alt',
|
||||
},
|
||||
content: h('span', Messages.shareButton),
|
||||
action: function (e) {
|
||||
e.stopPropagation();
|
||||
var friends = common.getFriends();
|
||||
var cal = APP.calendars[id];
|
||||
var title = Util.find(cal, ['content', 'metadata', 'title']);
|
||||
var color = Util.find(cal, ['content', 'metadata', 'color']);
|
||||
Share.getShareModal(common, {
|
||||
teamId: teamId === 1 ? undefined : teamId,
|
||||
origin: APP.origin,
|
||||
pathname: "/calendar/",
|
||||
friends: friends,
|
||||
title: title,
|
||||
password: cal.password, // XXX support passwords
|
||||
calendar: {
|
||||
title: title,
|
||||
color: color,
|
||||
channel: id,
|
||||
},
|
||||
common: common,
|
||||
hashes: cal.hashes
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}, {
|
||||
tag: 'a',
|
||||
|
@ -361,7 +397,9 @@ Messages.calendar_errorNoCalendar = "No editable calendar selected!";
|
|||
var md = Util.find(data, ['content', 'metadata']);
|
||||
if (!md) { return; }
|
||||
var active = data.hidden ? '' : '.cp-active';
|
||||
var calendar = h('div.cp-calendar-entry'+active, [
|
||||
var calendar = h('div.cp-calendar-entry'+active, {
|
||||
'data-uid': id
|
||||
}, [
|
||||
h('span.cp-calendar-color', {
|
||||
style: 'background-color: '+md.color+';'
|
||||
}),
|
||||
|
@ -370,7 +408,12 @@ Messages.calendar_errorNoCalendar = "No editable calendar selected!";
|
|||
]);
|
||||
$(calendar).click(function () {
|
||||
data.hidden = !data.hidden;
|
||||
$(calendar).toggleClass('cp-active', !data.hidden);
|
||||
if (APP.$calendars) {
|
||||
APP.$calendars.find('[data-uid="'+id+'"]').toggleClass('cp-active', !data.hidden);
|
||||
} else {
|
||||
$(calendar).toggleClass('cp-active', !data.hidden);
|
||||
}
|
||||
|
||||
renderCalendar();
|
||||
});
|
||||
if (APP.$calendars) { APP.$calendars.append(calendar); }
|
||||
|
@ -436,10 +479,35 @@ Messages.calendar_errorNoCalendar = "No editable calendar selected!";
|
|||
var $calendars = APP.$calendars = $(calendars).appendTo($container);
|
||||
onCalendarsUpdate.reg(function () {
|
||||
$calendars.empty();
|
||||
Object.keys(APP.calendars || {}).forEach(function (id) {
|
||||
var cal = APP.calendars[id];
|
||||
if (!cal) { return; }
|
||||
(cal.teams || []).forEach(function (teamId) {
|
||||
var metadataMgr = common.getMetadataMgr();
|
||||
var privateData = metadataMgr.getPrivateData();
|
||||
var filter = function (teamId) {
|
||||
return Object.keys(APP.calendars || {}).filter(function (id) {
|
||||
var cal = APP.calendars[id] || {};
|
||||
var teams = cal.teams || [];
|
||||
return teams.indexOf(teamId || 1) !== -1;
|
||||
});
|
||||
};
|
||||
var myCalendars = filter(1);
|
||||
if (myCalendars.length) {
|
||||
APP.$calendars.append(h('div.cp-calendar-team', [
|
||||
h('span', Messages.calendar_myCalendars)
|
||||
]));
|
||||
}
|
||||
myCalendars.forEach(function (id) {
|
||||
makeCalendarEntry(id, 1);
|
||||
});
|
||||
Object.keys(privateData.teams).forEach(function (teamId) {
|
||||
var calendars = filter(teamId);
|
||||
if (!calendars.length) { return; }
|
||||
var team = privateData.teams[teamId];
|
||||
var avatar = h('span.cp-avatar');
|
||||
common.displayAvatar($(avatar), team.avatar, team.displayName);
|
||||
APP.$calendars.append(h('div.cp-calendar-team', [
|
||||
avatar,
|
||||
h('span.cp-name', {title: team.name}, team.name)
|
||||
]));
|
||||
calendars.forEach(function (id) {
|
||||
makeCalendarEntry(id, teamId);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1350,13 +1350,20 @@ define([
|
|||
var $innerblock = $('<div>', {'class': 'cp-dropdown-content'});
|
||||
if (config.left) { $innerblock.addClass('cp-dropdown-left'); }
|
||||
|
||||
var hide = function () {
|
||||
window.setTimeout(function () { $innerblock.hide(); }, 0);
|
||||
};
|
||||
|
||||
config.options.forEach(function (o) {
|
||||
if (!isValidOption(o)) { return; }
|
||||
if (isElement(o)) { return $innerblock.append($(o)); }
|
||||
var $el = $('<' + o.tag + '>', o.attributes || {}).html(o.content || '');
|
||||
$el.appendTo($innerblock);
|
||||
if (typeof(o.action) === 'function') {
|
||||
$el.click(o.action);
|
||||
$el.click(function (e) {
|
||||
var close = o.action(e);
|
||||
if (close) { hide(); }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1376,10 +1383,6 @@ define([
|
|||
}
|
||||
};
|
||||
|
||||
var hide = function () {
|
||||
window.setTimeout(function () { $innerblock.hide(); }, 0);
|
||||
};
|
||||
|
||||
var show = function () {
|
||||
var wh = $(window).height();
|
||||
var button = $button[0].getBoundingClientRect();
|
||||
|
|
|
@ -111,6 +111,7 @@ define([
|
|||
password: config.password,
|
||||
isTemplate: config.isTemplate,
|
||||
name: myName,
|
||||
isCalendar: Boolean(config.calendar),
|
||||
title: title
|
||||
}, {
|
||||
viewed: team && team.id,
|
||||
|
@ -122,6 +123,19 @@ define([
|
|||
}
|
||||
// If it's a team with edit right, add the pad directly
|
||||
if (!team) { return; }
|
||||
if (config.calendar) {
|
||||
var calendarModule = common.makeUniversal('calendar');
|
||||
var calendarData = config.calendar;
|
||||
calendarData.href = href;
|
||||
calendarData.teamId = team.id;
|
||||
calendarModule.execCommand('ADD', calendarData, function (obj) {
|
||||
if (obj && obj.error) {
|
||||
console.error(obj.error);
|
||||
return void UI.warn(Messages.error);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
sframeChan.query('Q_STORE_IN_TEAM', {
|
||||
href: href,
|
||||
password: config.password,
|
||||
|
|
|
@ -2670,6 +2670,7 @@ define([
|
|||
}, true);
|
||||
}).nThen(function (waitFor) {
|
||||
loadUniversal(Team, 'team', waitFor, clientId);
|
||||
}).nThen(function (waitFor) {
|
||||
loadUniversal(Calendar, 'calendar', waitFor);
|
||||
}).nThen(function () {
|
||||
cb();
|
||||
|
|
|
@ -102,7 +102,8 @@ ctx.calendars[channel] = {
|
|||
deleted: !c.stores.length,
|
||||
restricted: c.restricted,
|
||||
owned: ctx.Store.isOwned(c.owners),
|
||||
content: Util.clone(c.proxy)
|
||||
content: Util.clone(c.proxy),
|
||||
hashes: c.hashes
|
||||
}, ctx.clients);
|
||||
};
|
||||
|
||||
|
@ -127,14 +128,21 @@ ctx.calendars[channel] = {
|
|||
if (!channel) { return; }
|
||||
|
||||
var c = ctx.calendars[channel];
|
||||
|
||||
var update = function () {
|
||||
sendUpdate(ctx, c);
|
||||
};
|
||||
|
||||
if (c) {
|
||||
if (c.stores && c.stores.indexOf(teamId) !== -1) { return; }
|
||||
if (c.readOnly && data.href) {
|
||||
// XXX UPGRADE
|
||||
// c.hashes.editHash =
|
||||
// XXX different cases if already ready or not?
|
||||
}
|
||||
if (c.stores && c.stores.indexOf(teamId) !== -1) { return void cb(); }
|
||||
c.stores.push(teamId);
|
||||
return;
|
||||
update();
|
||||
return void cb();
|
||||
}
|
||||
|
||||
// Multiple teams can have the same calendar. Make sure we remember the list of stores
|
||||
|
@ -143,12 +151,8 @@ ctx.calendars[channel] = {
|
|||
ready: false,
|
||||
channel: channel,
|
||||
readOnly: !data.href,
|
||||
stores: [teamId]
|
||||
};
|
||||
|
||||
var update = function () {
|
||||
console.log(ctx.clients);
|
||||
sendUpdate(ctx, c);
|
||||
stores: [teamId],
|
||||
hashes: {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -156,6 +160,11 @@ ctx.calendars[channel] = {
|
|||
var secret = Hash.getSecrets('calendar', parsed.hash);
|
||||
var crypto = Crypto.createEncryptor(secret.keys);
|
||||
|
||||
c.hashes.viewHash = Hash.getViewHashFromKeys(secret);
|
||||
if (data.href) {
|
||||
c.hashes.editHash = Hash.getEditHashFromKeys(secret);
|
||||
}
|
||||
|
||||
c.proxy = {
|
||||
metadata: {
|
||||
color: data.color,
|
||||
|
@ -290,6 +299,14 @@ ctx.calendars[channel] = {
|
|||
|
||||
// Personal drive
|
||||
findFromStore(ctx.store);
|
||||
|
||||
var teams = ctx.store.modules.team && ctx.store.modules.team.getTeamsData();
|
||||
if (!teams) { return; }
|
||||
Object.keys(teams).forEach(function (id) {
|
||||
var store = getStore(ctx, id);
|
||||
console.log(store);
|
||||
findFromStore(store);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
@ -308,6 +325,44 @@ ctx.calendars[channel] = {
|
|||
});
|
||||
};
|
||||
|
||||
var addCalendar = function (ctx, data, cId, cb) {
|
||||
var store = getStore(ctx, data.teamId);
|
||||
if (!store) { return void cb({error: "NO_STORE"}); }
|
||||
// Check team edit rights: viewers in teams don't have rpc
|
||||
if (!store.rpc) { return void cb({error: "EFORBIDDEN"}); }
|
||||
|
||||
var c = store.proxy.calendars = store.proxy.calendars || {};
|
||||
var parsed = Hash.parsePadUrl(data.href);
|
||||
var secret = Hash.getSecrets(parsed.type, parsed.hash, data.password);
|
||||
|
||||
var cal = {
|
||||
href: Hash.getEditHashFromKeys(secret),
|
||||
roHref: Hash.getViewHashFromKeys(secret),
|
||||
color: data.color,
|
||||
title: data.title,
|
||||
channel: data.channel
|
||||
};
|
||||
cal.color = data.color;
|
||||
cal.title = data.title;
|
||||
openChannel(ctx, {
|
||||
storeId: store.id || 1,
|
||||
data: cal,
|
||||
isNew: true
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
// Can't open this channel, don't store it
|
||||
console.error(err);
|
||||
return void cb({error: err.error})
|
||||
}
|
||||
// Add the calendar and call back
|
||||
c[cal.channel] = cal;
|
||||
var pin = store.pin || ctx.pinPads;
|
||||
pin([cal.channel], function (res) {
|
||||
if (res && res.error) { console.error(res.error); }
|
||||
});
|
||||
ctx.Store.onSync(store.id, cb);
|
||||
});
|
||||
};
|
||||
var createCalendar = function (ctx, data, cId, cb) {
|
||||
var store = getStore(ctx, data.teamId);
|
||||
if (!store) { return void cb({error: "NO_STORE"}); }
|
||||
|
@ -322,7 +377,7 @@ ctx.calendars[channel] = {
|
|||
storeId: store.id || 1,
|
||||
data: cal,
|
||||
isNew: true
|
||||
}, function (err, proxy) {
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
// Can't open this channel, don't store it
|
||||
console.error(err);
|
||||
|
@ -460,6 +515,10 @@ ctx.calendars[channel] = {
|
|||
if (cmd === 'SUBSCRIBE') {
|
||||
return void subscribe(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'ADD') {
|
||||
if (ctx.store.offline) { return void cb({error: 'OFFLINE'}); }
|
||||
return void addCalendar(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'CREATE') {
|
||||
if (ctx.store.offline) { return void cb({error: 'OFFLINE'}); }
|
||||
return void createCalendar(ctx, data, clientId, cb);
|
||||
|
|
Loading…
Reference in New Issue