From 9ae482b744fab0a058c0a6628910c341cfdcb14f Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 6 Apr 2021 17:25:18 +0200 Subject: [PATCH] Share calendar with a team --- www/calendar/app-calendar.less | 17 +++++++ www/calendar/inner.js | 82 +++++++++++++++++++++++++++++--- www/common/common-ui-elements.js | 13 +++-- www/common/inner/share.js | 14 ++++++ www/common/outer/async-store.js | 1 + www/common/outer/calendar.js | 79 ++++++++++++++++++++++++++---- 6 files changed, 184 insertions(+), 22 deletions(-) diff --git a/www/calendar/app-calendar.less b/www/calendar/app-calendar.less index 38aee3973..69be43ab6 100644 --- a/www/calendar/app-calendar.less +++ b/www/calendar/app-calendar.less @@ -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; diff --git a/www/calendar/inner.js b/www/calendar/inner.js index 660b8f2a1..f51fc240a 100644 --- a/www/calendar/inner.js +++ b/www/calendar/inner.js @@ -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); }); }); diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index 92ecb4b4e..6c6c51c26 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -1350,13 +1350,20 @@ define([ var $innerblock = $('
', {'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(); diff --git a/www/common/inner/share.js b/www/common/inner/share.js index 614fc23e7..f47fe5add 100644 --- a/www/common/inner/share.js +++ b/www/common/inner/share.js @@ -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, diff --git a/www/common/outer/async-store.js b/www/common/outer/async-store.js index 6ce036e53..5c7f3623c 100644 --- a/www/common/outer/async-store.js +++ b/www/common/outer/async-store.js @@ -2670,6 +2670,7 @@ define([ }, true); }).nThen(function (waitFor) { loadUniversal(Team, 'team', waitFor, clientId); + }).nThen(function (waitFor) { loadUniversal(Calendar, 'calendar', waitFor); }).nThen(function () { cb(); diff --git a/www/common/outer/calendar.js b/www/common/outer/calendar.js index a5d4b91a6..cc17ca674 100644 --- a/www/common/outer/calendar.js +++ b/www/common/outer/calendar.js @@ -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);