diff --git a/customize.dist/pages/features.js b/customize.dist/pages/features.js index bf8115ff6..d84b2be0b 100644 --- a/customize.dist/pages/features.js +++ b/customize.dist/pages/features.js @@ -14,6 +14,8 @@ define([ Msg.features_f_apps_note = AppConfig.availablePadTypes.map(function (app) { if (AppConfig.registeredOnlyTypes.indexOf(app) !== -1) { return; } if (AppConfig.premiumTypes && AppConfig.premiumTypes.includes(app)) { return; } + if (Constants.earlyAccessApps && Constants.earlyAccessApps.includes(app) && + AppConfig.enableEarlyAccess) { return; } return Msg.type[app]; }).filter(function (x) { return x; }).join(', '); var premiumButton = h('a', { diff --git a/customize.dist/pages/index.js b/customize.dist/pages/index.js index 7e2f980e5..c5463e904 100644 --- a/customize.dist/pages/index.js +++ b/customize.dist/pages/index.js @@ -5,13 +5,14 @@ define([ '/common/common-feedback.js', '/common/common-interface.js', '/common/common-hash.js', + '/common/common-constants.js', '/common/common-util.js', '/lib/textFit.min.js', '/customize/messages.js', '/customize/application_config.js', '/common/outer/local-store.js', '/customize/pages.js' -], function ($, Config, h, Feedback, UI, Hash, Util, TextFit, Msg, AppConfig, LocalStore, Pages) { +], function ($, Config, h, Feedback, UI, Hash, Constants, Util, TextFit, Msg, AppConfig, LocalStore, Pages) { var urlArgs = Config.requireConf.urlArgs; var isAvailableType = function (x) { @@ -21,9 +22,14 @@ define([ // XXX PREMIUM - var checkPremium = function (x) { - return Util.checkPremiumApp(x, AppConfig.premiumTypes, + var checkEarlyAccess = function (x) { + // Check if this is an early access app and if they are allowed. + // Check if this is a premium app and if you're premium + // Returns false if the app should be hidden + var earlyTypes = Constants.earlyAccessApps; + var ea = Util.checkRestrictedApp(x, AppConfig, earlyTypes, LocalStore.getPremium(), LocalStore.isLoggedIn()); + return ea > 0; }; var checkRegisteredType = function (x) { // Return true if we're registered or if the app is not registeredOnly @@ -51,7 +57,7 @@ define([ var s = 'div.bs-callout.cp-callout-' + x[0]; var cls = ''; var isEnabled = checkRegisteredType(x[0]); - var isPremium = checkPremium(x[0]); + var isEAEnabled = checkEarlyAccess(x[0]); //if (i > 2) { s += '.cp-more.cp-hidden'; } var icon = AppConfig.applicationsIcon[x[0]]; var font = icon.indexOf('cptools') === 0 ? 'cptools' : 'fa'; @@ -63,10 +69,8 @@ define([ window.location.href = url; } }; - if (isPremium === -1) { - cls += '.cp-app-hidden.cp-app-disabled'; - } else if (isPremium === 0) { - cls += '.cp-app-disabled'; + if (!isEAEnabled) { + cls += '.cp-app-hidden'; } if (!isEnabled) { cls += '.cp-app-disabled'; diff --git a/customize.dist/src/less2/include/drive.less b/customize.dist/src/less2/include/drive.less index c1b1ca3a7..304816f49 100644 --- a/customize.dist/src/less2/include/drive.less +++ b/customize.dist/src/less2/include/drive.less @@ -83,7 +83,7 @@ // XXX PREMIUM &.cp-app-hidden { - display: none; + display: none !important; } &.cp-app-disabled { cursor: not-allowed !important; diff --git a/customize.dist/src/less2/include/icons.less b/customize.dist/src/less2/include/icons.less index 11bd2d545..4ea81ca71 100644 --- a/customize.dist/src/less2/include/icons.less +++ b/customize.dist/src/less2/include/icons.less @@ -41,7 +41,7 @@ // XXX PREMIUM &.cp-app-hidden { - display: none; + display: none !important; } &.cp-app-disabled { cursor: not-allowed !important; diff --git a/www/common/application_config_internal.js b/www/common/application_config_internal.js index 4a58085ab..cc4eee764 100644 --- a/www/common/application_config_internal.js +++ b/www/common/application_config_internal.js @@ -11,8 +11,8 @@ define(function() { * redirected to the drive. * You should never remove the drive from this list. */ - AppConfig.availablePadTypes = ['drive', 'teams', 'pad', 'sheet', 'code', 'slide', 'poll', 'kanban', 'whiteboard', - /*'doc', 'presentation',*/ 'file', /*'todo',*/ 'contacts', 'form', 'convert']; + AppConfig.availablePadTypes = ['drive', 'teams', 'doc', 'sheet', 'presentation', 'pad', 'code', 'slide', 'poll', 'kanban', 'whiteboard', + 'file', 'contacts', 'form', 'convert']; /* The registered only types are apps restricted to registered users. * You should never remove apps from this list unless you know what you're doing. The apps * listed here by default can't work without a user account. @@ -22,6 +22,13 @@ define(function() { */ AppConfig.registeredOnlyTypes = ['file', 'contacts', 'notifications', 'support']; + /* New application may be introduced in an "early access" state which can contain + * bugs and can cause loss of user content. You can enable these applications on your + * CryptPad instance to test them and report bugs to the developers or keep them + * disable until they are officialy considered safe. + */ + AppConfig.enableEarlyAccess = false; + // to prevent apps that aren't officially supported from showing up // in the document creation modal AppConfig.hiddenTypes = ['drive', 'teams', 'contacts', 'todo', 'file', 'accounts', 'calendar', 'poll', 'convert', diff --git a/www/common/common-constants.js b/www/common/common-constants.js index 5f0f59be6..6be5d7552 100644 --- a/www/common/common-constants.js +++ b/www/common/common-constants.js @@ -17,6 +17,7 @@ define(['/customize/application_config.js'], function (AppConfig) { MAX_TEAMS_SLOTS: AppConfig.maxTeamsSlots || 5, MAX_TEAMS_OWNED: AppConfig.maxOwnedTeams || 5, // Apps - criticalApps: ['profile', 'settings', 'debug', 'admin', 'support', 'notifications', 'calendar'] + criticalApps: ['profile', 'settings', 'debug', 'admin', 'support', 'notifications', 'calendar'], + earlyAccessApps: ['doc', 'presentation'] }; }); diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js index f7ad0220a..d765236b7 100644 --- a/www/common/common-ui-elements.js +++ b/www/common/common-ui-elements.js @@ -2130,8 +2130,8 @@ define([ common.openURL('/' + p + '/'); }); // XXX PREMIUM - var premium = Util.checkPremiumApp(p, AppConfig.premiumTypes, priv.plan, priv.loggedIn); - if (premium === -1) { + var premium = common.checkRestrictedApp(p); + if (premium < 0) { $element.addClass('cp-app-hidden cp-app-disabled'); } else if (premium === 0) { $element.addClass('cp-app-disabled'); diff --git a/www/common/common-util.js b/www/common/common-util.js index 47359232b..efcb46227 100644 --- a/www/common/common-util.js +++ b/www/common/common-util.js @@ -638,11 +638,17 @@ getColor().toString(16); }; - Util.checkPremiumApp = function (app, premiumTypes, plan, loggedIn) { + Util.checkRestrictedApp = function (app, AppConfig, earlyTypes, plan, loggedIn) { + // If this is an early access app, make sure this instance allows them + if (Array.isArray(earlyTypes) && earlyTypes.includes(app) && !AppConfig.enableEarlyAccess) { + return -2; + } + + var premiumTypes = AppConfig.premiumTypes; // If this is not a premium app, don't disable it if (!Array.isArray(premiumTypes) || !premiumTypes.includes(app)) { return 2; } // This is a premium app - // if you're not logged in, disbale it + // if you're not logged in, disable it if (!loggedIn) { return -1; } // if you're logged in, enable it only if you're a premium user return plan ? 1 : 0; diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js index e1ddf2b26..33b763b2d 100644 --- a/www/common/drive-ui.js +++ b/www/common/drive-ui.js @@ -337,17 +337,15 @@ define([ Messages.fc_openIn = "Open in {0}"; // XXX // delete fc_openInCode // XXX - var createContextMenu = function (priv) { + var createContextMenu = function (common) { // XXX PREMIUM // XXX "Edit in Document" and "New Document" (and presentation) - var premiumP = Util.checkPremiumApp('presentation', AppConfig.premiumTypes, priv.plan, priv.loggedIn); - var premiumD = Util.checkPremiumApp('doc', AppConfig.premiumTypes, priv.plan, priv.loggedIn); + var premiumP = common.checkRestrictedApp('presentation'); + var premiumD = common.checkRestrictedApp('doc'); var getOpenIn = function (app) { var icon = AppConfig.applicationsIcon[app]; var cls = icon.indexOf('cptools') === 0 ? 'cptools '+icon : 'fa '+icon; var html = '' + Messages.type[app]; - console.error(html); - console.error(Messages._getKey('fc_openIn', [html])); return Messages._getKey('fc_openIn', [html]); }; var menu = h('div.cp-contextmenu.dropdown.cp-unselectable', [ @@ -377,11 +375,11 @@ define([ 'tabindex': '-1', 'data-icon': 'fa-arrows', }), getOpenIn('sheet'))), - premiumD === -1 ? undefined : h('li', UI.setHTML(h('a.cp-app-drive-context-openindoc.dropdown-item' + (premiumD === 0 ? '.cp-app-disabled' : ''), { + premiumD < 0 ? undefined : h('li', UI.setHTML(h('a.cp-app-drive-context-openindoc.dropdown-item' + (premiumD === 0 ? '.cp-app-disabled' : ''), { 'tabindex': '-1', 'data-icon': 'fa-arrows', }), getOpenIn('doc'))), - premiumP === -1 ? undefined : h('li', UI.setHTML(h('a.cp-app-drive-context-openinpresentation.dropdown-item' + (premiumP === 0 ? '.cp-app-disabled' : ''), { + premiumP < 0 ? undefined : h('li', UI.setHTML(h('a.cp-app-drive-context-openinpresentation.dropdown-item' + (premiumP === 0 ? '.cp-app-disabled' : ''), { 'tabindex': '-1', 'data-icon': 'fa-arrows', }), getOpenIn('presentation'))), @@ -652,7 +650,7 @@ define([ var $content = APP.$content = $("#cp-app-drive-content"); var $appContainer = $(".cp-app-drive-container"); var $driveToolbar = APP.toolbar.$bottom; - var $contextMenu = createContextMenu(priv).appendTo($appContainer); + var $contextMenu = createContextMenu(common).appendTo($appContainer); var $contentContextMenu = $("#cp-app-drive-context-content"); var $defaultContextMenu = $("#cp-app-drive-context-default"); @@ -2952,8 +2950,8 @@ define([ }; // XXX PREMIUM - var premium = Util.checkPremiumApp(type, AppConfig.premiumTypes, priv.plan, priv.loggedIn); - if (premium === -1) { + var premium = common.checkRestrictedApp(type); + if (premium < 0) { attributes.class += ' cp-app-hidden cp-app-disabled'; } else if (premium === 0) { attributes.class += ' cp-app-disabled'; @@ -3287,8 +3285,8 @@ define([ $element.attr('data-type', type); // XXX PREMIUM - var premium = Util.checkPremiumApp(type, AppConfig.premiumTypes, priv.plan, priv.loggedIn); - if (premium === -1) { + var premium = common.checkRestrictedApp(type); + if (premium < 0) { $element.addClass('cp-app-hidden cp-app-disabled'); } else if (premium === 0) { $element.addClass('cp-app-disabled'); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index f90728ade..0053de3a6 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -666,10 +666,14 @@ define([ // XXX PREMIUM var priv = metaObj.priv; - var p = Utils.Util.checkPremiumApp(parsed.type, AppConfig.premiumTypes, priv.plan, additionalPriv.loggedIn); + var p = Utils.Util.checkRestrictedApp(parsed.type, AppConfig, + Utils.Constants.earlyAccessApps, priv.plan, additionalPriv.loggedIn); if (p === 0 || p === -1) { additionalPriv.premiumOnly = true; } + if (p === -2) { + additionalPriv.earlyAccessBlocked = true; + } if (isSafe) { additionalPriv.hashes = hashes; diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index eb979d721..1d0b56d04 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -25,6 +25,7 @@ define([ '/common/common-interface.js', '/common/common-feedback.js', '/common/common-language.js', + '/common/common-constants.js', '/bower_components/localforage/dist/localforage.min.js', '/common/hyperscript.js', ], function ( @@ -53,6 +54,7 @@ define([ UI, Feedback, Language, + Constants, localForage, h ) { @@ -729,6 +731,12 @@ define([ ApiConfig.adminKeys.indexOf(privateData.edPublic) !== -1; }; + funcs.checkRestrictedApp = function (app) { + var ea = Constants.earlyAccessApps; + var priv = ctx.metadataMgr.getPrivateData(); + return Util.checkRestrictedApp(app, AppConfig, ea, priv.plan, priv.loggedIn); + }; + funcs.mailbox = {}; Object.freeze(funcs); @@ -918,6 +926,14 @@ define([ }, {forefront: true}); return; } + if (privateData.earlyAccessBlocked) { + Messages.earlyAccessBlocked = "This application is not ready yet, come back later."; // XXX + UI.errorLoadingScreen(Messages.earlyAccessBlocked, null, function () { + funcs.gotoURL('/drive/'); + }, {forefront: true}); + return; + + } } catch (e) { console.error("Can't check permissions for the app"); }