mirror of
https://github.com/cryptpad/cryptpad.git
synced 2026-09-12 19:49:59 +05:00
Merge branch 'badges' into modularize
This commit is contained in:
commit
900ab02404
@ -134,7 +134,12 @@ define(req, function(AppConfig, Default, Language) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// XXX
|
||||
Messages.badges_admin = "Instance administrator";
|
||||
Messages.badges_moderator = "Instance moderator";
|
||||
Messages.badges_premium = "Premium user";
|
||||
Messages.badges_error = "Error while validating this user's data";
|
||||
Messages.profile_badges = "Badges";
|
||||
|
||||
return Messages;
|
||||
|
||||
|
||||
28
customize.dist/src/less2/include/badges.less
Normal file
28
customize.dist/src/less2/include/badges.less
Normal file
@ -0,0 +1,28 @@
|
||||
@import (reference) "./colortheme-all.less";
|
||||
@import (reference) "./variables.less";
|
||||
.badges_vars(
|
||||
@width: 30px
|
||||
) {
|
||||
@badges-width: @width;
|
||||
}
|
||||
.badges_main(@width: 30px) {
|
||||
--LessLoader_require: LessLoader_currentFile();
|
||||
.badges_vars(@width);
|
||||
--badges-width: @badges-width;
|
||||
--badges-font: ceil(@badges-width*2/3);
|
||||
}
|
||||
& {
|
||||
.badges_vars();
|
||||
i.cp-badge {
|
||||
width: var(--badges-width);
|
||||
height: var(--badges-width);
|
||||
box-sizing: border-box;
|
||||
border: 1px solid @cryptpad_text_col;
|
||||
border-radius: 50%;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: var(--badges-font);
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,6 +263,14 @@
|
||||
.cp-toolbar-userlist-friend {
|
||||
padding: 0;
|
||||
}
|
||||
.cp-userlist-badge {
|
||||
i {
|
||||
color: @cryptpad_color_brand;
|
||||
}
|
||||
i.cp-badge-error {
|
||||
color: @cryptpad_color_warn_red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,3 +309,9 @@ Pinning.getDeletedPads = function (Env, channels, cb) {
|
||||
Pinning.isChannelPinned = function (Env, channel, cb) {
|
||||
return void cb(void 0, true);
|
||||
};
|
||||
|
||||
Pinning.isPremium = function (Env, userKey, cb) {
|
||||
const limit = Env.limits[userKey];
|
||||
return void cb(void 0, !!limit?.plan);
|
||||
//return void cb(void 0, (limit?.plan && limit.plan !== "custom"));
|
||||
};
|
||||
|
||||
@ -24,6 +24,7 @@ const UNAUTHENTICATED_CALLS = {
|
||||
WRITE_PRIVATE_MESSAGE: Channel.writePrivateMessage,
|
||||
DELETE_MAILBOX_MESSAGE: Channel.deleteMailboxMessage,
|
||||
GET_METADATA: Metadata.getMetadata,
|
||||
IS_PREMIUM: Pinning.isPremium,
|
||||
ADD_FIRST_ADMIN: Admin.addFirstAdmin
|
||||
};
|
||||
|
||||
|
||||
@ -8,12 +8,13 @@ const factory = (Sortify, UserObject, ProxyManager,
|
||||
SF, AccountTS, DriveTS, Cursor,
|
||||
Support, Integration, OnlyOffice,
|
||||
Mailbox, Profile, Team, Messenger, History,
|
||||
Calendar, Block, NetConfig,
|
||||
Calendar, BadgeTS, Block, NetConfig,
|
||||
Crypto, ChainPad, CpNetflux, Listmap,
|
||||
Netflux, nThen) => {
|
||||
|
||||
const Account = AccountTS.Account;
|
||||
const Drive = DriveTS.Drive;
|
||||
const Badge = BadgeTS.Badge;
|
||||
const window = globalThis;
|
||||
globalThis.nacl = globalThis.nacl || Crypto.Nacl;
|
||||
|
||||
@ -661,11 +662,15 @@ const factory = (Sortify, UserObject, ProxyManager,
|
||||
color: Store.getUserColor(),
|
||||
notifications: Util.find(proxy, ['mailboxes', 'notifications', 'channel']),
|
||||
curvePublic: proxy.curvePublic,
|
||||
edPublic: proxy.edPublic,
|
||||
netfluxId: store?.network?.webChannels?.[0]?.myID,
|
||||
badge: Util.find(proxy, ['profile', 'badge'])
|
||||
},
|
||||
// "priv" is not shared with other users but is needed by the apps
|
||||
priv: {
|
||||
clientId: clientId,
|
||||
edPublic: proxy.edPublic,
|
||||
edPrivate: proxy.edPrivate,
|
||||
friends: proxy.friends || {},
|
||||
settings: proxy.settings || NEW_USER_SETTINGS,
|
||||
thumbnails: disableThumbnails === false,
|
||||
@ -2809,6 +2814,7 @@ const factory = (Sortify, UserObject, ProxyManager,
|
||||
loadUniversal(Integration, 'integration', waitFor);
|
||||
loadUniversal(Messenger, 'messenger', waitFor);
|
||||
loadUniversal(History, 'history', waitFor);
|
||||
loadUniversal(Badge, 'badge', waitFor);
|
||||
loadOnlyOffice();
|
||||
if (store) {
|
||||
store.messenger = store.modules['messenger'];
|
||||
@ -3464,7 +3470,7 @@ module.exports = factory(
|
||||
require('../common/common-constants'),
|
||||
require('../common/common-feedback'),
|
||||
require('../common/common-realtime'),
|
||||
require('../common/common-messaging'),
|
||||
require('./components/messaging'),
|
||||
require('../common/pinpad'),
|
||||
require('../common/rpc'),
|
||||
require('./components/merge-drive'),
|
||||
@ -3482,6 +3488,7 @@ module.exports = factory(
|
||||
require('./modules/messenger'),
|
||||
require('./modules/history'),
|
||||
require('./modules/calendar'),
|
||||
require('./modules/badge'), // .ts
|
||||
require('../common/outer/login-block'),
|
||||
require('../common/network-config'),
|
||||
require('chainpad-crypto'),
|
||||
|
||||
@ -983,7 +983,7 @@ const factory = (Messaging, Hash, Util, Crypto, Block) => {
|
||||
};
|
||||
|
||||
module.exports = factory(
|
||||
require('../../common/common-messaging'),
|
||||
require('./messaging'),
|
||||
require('../../common/common-hash'),
|
||||
require('../../common/common-util'),
|
||||
require('chainpad-crypto'),
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
(() => {
|
||||
const factory = (Crypto, Hash, Util, Constants, Realtime) => {
|
||||
var Msg = {};
|
||||
|
||||
@ -15,6 +14,7 @@ const factory = (Crypto, Hash, Util, Constants, Realtime) => {
|
||||
curvePublic: proxy.curvePublic,
|
||||
notifications: Util.find(proxy, ['mailboxes', 'notifications', 'channel']),
|
||||
avatar: proxy.profile && proxy.profile.avatar,
|
||||
badge: proxy.profile && proxy.profile.badge,
|
||||
uid: proxy.uid,
|
||||
};
|
||||
if (hash === false) { delete data.channel; }
|
||||
@ -139,23 +139,10 @@ const factory = (Crypto, Hash, Util, Constants, Realtime) => {
|
||||
return Msg;
|
||||
};
|
||||
|
||||
if (typeof(module) !== 'undefined' && module.exports) {
|
||||
module.exports = factory(
|
||||
require('chainpad-crypto'),
|
||||
require('./common-hash'),
|
||||
require('./common-util'),
|
||||
require('./common-constants'),
|
||||
require('./common-realtime')
|
||||
);
|
||||
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
||||
define([
|
||||
'/components/chainpad-crypto/crypto.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-util.js',
|
||||
'/common/common-constants.js',
|
||||
'/common/common-realtime.js',
|
||||
], factory);
|
||||
} else {
|
||||
// unsupported initialization
|
||||
}
|
||||
})();
|
||||
module.exports = factory(
|
||||
require('chainpad-crypto'),
|
||||
require('../../common/common-hash'),
|
||||
require('../../common/common-util'),
|
||||
require('../../common/common-constants'),
|
||||
require('../../common/common-realtime')
|
||||
);
|
||||
@ -511,7 +511,7 @@ module.exports = factory(
|
||||
require('../../common/common-feedback'),
|
||||
require('../../common/common-hash'),
|
||||
require('../../common/common-util'),
|
||||
require('../../common/common-messaging'),
|
||||
require('./messaging'),
|
||||
require('../../common/cryptget'),
|
||||
require('../modules/mailbox'),
|
||||
require('../../common/common-realtime'),
|
||||
|
||||
114
src/worker/modules/badge.ts
Normal file
114
src/worker/modules/badge.ts
Normal file
@ -0,0 +1,114 @@
|
||||
import nacl from 'tweetnacl/nacl-fast';
|
||||
import nThen from 'nthen';
|
||||
import { Module, ModuleObject, Callback } from '../types'
|
||||
import * as Util from '../../common/common-util.js';
|
||||
|
||||
export interface BadgeModule<T> extends Module<T> {
|
||||
setCustomize: (data: any) => void
|
||||
}
|
||||
|
||||
let ApiConfig:any = {};
|
||||
|
||||
const checkApi = (ctx, ed, cb) => {
|
||||
const badges = [];
|
||||
const origin:string = ApiConfig?.httpUnsafeOrigin;
|
||||
Util.fetchApi(origin, 'config', true, Config => {
|
||||
const isAdmin = Config?.adminKeys?.includes(ed);
|
||||
if (isAdmin) { badges.push('admin'); }
|
||||
const isModerator = Config?.moderatorKeys?.includes(ed);
|
||||
if (isModerator) { badges.push('moderator'); }
|
||||
cb(badges);
|
||||
});
|
||||
};
|
||||
const checkPremium = (ctx, ed, cb) => {
|
||||
ctx.Store.anonRpcMsg('', {
|
||||
msg: 'IS_PREMIUM',
|
||||
data: ed
|
||||
}, obj => {
|
||||
let premium = Array.isArray(obj) && obj[0];
|
||||
cb(premium ? ['premium'] : []);
|
||||
});
|
||||
};
|
||||
|
||||
const listBadges:Callback = (ctx, data, clientId, cb) => {
|
||||
const badges = [];
|
||||
const origin:string = ApiConfig?.httpUnsafeOrigin;
|
||||
const ed = data.edPublic || ctx.store?.proxy?.edPublic;
|
||||
nThen(waitFor => {
|
||||
checkApi(ctx, ed, waitFor(list => {
|
||||
Array.prototype.push.apply(badges, list);
|
||||
}));
|
||||
}).nThen(waitFor => {
|
||||
checkPremium(ctx, ed, waitFor(list => {
|
||||
Array.prototype.push.apply(badges, list);
|
||||
}));
|
||||
}).nThen(() => {
|
||||
cb(badges);
|
||||
});
|
||||
};
|
||||
|
||||
const allBadges = {
|
||||
'admin': checkApi,
|
||||
'moderator': checkApi,
|
||||
'premium': checkPremium
|
||||
};
|
||||
|
||||
const checkBadge:Callback = (ctx, data, clientId, cb) => {
|
||||
const { badge, ed, sig, nid/*, channel*/ } = data;
|
||||
|
||||
const publicKey = Util.decodeBase64(ed); // Public key uint8
|
||||
const signature = Util.decodeBase64(sig); // badge uint8
|
||||
|
||||
// Check signature
|
||||
const msg = nacl.sign.open(signature, publicKey);
|
||||
if (!msg) { return void cb({verified: false}); }
|
||||
|
||||
// Check channel (replay attack)
|
||||
const msgStr:string = Util.encodeUTF8(msg);
|
||||
const expected:string = nid; // + channel;
|
||||
if (msgStr !== expected) { return void cb({verified: false}); }
|
||||
|
||||
let f = allBadges[badge];
|
||||
if (!f) { return void cb({verified: false, error: 'EINVAL'}); }
|
||||
|
||||
f(ctx, ed, list => {
|
||||
cb({
|
||||
verified: list.includes(badge),
|
||||
badge: badge
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const Badge: BadgeModule<ModuleObject> = {
|
||||
|
||||
init: (config, cb, emit) => {
|
||||
|
||||
const ctx:any = {
|
||||
store: config.store,
|
||||
Store: config.Store,
|
||||
updateMetadata: config.updateMetadata
|
||||
};
|
||||
|
||||
return {
|
||||
removeClient: () => {},
|
||||
execCommand: (clientId, obj, cb) => {
|
||||
console.log('Exex command', clientId, obj);
|
||||
const cmd = obj.cmd;
|
||||
const data = obj.data;
|
||||
if (cmd === 'LIST_BADGES') {
|
||||
return void listBadges(ctx, data, clientId, cb);
|
||||
}
|
||||
if (cmd === 'CHECK_BADGE') {
|
||||
return void checkBadge(ctx, data, clientId, cb);
|
||||
}
|
||||
cb();
|
||||
},
|
||||
}
|
||||
},
|
||||
setCustomize: data => {
|
||||
ApiConfig = data?.ApiConfig;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export { Badge }
|
||||
@ -677,7 +677,7 @@ module.exports = factory(
|
||||
require('../../common/common-util'),
|
||||
require('../../common/common-hash'),
|
||||
require('../../common/common-realtime'),
|
||||
require('../../common/common-messaging'),
|
||||
require('../components/messaging'),
|
||||
require('../../common/notify'),
|
||||
require('../components/mailbox-handlers'),
|
||||
require('chainpad-netflux'),
|
||||
|
||||
@ -1124,7 +1124,7 @@ module.exports = factory(
|
||||
require('../../common/common-hash'),
|
||||
require('../../common/common-util'),
|
||||
require('../../common/common-realtime'),
|
||||
require('../../common/common-messaging'),
|
||||
require('../components/messaging'),
|
||||
require('../../common/common-constants'),
|
||||
require('../../common/pad-types'),
|
||||
require('nthen')
|
||||
|
||||
@ -98,6 +98,12 @@ const factory = (Util, Hash, Constants, Realtime,
|
||||
ctx.emit('UPDATE', ctx.listmap.proxy, ctx.clients.filter(function (clientId) {
|
||||
return clientId !== cId;
|
||||
}));
|
||||
if (key === 'badge') {
|
||||
ctx.Store.set(null, {
|
||||
key: ['profile', 'badge'],
|
||||
value: value || undefined
|
||||
}, () => {});
|
||||
}
|
||||
cb(ctx.listmap.proxy);
|
||||
});
|
||||
};
|
||||
@ -112,6 +118,7 @@ const factory = (Util, Hash, Constants, Realtime,
|
||||
var store = cfg.store;
|
||||
if (!store.loggedIn || !store.proxy.edPublic) { return; }
|
||||
var ctx = {
|
||||
Store: cfg.Store,
|
||||
store: store,
|
||||
pinPads: cfg.pinPads,
|
||||
updateMetadata: cfg.updateMetadata,
|
||||
|
||||
@ -2250,7 +2250,7 @@ module.exports = factory(
|
||||
require('../../common/user-object'),
|
||||
require('../components/sharedfolder'),
|
||||
require('../components/roster'),
|
||||
require('../../common/common-messaging'),
|
||||
require('../components/messaging'),
|
||||
require('../../common/common-feedback'),
|
||||
require('../components/invitation'),
|
||||
require('../../common/cryptget'),
|
||||
|
||||
@ -12,7 +12,7 @@ export interface TestModuleObject extends ModuleObject {
|
||||
|
||||
const TestModule: Module<TestModuleObject> = {
|
||||
|
||||
init: (config, cb) => {
|
||||
init: (config, cb, emit) => {
|
||||
let myTest = {};
|
||||
|
||||
cb();
|
||||
|
||||
@ -15,7 +15,6 @@ import * as Util from '../common/common-util.js';
|
||||
import * as Hash from '../common/common-hash.js';
|
||||
import * as Feedback from '../common/common-feedback.js';
|
||||
import * as Realtime from '../common/common-realtime.js';
|
||||
import * as Messaging from '../common/common-messaging.js';
|
||||
import * as Constants from '../common/common-constants.js';
|
||||
import * as Credential from '../common/common-credential.js';
|
||||
import * as ProxyManager from '../common/proxy-manager.js';
|
||||
@ -36,6 +35,7 @@ import * as AsyncConnector from './core/async-connector.js';
|
||||
|
||||
// Components
|
||||
import * as Migrate from './components/migrate-user-object.js';
|
||||
import * as Messaging from './components/messaging.js';
|
||||
|
||||
// Modules
|
||||
import * as Mailbox from './modules/mailbox.js';
|
||||
@ -48,6 +48,7 @@ import * as Team from './modules/team.js';
|
||||
import * as Messenger from './modules/messenger.js';
|
||||
import * as History from './modules/history.js';
|
||||
import * as Calendar from './modules/calendar.js';
|
||||
import { Badge } from './modules/badge';
|
||||
|
||||
declare var WorkerGlobalScope: any
|
||||
declare var SharedWorkerGlobalScope: any
|
||||
@ -76,7 +77,8 @@ let start = (cfg: StoreConfig):void => {
|
||||
Calendar,
|
||||
Store,
|
||||
Account,
|
||||
Mailbox
|
||||
Mailbox,
|
||||
Badge
|
||||
].forEach(dep => {
|
||||
if (typeof(dep.setCustomize) === "function") {
|
||||
dep.setCustomize(cfg);
|
||||
|
||||
@ -7,7 +7,11 @@
|
||||
export type Callback = (...args: any[]) => void
|
||||
|
||||
export type ModuleConfig = {
|
||||
emit: Function
|
||||
store: any,
|
||||
Store: any,
|
||||
updateMetadata: Callback,
|
||||
pinPads: Callback,
|
||||
unpinPads: Callback
|
||||
}
|
||||
|
||||
export type CommandData = {
|
||||
@ -21,7 +25,7 @@ export interface ModuleObject {
|
||||
}
|
||||
|
||||
export interface Module<T> {
|
||||
init: (config: ModuleConfig, cb: Callback) => T
|
||||
init: (config: ModuleConfig, cb: Callback, emit: Callback) => T
|
||||
}
|
||||
|
||||
|
||||
|
||||
32
www/common/inner/badges.js
Normal file
32
www/common/inner/badges.js
Normal file
@ -0,0 +1,32 @@
|
||||
// SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
define([
|
||||
'/common/hyperscript.js',
|
||||
'/customize/messages.js',
|
||||
], function (h, Messages) {
|
||||
var Badges = {};
|
||||
|
||||
const badges = {
|
||||
admin: 'fa-star',
|
||||
moderator: 'fa-life-ring',
|
||||
premium: 'fa-check-circle',
|
||||
error: 'fa-exclamation-circle'
|
||||
};
|
||||
|
||||
Badges.render = id => {
|
||||
let icon = badges[id];
|
||||
if (!icon) { return; }
|
||||
let cls = icon.indexOf('cptools') === 0 ? 'cptools '+icon : 'fa '+icon;
|
||||
if (id === 'error') { cls += ' cp-badge-error'; }
|
||||
return h('i', {
|
||||
'class': `cp-badge ${cls}`,
|
||||
'title': Messages[`badges_${id}`] || id
|
||||
});
|
||||
};
|
||||
|
||||
return Badges;
|
||||
});
|
||||
|
||||
|
||||
@ -186,7 +186,7 @@ define([
|
||||
if (avatars[href]) {
|
||||
var nodes = $.parseHTML(avatars[href]);
|
||||
var $el = $(nodes[0]);
|
||||
$container.append($el);
|
||||
$container.empty().append($el);
|
||||
return void cb($el);
|
||||
}
|
||||
|
||||
@ -222,7 +222,7 @@ define([
|
||||
if (typeof data !== "number") { return void displayDefault(); }
|
||||
if (Util.bytesToMegabytes(data) > 0.5) { return void displayDefault(); }
|
||||
var mt = UI.mediaTag(src, cryptKey);
|
||||
var $img = $(mt).appendTo($container);
|
||||
var $img = $(mt).appendTo($container.empty());
|
||||
MT.displayMediatagImage(common, $img, function (err, $image) {
|
||||
if (err) { return void console.error(err); }
|
||||
centerImage($img, $image);
|
||||
|
||||
@ -751,6 +751,7 @@ define([
|
||||
if (!parsed.type) { throw new Error(); }
|
||||
var defaultTitle = Utils.UserObject.getDefaultName(parsed);
|
||||
var edPublic, curvePublic, notifications, isTemplate;
|
||||
var edPrivate;
|
||||
var settings = {};
|
||||
var isSafe = ['debug', 'profile', 'drive', 'teams', 'calendar', 'file'].indexOf(currentPad.app) !== -1;
|
||||
var isOO = ['sheet', 'doc', 'presentation'].indexOf(parsed.type) !== -1;
|
||||
@ -760,6 +761,7 @@ define([
|
||||
if (isDeleted) {
|
||||
Utils.Cache.clearChannel(secret.channel);
|
||||
}
|
||||
let signature;
|
||||
|
||||
var updateMeta = function () {
|
||||
//console.log('EV_METADATA_UPDATE');
|
||||
@ -775,6 +777,9 @@ define([
|
||||
curvePublic = metaObj.user.curvePublic;
|
||||
notifications = metaObj.user.notifications;
|
||||
settings = metaObj.priv.settings;
|
||||
|
||||
edPrivate = metaObj.priv.edPrivate;
|
||||
delete metaObj.priv.edPrivate; // don't send to inner
|
||||
}));
|
||||
if (typeof(isTemplate) === "undefined") {
|
||||
Cryptpad.isTemplate(currentPad.href, waitFor(function (err, t) {
|
||||
@ -856,6 +861,18 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
if (metaObj?.user?.edPublic) {
|
||||
let str = metaObj?.user?.netfluxId;// + secret.channel;
|
||||
if (!signature && str) {
|
||||
let myIDu8 = Utils.Util.decodeUTF8(str);
|
||||
let k = Utils.Util.decodeBase64(edPrivate);
|
||||
let nacl = Utils.Crypto.Nacl;
|
||||
let s = nacl.sign(myIDu8, k);
|
||||
signature = Utils.Util.encodeBase64(s);
|
||||
}
|
||||
metaObj.user.signature = signature;
|
||||
}
|
||||
|
||||
// Early access
|
||||
var priv = metaObj.priv;
|
||||
var _plan = typeof(priv.plan) === "undefined" ? Utils.LocalStore.getPremium() : priv.plan;
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
(() => {
|
||||
const factory = function () {
|
||||
let USE_MIN = false;
|
||||
let USE_MIN = true;
|
||||
|
||||
let path = '/common/worker.bundle.js?';
|
||||
if (USE_MIN) { path = '/common/worker.bundle.min.js?'; }
|
||||
|
||||
@ -13,12 +13,13 @@ define([
|
||||
'/common/common-util.js',
|
||||
'/common/common-feedback.js',
|
||||
'/common/inner/common-mediatag.js',
|
||||
'/common/inner/badges.js',
|
||||
'/common/hyperscript.js',
|
||||
'/common/messenger-ui.js',
|
||||
'/customize/messages.js',
|
||||
'/customize/pages.js',
|
||||
'/common/pad-types.js',
|
||||
], function ($, Config, ApiConfig, Broadcast, UIElements, UI, Hash, Util, Feedback, MT, h,
|
||||
], function ($, Config, ApiConfig, Broadcast, UIElements, UI, Hash, Util, Feedback, MT, Badges, h,
|
||||
MessengerUI, Messages, Pages, PadTypes) {
|
||||
var Common;
|
||||
|
||||
@ -193,16 +194,14 @@ MessengerUI, Messages, Pages, PadTypes) {
|
||||
// Display only one time each user (if he is connected in multiple tabs)
|
||||
var uids = [];
|
||||
Object.keys(userData).forEach(function(user) {
|
||||
//if (user !== userNetfluxId) {
|
||||
var data = userData[user] || {};
|
||||
var userId = data.uid;
|
||||
if (!userId) { return; }
|
||||
//data.netfluxId = user;
|
||||
if (uids.indexOf(userId) === -1) {// && (!myUid || userId !== myUid)) {
|
||||
if (user !== data.netfluxId) { return; }
|
||||
if (uids.indexOf(userId) === -1) {
|
||||
uids.push(userId);
|
||||
list.push(data);
|
||||
} else { i++; }
|
||||
//}
|
||||
});
|
||||
return {
|
||||
list: list,
|
||||
@ -223,6 +222,7 @@ MessengerUI, Messages, Pages, PadTypes) {
|
||||
});
|
||||
};
|
||||
var showColors = false;
|
||||
const validatedBadges = {};
|
||||
var updateUserList = function (toolbar, config, forceOffline) {
|
||||
if (!config.displayed || config.displayed.indexOf('userlist') === -1) { return; }
|
||||
if (toolbar.isAlone) { return; }
|
||||
@ -427,6 +427,38 @@ MessengerUI, Messages, Pages, PadTypes) {
|
||||
$span.append($rightCol);
|
||||
}, data.uid);
|
||||
$span.data('uid', data.uid);
|
||||
if (data.badge && data.edPublic) {
|
||||
const addBadge = (badge) => {
|
||||
let i = Badges.render(badge);
|
||||
if (!i) { return; }
|
||||
$rightCol.append(h('div.cp-userlist-badge', i));
|
||||
};
|
||||
const key = data.signature + '-' + data.badge;
|
||||
const v = validatedBadges[key];
|
||||
if (typeof (v) === "string") {
|
||||
addBadge(v);
|
||||
} else if (v === false) {
|
||||
addBadge('error');
|
||||
} else {
|
||||
let ev = validatedBadges[key] ||= Util.mkEvent(true);
|
||||
ev.reg(badge => { addBadge(badge); });
|
||||
toolbar.badges.execCommand('CHECK_BADGE', {
|
||||
badge: data.badge,
|
||||
channel: priv.channel,
|
||||
ed: data.edPublic,
|
||||
sig: data.signature,
|
||||
nid: data.netfluxId
|
||||
}, res => {
|
||||
if (!res?.verified) {
|
||||
validatedBadges[key] = false;
|
||||
return void addBadge('error');
|
||||
}
|
||||
validatedBadges[key] = res.badge;
|
||||
ev.fire(res.badge);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
$editUsersList.append($span);
|
||||
});
|
||||
|
||||
@ -1401,6 +1433,8 @@ MessengerUI, Messages, Pages, PadTypes) {
|
||||
toolbar.connected = false;
|
||||
toolbar.firstConnection = true;
|
||||
|
||||
toolbar.badges = Common.makeUniversal('badge');
|
||||
|
||||
if (Array.isArray(cfg.displayed) && cfg.displayed.includes('pad')) {
|
||||
cfg.addFileMenu = true;
|
||||
}
|
||||
|
||||
2
www/common/worker.bundle.min.js
vendored
2
www/common/worker.bundle.min.js
vendored
File diff suppressed because one or more lines are too long
@ -7,6 +7,7 @@
|
||||
@import (reference) '../../customize/src/less2/include/framework.less';
|
||||
@import (reference) '../../customize/src/less2/include/sidebar-layout.less';
|
||||
@import (reference) '../../customize/src/less2/include/variables.less';
|
||||
@import (reference) '../../customize/src/less2/include/badges.less';
|
||||
|
||||
&.cp-app-profile {
|
||||
|
||||
@ -26,6 +27,29 @@
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.cp-profile-badges {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
& > span {
|
||||
margin-right: 1em;
|
||||
}
|
||||
.cp-profile-badges-list {
|
||||
.badges_main(40px);
|
||||
i {
|
||||
cursor: pointer;
|
||||
&:focus-visible {
|
||||
outline: @variables_focus_style;
|
||||
}
|
||||
&:not(:last-child) {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
&.cp-selected {
|
||||
border-color: @cryptpad_color_brand;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#cp-app-profile-header {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
|
||||
@ -17,6 +17,7 @@ define([
|
||||
'/common/common-realtime.js',
|
||||
'/common/clipboard.js',
|
||||
'/common/inner/common-mediatag.js',
|
||||
'/common/inner/badges.js',
|
||||
'/common/hyperscript.js',
|
||||
'/customize/messages.js',
|
||||
'/customize/application_config.js',
|
||||
@ -48,6 +49,7 @@ define([
|
||||
Realtime,
|
||||
Clipboard,
|
||||
MT,
|
||||
Badges,
|
||||
h,
|
||||
Messages,
|
||||
AppConfig,
|
||||
@ -92,6 +94,7 @@ define([
|
||||
var LINK_ID = "cp-app-profile-link";
|
||||
var AVATAR_ID = "cp-app-profile-avatar";
|
||||
var DESCRIPTION_ID = "cp-app-profile-description";
|
||||
var BADGES_ID = "cp-app-profile-badges";
|
||||
var CREATE_ID = "cp-app-profile-create";
|
||||
var HEADER_ID = "cp-app-profile-header";
|
||||
var HEADER_RIGHT_ID = "cp-app-profile-rightside";
|
||||
@ -375,7 +378,7 @@ define([
|
||||
var displayAvatar = function (val) {
|
||||
var sframeChan = common.getSframeChannel();
|
||||
var $span = APP.$avatar;
|
||||
$span.html('');
|
||||
$span.empty();
|
||||
if (!val) {
|
||||
$('<img>', {
|
||||
src: '/customize/images/avatar.png',
|
||||
@ -447,6 +450,48 @@ define([
|
||||
displayAvatar(data.avatar);
|
||||
};
|
||||
|
||||
const addBadges = $container => {
|
||||
var $block = $('<div>', {id: BADGES_ID, class:'cp-sidebarlayout-element'}).appendTo($container);
|
||||
APP.$badges = $(h('span')).appendTo($block);
|
||||
};
|
||||
const refreshBadges = (obj) => {
|
||||
if (!APP.$badges) { return; }
|
||||
const metadataMgr = APP.common.getMetadataMgr();
|
||||
const privateData = metadataMgr.getPrivateData();
|
||||
let args = {};
|
||||
if (!privateData.isOwnProfile) { args.edPublic = obj.edPublic; }
|
||||
APP.badge.execCommand('LIST_BADGES', args, data => {
|
||||
APP.$badges.empty();
|
||||
let spinner;
|
||||
APP.$badges.toggle(!!data.length);
|
||||
let all = data.map(str => {
|
||||
const i = Badges.render(str);
|
||||
const $i = $(i).attr('tabindex', 0);
|
||||
if (APP.readOnly) { return i; }
|
||||
const selected = obj?.badge === str;
|
||||
if (selected) { $i.addClass('cp-selected'); }
|
||||
Util.onClickEnter($i, () => {
|
||||
let value = selected ? '' : str;
|
||||
spinner.spin();
|
||||
APP.module.execCommand('SET', {
|
||||
key: 'badge',
|
||||
value
|
||||
}, function (data) {
|
||||
spinner.hide();
|
||||
APP.updateValues(data);
|
||||
});
|
||||
});
|
||||
return i;
|
||||
});
|
||||
let content = h('div.cp-profile-badges', [
|
||||
h('span', Messages.profile_badges),
|
||||
h('div.cp-profile-badges-list', all)
|
||||
]);
|
||||
APP.$badges.append(content);
|
||||
spinner = UI.makeSpinner(APP.$badges.find('> div'));
|
||||
});
|
||||
};
|
||||
|
||||
var addDescription = function ($container) {
|
||||
var $block = $('<div>', {id: DESCRIPTION_ID, class: PROFILE_SECTION}).appendTo($container);
|
||||
|
||||
@ -462,7 +507,7 @@ define([
|
||||
}, [
|
||||
h('i.fa.fa-pencil', {'aria-hidden': 'true' }),
|
||||
h('span#cp-profile-add-description-button', Messages.profile_addDescription)
|
||||
]);
|
||||
]);
|
||||
APP.$descriptionEdit = $(button);
|
||||
var save = h('button.btn.btn-primary', Messages.settings_save);
|
||||
var text = h('textarea');
|
||||
@ -609,6 +654,7 @@ define([
|
||||
addLink($rightside);
|
||||
addFriendRequest($rightside);
|
||||
addMuteButton($rightside);
|
||||
addBadges($rightside);
|
||||
addPublicKey($rightside);
|
||||
addCopyData($rightside);
|
||||
addViewButton($rightside);
|
||||
@ -627,6 +673,7 @@ define([
|
||||
refreshName(data);
|
||||
refreshLink(data);
|
||||
refreshDescription(data);
|
||||
refreshBadges(data);
|
||||
refreshFriendRequest(data);
|
||||
refreshMute(data);
|
||||
setPublicKeyButton(data);
|
||||
@ -700,6 +747,9 @@ define([
|
||||
return;
|
||||
}
|
||||
|
||||
APP.badge = common.makeUniversal('badge', {
|
||||
onEvent: onEvent
|
||||
});
|
||||
if (privateData.isOwnProfile) {
|
||||
|
||||
APP.module = common.makeUniversal('profile', {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user