diff --git a/customize.dist/pages/features.js b/customize.dist/pages/features.js
index 1dfd2417f..bf8115ff6 100644
--- a/customize.dist/pages/features.js
+++ b/customize.dist/pages/features.js
@@ -13,6 +13,7 @@ define([
return function () {
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; }
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 ac37ac104..7e2f980e5 100644
--- a/customize.dist/pages/index.js
+++ b/customize.dist/pages/index.js
@@ -5,12 +5,13 @@ define([
'/common/common-feedback.js',
'/common/common-interface.js',
'/common/common-hash.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, TextFit, Msg, AppConfig, LocalStore, Pages) {
+], function ($, Config, h, Feedback, UI, Hash, Util, TextFit, Msg, AppConfig, LocalStore, Pages) {
var urlArgs = Config.requireConf.urlArgs;
var isAvailableType = function (x) {
@@ -18,6 +19,12 @@ define([
return AppConfig.availablePadTypes.indexOf(x) !== -1;
};
+
+ // XXX PREMIUM
+ var checkPremium = function (x) {
+ return Util.checkPremiumApp(x, AppConfig.premiumTypes,
+ LocalStore.getPremium(), LocalStore.isLoggedIn());
+ };
var checkRegisteredType = function (x) {
// Return true if we're registered or if the app is not registeredOnly
if (LocalStore.isLoggedIn()) { return true; }
@@ -31,6 +38,8 @@ define([
[ 'code', Msg.type.code],
[ 'slide', Msg.type.slide],
[ 'sheet', Msg.type.sheet],
+ [ 'doc', Msg.type.doc],
+ [ 'presentation', Msg.type.presentation],
[ 'form', Msg.type.form],
[ 'kanban', Msg.type.kanban],
[ 'whiteboard', Msg.type.whiteboard],
@@ -40,7 +49,9 @@ define([
})
.map(function (x) {
var s = 'div.bs-callout.cp-callout-' + x[0];
+ var cls = '';
var isEnabled = checkRegisteredType(x[0]);
+ var isPremium = checkPremium(x[0]);
//if (i > 2) { s += '.cp-more.cp-hidden'; }
var icon = AppConfig.applicationsIcon[x[0]];
var font = icon.indexOf('cptools') === 0 ? 'cptools' : 'fa';
@@ -52,11 +63,16 @@ define([
window.location.href = url;
}
};
+ if (isPremium === -1) {
+ cls += '.cp-app-hidden.cp-app-disabled';
+ } else if (isPremium === 0) {
+ cls += '.cp-app-disabled';
+ }
if (!isEnabled) {
- s += '.cp-app-disabled';
+ cls += '.cp-app-disabled';
attr.title = Msg.mustLogin;
}
- return h('a', [
+ return h('a.cp-index-appitem' + cls, [
attr,
h(s, [
h('i.' + font + '.' + icon, {'aria-hidden': 'true'}),
diff --git a/customize.dist/src/less2/include/contextmenu.less b/customize.dist/src/less2/include/contextmenu.less
index 09b26dda9..1c6912f6e 100644
--- a/customize.dist/src/less2/include/contextmenu.less
+++ b/customize.dist/src/less2/include/contextmenu.less
@@ -59,6 +59,11 @@
color: @cp_context-icon;
width: 16px;
}
+ // XXX PREMIUM
+ &.cp-app-disabled {
+ cursor: not-allowed !important;
+ opacity: 0.5;
+ }
}
}
.cp-app-drive-context-noAction {
diff --git a/customize.dist/src/less2/include/drive.less b/customize.dist/src/less2/include/drive.less
index 5feb22ca3..9e2cb76b8 100644
--- a/customize.dist/src/less2/include/drive.less
+++ b/customize.dist/src/less2/include/drive.less
@@ -80,6 +80,15 @@
display: none;
}
}
+
+ // XXX PREMIUM
+ &.cp-app-hidden {
+ display: none;
+ }
+ &.cp-app-disabled {
+ cursor: not-allowed !important;
+ opacity: 0.5;
+ }
}
}
diff --git a/customize.dist/src/less2/include/dropdown.less b/customize.dist/src/less2/include/dropdown.less
index ddba87cd7..a7c810692 100644
--- a/customize.dist/src/less2/include/dropdown.less
+++ b/customize.dist/src/less2/include/dropdown.less
@@ -120,6 +120,15 @@
background-color: @cp_dropdown-bg-active;
color: @cp_dropdown-fg;
}
+
+ // XXX PREMIUM
+ &.cp-app-hidden {
+ display: none;
+ }
+ &.cp-app-disabled {
+ cursor: not-allowed !important;
+ opacity: 0.5;
+ }
}
&> span {
box-sizing: border-box;
diff --git a/customize.dist/src/less2/include/icons.less b/customize.dist/src/less2/include/icons.less
index 6c05803c7..501980c83 100644
--- a/customize.dist/src/less2/include/icons.less
+++ b/customize.dist/src/less2/include/icons.less
@@ -38,5 +38,14 @@
display: none;
}
}
+
+ // XXX PREMIUM
+ &.cp-app-hidden {
+ display: none;
+ }
+ &.cp-app-disabled {
+ cursor: not-allowed !important;
+ opacity: 0.5;
+ }
}
}
diff --git a/customize.dist/src/less2/pages/page-index.less b/customize.dist/src/less2/pages/page-index.less
index 8c5fdc164..41a3014c7 100644
--- a/customize.dist/src/less2/pages/page-index.less
+++ b/customize.dist/src/less2/pages/page-index.less
@@ -118,15 +118,23 @@
padding: 10px 10px 0px 10px;
//height: @icons-size - @icons-text-size;
}
- &.cp-app-disabled {
- cursor: not-allowed !important;
- opacity: 0.5;
- }
.pad-button-text {
color: @cryptpad_text_col;
padding: 5px;
}
}
+ .cp-index-appitem {
+ // XXX PREMIUM
+ &.cp-app-hidden {
+ display: none;
+ }
+ &.cp-app-disabled {
+ div {
+ cursor: not-allowed !important;
+ }
+ opacity: 0.5;
+ }
+ }
h4 {
margin: 0;
}
diff --git a/www/common/common-constants.js b/www/common/common-constants.js
index fd4d1474b..5f0f59be6 100644
--- a/www/common/common-constants.js
+++ b/www/common/common-constants.js
@@ -11,6 +11,7 @@ define(['/customize/application_config.js'], function (AppConfig) {
storageKey: 'filesData',
tokenKey: 'loginToken',
prefersDriveRedirectKey: 'prefersDriveRedirect',
+ isPremiumKey: 'isPremiumUser',
displayPadCreationScreen: 'displayPadCreationScreen',
deprecatedKey: 'deprecated',
MAX_TEAMS_SLOTS: AppConfig.maxTeamsSlots || 5,
diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js
index 4be00efec..f7ad0220a 100644
--- a/www/common/common-ui-elements.js
+++ b/www/common/common-ui-elements.js
@@ -2087,6 +2087,7 @@ define([
};
+
UIElements.createNewPadModal = function (common) {
// if in drive, show new pad modal instead
if ($(".cp-app-drive-element-row.cp-app-drive-new-ghost").length !== 0) {
@@ -2113,6 +2114,9 @@ define([
AppConfig.registeredOnlyTypes.indexOf(p) !== -1) { return; }
return true;
});
+
+ var priv = common.getMetadataMgr().getPrivateData();
+
types.forEach(function (p) {
var $element = $('
', {
'class': 'cp-icons-element',
@@ -2125,6 +2129,13 @@ define([
$modal.hide();
common.openURL('/' + p + '/');
});
+ // XXX PREMIUM
+ var premium = Util.checkPremiumApp(p, AppConfig.premiumTypes, priv.plan, priv.loggedIn);
+ if (premium === -1) {
+ $element.addClass('cp-app-hidden cp-app-disabled');
+ } else if (premium === 0) {
+ $element.addClass('cp-app-disabled');
+ }
});
var selected = -1;
diff --git a/www/common/common-util.js b/www/common/common-util.js
index e70f4747e..47359232b 100644
--- a/www/common/common-util.js
+++ b/www/common/common-util.js
@@ -638,6 +638,17 @@
getColor().toString(16);
};
+ Util.checkPremiumApp = function (app, premiumTypes, plan, loggedIn) {
+ // 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 (!loggedIn) { return -1; }
+ // if you're logged in, enable it only if you're a premium user
+ return plan ? 1 : 0;
+
+ };
+
/* Chrome 92 dropped support for SharedArrayBuffer in cross-origin contexts
where window.crossOriginIsolated is false.
diff --git a/www/common/drive-ui.js b/www/common/drive-ui.js
index 165ac7b02..dfcfe6da2 100644
--- a/www/common/drive-ui.js
+++ b/www/common/drive-ui.js
@@ -338,7 +338,11 @@ define([
Messages.fc_openInSheet = "Edit in Sheet"; // XXX
Messages.fc_openInDoc = "Edit in Document"; // XXX
Messages.fc_openInPresentation = "Edit in Presentation"; // XXX
- var createContextMenu = function () {
+ var createContextMenu = function (priv) {
+ // 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 menu = h('div.cp-contextmenu.dropdown.cp-unselectable', [
h('ul.dropdown-menu', {
'role': 'menu',
@@ -366,11 +370,11 @@ define([
'tabindex': '-1',
'data-icon': faOpenInSheet,
}, Messages.fc_openInSheet)),
- h('li', h('a.cp-app-drive-context-openindoc.dropdown-item', {
+ premiumD === -1 ? undefined : h('li', h('a.cp-app-drive-context-openindoc.dropdown-item' + (premiumD === 0 ? '.cp-app-disabled' : ''), {
'tabindex': '-1',
'data-icon': faOpenInDoc,
}, Messages.fc_openInDoc)),
- h('li', h('a.cp-app-drive-context-openinpresentation.dropdown-item', {
+ premiumP === -1 ? undefined : h('li', h('a.cp-app-drive-context-openinpresentation.dropdown-item' + (premiumP === 0 ? '.cp-app-disabled' : ''), {
'tabindex': '-1',
'data-icon': faOpenInPresentation,
}, Messages.fc_openInPresentation)),
@@ -446,6 +450,16 @@ define([
'data-icon': AppConfig.applicationsIcon.sheet,
'data-type': 'sheet'
}, Messages.button_newsheet)),
+ premiumD === -1 ? undefined : h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable' + (premiumD === 0 ? '.cp-app-disabled' : ''), {
+ 'tabindex': '-1',
+ 'data-icon': AppConfig.applicationsIcon.doc,
+ 'data-type': 'doc'
+ }, Messages.button_newdoc)),
+ premiumP === -1 ? undefined : h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable' + (premiumP === 0 ? '.cp-app-disabled' : ''), {
+ 'tabindex': '-1',
+ 'data-icon': AppConfig.applicationsIcon.presentation,
+ 'data-type': 'presentation'
+ }, Messages.button_newpresentation)),
h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', {
'tabindex': '-1',
'data-icon': AppConfig.applicationsIcon.whiteboard,
@@ -631,7 +645,7 @@ define([
var $content = APP.$content = $("#cp-app-drive-content");
var $appContainer = $(".cp-app-drive-container");
var $driveToolbar = APP.toolbar.$bottom;
- var $contextMenu = createContextMenu().appendTo($appContainer);
+ var $contextMenu = createContextMenu(priv).appendTo($appContainer);
var $contentContextMenu = $("#cp-app-drive-context-content");
var $defaultContextMenu = $("#cp-app-drive-context-default");
@@ -2929,6 +2943,15 @@ define([
'data-type': type,
'href': '#'
};
+
+ // XXX PREMIUM
+ var premium = Util.checkPremiumApp(type, AppConfig.premiumTypes, priv.plan, priv.loggedIn);
+ if (premium === -1) {
+ attributes.class += ' cp-app-hidden cp-app-disabled';
+ } else if (premium === 0) {
+ attributes.class += ' cp-app-disabled';
+ }
+
options.push({
tag: 'a',
attributes: attributes,
@@ -3255,6 +3278,14 @@ define([
$element.append($('', {'class': 'cp-app-drive-new-name'})
.text(Messages.type[type]));
$element.attr('data-type', type);
+
+ // XXX PREMIUM
+ var premium = Util.checkPremiumApp(type, AppConfig.premiumTypes, priv.plan, priv.loggedIn);
+ if (premium === -1) {
+ $element.addClass('cp-app-hidden cp-app-disabled');
+ } else if (premium === 0) {
+ $element.addClass('cp-app-disabled');
+ }
});
$container.find('.cp-app-drive-element-row').click(function () {
diff --git a/www/common/outer/local-store.js b/www/common/outer/local-store.js
index 77d36645c..5d6f2e0ff 100644
--- a/www/common/outer/local-store.js
+++ b/www/common/outer/local-store.js
@@ -90,6 +90,15 @@ define([
localStorage.setItem(Constants.redirectToDriveKey, Boolean(bool));
};
+ LocalStore.getPremium = function () {
+ try {
+ return JSON.parse(localStorage[Constants.isPremiumKey]);
+ } catch (err) { return; }
+ };
+ LocalStore.setPremium = function (bool) {
+ localStorage.setItem(Constants.isPremiumKey, Boolean(bool));
+ };
+
LocalStore.login = function (hash, name, cb) {
if (!hash) { throw new Error('expected a user hash'); }
if (!name) { throw new Error('expected a user name'); }
diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js
index bce02657b..f90728ade 100644
--- a/www/common/sframe-common-outer.js
+++ b/www/common/sframe-common-outer.js
@@ -664,6 +664,13 @@ define([
additionalPriv.registeredOnly = true;
}
+ // XXX PREMIUM
+ var priv = metaObj.priv;
+ var p = Utils.Util.checkPremiumApp(parsed.type, AppConfig.premiumTypes, priv.plan, additionalPriv.loggedIn);
+ if (p === 0 || p === -1) {
+ additionalPriv.premiumOnly = true;
+ }
+
if (isSafe) {
additionalPriv.hashes = hashes;
additionalPriv.password = password;
@@ -675,6 +682,10 @@ define([
cfg.addData(metaObj.priv, Cryptpad, metaObj.user, Utils);
}
+ if (metaObj && metaObj.priv && typeof(metaObj.priv.plan) === "string") {
+ Utils.LocalStore.setPremium(metaObj.priv.plan);
+ }
+
sframeChan.event('EV_METADATA_UPDATE', metaObj);
});
};
diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js
index b7efd9f4f..ecd4f094e 100644
--- a/www/common/sframe-common.js
+++ b/www/common/sframe-common.js
@@ -907,6 +907,15 @@ define([
}, {forefront: true});
return;
}
+ // XXX PREMIUM
+ Messages.premiumOnly = "Premium only for now..."; // XXX
+ var blocked = privateData.premiumOnly && privateData.isNewFile;
+ if (blocked) {
+ UI.alert(Messages.premiumOnly, function () {
+ funcs.gotoURL('/drive/');
+ }, {forefront: true});
+ return;
+ }
} catch (e) {
console.error("Can't check permissions for the app");
}