Share calendar with a team

This commit is contained in:
yflory 2021-04-06 17:25:18 +02:00
parent 1a3ab6fed8
commit 9ae482b744
6 changed files with 184 additions and 22 deletions

View file

@ -1,6 +1,7 @@
@import (reference) '../../customize/src/less2/include/framework.less'; @import (reference) '../../customize/src/less2/include/framework.less';
@import (reference) '../../customize/src/less2/include/sidebar-layout.less'; @import (reference) '../../customize/src/less2/include/sidebar-layout.less';
@import (reference) '../../customize/src/less2/include/tools.less'; @import (reference) '../../customize/src/less2/include/tools.less';
@import (reference) '../../customize/src/less2/include/avatar.less';
&.cp-app-calendar { &.cp-app-calendar {
@ -104,6 +105,22 @@
} }
.cp-calendar-list { .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 { .cp-calendar-entry {
display: flex; display: flex;
align-items: center; align-items: center;

View file

@ -16,6 +16,10 @@ define([
'/customize/application_config.js', '/customize/application_config.js',
'/lib/calendar/tui-calendar.min.js', '/lib/calendar/tui-calendar.min.js',
'/common/inner/share.js',
'/common/inner/access.js',
'/common/inner/properties.js',
'/common/jscolor.js', '/common/jscolor.js',
'css!/lib/calendar/tui-calendar.min.css', 'css!/lib/calendar/tui-calendar.min.css',
'css!/bower_components/components-font-awesome/css/font-awesome.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
@ -36,7 +40,8 @@ define([
h, h,
Messages, Messages,
AppConfig, AppConfig,
Calendar Calendar,
Share, Access, Properties
) )
{ {
var APP = window.APP = { 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_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_deleteOwned = " It will still be visible for the users it has been shared with.";
Messages.calendar_errorNoCalendar = "No editable calendar selected!"; Messages.calendar_errorNoCalendar = "No editable calendar selected!";
Messages.calendar_myCalendars = "My calendars";
var onCalendarsUpdate = Util.mkEvent(); var onCalendarsUpdate = Util.mkEvent();
@ -310,6 +316,36 @@ Messages.calendar_errorNoCalendar = "No editable calendar selected!";
action: function (e) { action: function (e) {
e.stopPropagation(); e.stopPropagation();
editCalendar(id); 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', tag: 'a',
@ -361,7 +397,9 @@ Messages.calendar_errorNoCalendar = "No editable calendar selected!";
var md = Util.find(data, ['content', 'metadata']); var md = Util.find(data, ['content', 'metadata']);
if (!md) { return; } if (!md) { return; }
var active = data.hidden ? '' : '.cp-active'; 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', { h('span.cp-calendar-color', {
style: 'background-color: '+md.color+';' style: 'background-color: '+md.color+';'
}), }),
@ -370,7 +408,12 @@ Messages.calendar_errorNoCalendar = "No editable calendar selected!";
]); ]);
$(calendar).click(function () { $(calendar).click(function () {
data.hidden = !data.hidden; 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(); renderCalendar();
}); });
if (APP.$calendars) { APP.$calendars.append(calendar); } 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); var $calendars = APP.$calendars = $(calendars).appendTo($container);
onCalendarsUpdate.reg(function () { onCalendarsUpdate.reg(function () {
$calendars.empty(); $calendars.empty();
Object.keys(APP.calendars || {}).forEach(function (id) { var metadataMgr = common.getMetadataMgr();
var cal = APP.calendars[id]; var privateData = metadataMgr.getPrivateData();
if (!cal) { return; } var filter = function (teamId) {
(cal.teams || []).forEach(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); makeCalendarEntry(id, teamId);
}); });
}); });

View file

@ -1350,13 +1350,20 @@ define([
var $innerblock = $('<div>', {'class': 'cp-dropdown-content'}); var $innerblock = $('<div>', {'class': 'cp-dropdown-content'});
if (config.left) { $innerblock.addClass('cp-dropdown-left'); } if (config.left) { $innerblock.addClass('cp-dropdown-left'); }
var hide = function () {
window.setTimeout(function () { $innerblock.hide(); }, 0);
};
config.options.forEach(function (o) { config.options.forEach(function (o) {
if (!isValidOption(o)) { return; } if (!isValidOption(o)) { return; }
if (isElement(o)) { return $innerblock.append($(o)); } if (isElement(o)) { return $innerblock.append($(o)); }
var $el = $('<' + o.tag + '>', o.attributes || {}).html(o.content || ''); var $el = $('<' + o.tag + '>', o.attributes || {}).html(o.content || '');
$el.appendTo($innerblock); $el.appendTo($innerblock);
if (typeof(o.action) === 'function') { 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 show = function () {
var wh = $(window).height(); var wh = $(window).height();
var button = $button[0].getBoundingClientRect(); var button = $button[0].getBoundingClientRect();

View file

@ -111,6 +111,7 @@ define([
password: config.password, password: config.password,
isTemplate: config.isTemplate, isTemplate: config.isTemplate,
name: myName, name: myName,
isCalendar: Boolean(config.calendar),
title: title title: title
}, { }, {
viewed: team && team.id, viewed: team && team.id,
@ -122,6 +123,19 @@ define([
} }
// If it's a team with edit right, add the pad directly // If it's a team with edit right, add the pad directly
if (!team) { return; } 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', { sframeChan.query('Q_STORE_IN_TEAM', {
href: href, href: href,
password: config.password, password: config.password,

View file

@ -2670,6 +2670,7 @@ define([
}, true); }, true);
}).nThen(function (waitFor) { }).nThen(function (waitFor) {
loadUniversal(Team, 'team', waitFor, clientId); loadUniversal(Team, 'team', waitFor, clientId);
}).nThen(function (waitFor) {
loadUniversal(Calendar, 'calendar', waitFor); loadUniversal(Calendar, 'calendar', waitFor);
}).nThen(function () { }).nThen(function () {
cb(); cb();

View file

@ -102,7 +102,8 @@ ctx.calendars[channel] = {
deleted: !c.stores.length, deleted: !c.stores.length,
restricted: c.restricted, restricted: c.restricted,
owned: ctx.Store.isOwned(c.owners), owned: ctx.Store.isOwned(c.owners),
content: Util.clone(c.proxy) content: Util.clone(c.proxy),
hashes: c.hashes
}, ctx.clients); }, ctx.clients);
}; };
@ -127,14 +128,21 @@ ctx.calendars[channel] = {
if (!channel) { return; } if (!channel) { return; }
var c = ctx.calendars[channel]; var c = ctx.calendars[channel];
var update = function () {
sendUpdate(ctx, c);
};
if (c) { if (c) {
if (c.stores && c.stores.indexOf(teamId) !== -1) { return; }
if (c.readOnly && data.href) { if (c.readOnly && data.href) {
// XXX UPGRADE // XXX UPGRADE
// c.hashes.editHash =
// XXX different cases if already ready or not? // XXX different cases if already ready or not?
} }
if (c.stores && c.stores.indexOf(teamId) !== -1) { return void cb(); }
c.stores.push(teamId); c.stores.push(teamId);
return; update();
return void cb();
} }
// Multiple teams can have the same calendar. Make sure we remember the list of stores // Multiple teams can have the same calendar. Make sure we remember the list of stores
@ -143,12 +151,8 @@ ctx.calendars[channel] = {
ready: false, ready: false,
channel: channel, channel: channel,
readOnly: !data.href, readOnly: !data.href,
stores: [teamId] stores: [teamId],
}; hashes: {}
var update = function () {
console.log(ctx.clients);
sendUpdate(ctx, c);
}; };
@ -156,6 +160,11 @@ ctx.calendars[channel] = {
var secret = Hash.getSecrets('calendar', parsed.hash); var secret = Hash.getSecrets('calendar', parsed.hash);
var crypto = Crypto.createEncryptor(secret.keys); var crypto = Crypto.createEncryptor(secret.keys);
c.hashes.viewHash = Hash.getViewHashFromKeys(secret);
if (data.href) {
c.hashes.editHash = Hash.getEditHashFromKeys(secret);
}
c.proxy = { c.proxy = {
metadata: { metadata: {
color: data.color, color: data.color,
@ -290,6 +299,14 @@ ctx.calendars[channel] = {
// Personal drive // Personal drive
findFromStore(ctx.store); 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 createCalendar = function (ctx, data, cId, cb) {
var store = getStore(ctx, data.teamId); var store = getStore(ctx, data.teamId);
if (!store) { return void cb({error: "NO_STORE"}); } if (!store) { return void cb({error: "NO_STORE"}); }
@ -322,7 +377,7 @@ ctx.calendars[channel] = {
storeId: store.id || 1, storeId: store.id || 1,
data: cal, data: cal,
isNew: true isNew: true
}, function (err, proxy) { }, function (err) {
if (err) { if (err) {
// Can't open this channel, don't store it // Can't open this channel, don't store it
console.error(err); console.error(err);
@ -460,6 +515,10 @@ ctx.calendars[channel] = {
if (cmd === 'SUBSCRIBE') { if (cmd === 'SUBSCRIBE') {
return void subscribe(ctx, data, clientId, cb); 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 (cmd === 'CREATE') {
if (ctx.store.offline) { return void cb({error: 'OFFLINE'}); } if (ctx.store.offline) { return void cb({error: 'OFFLINE'}); }
return void createCalendar(ctx, data, clientId, cb); return void createCalendar(ctx, data, clientId, cb);