mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-12-20 15:30:39 +01:00
feat: show custom fields on edit/profile
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
"name": "Name",
|
"name": "Name",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"input-type-text": "Input (Text)",
|
"input-type-text": "Input (Text)",
|
||||||
|
"input-type-link": "Input (Link)",
|
||||||
"input-type-number": "Input (Number)",
|
"input-type-number": "Input (Number)",
|
||||||
"input-type-select": "Select",
|
"input-type-select": "Select",
|
||||||
"select-options": "Options",
|
"select-options": "Options",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const groups = require('../../groups');
|
|||||||
const privileges = require('../../privileges');
|
const privileges = require('../../privileges');
|
||||||
const plugins = require('../../plugins');
|
const plugins = require('../../plugins');
|
||||||
const file = require('../../file');
|
const file = require('../../file');
|
||||||
|
const accountHelpers = require('./helpers');
|
||||||
|
|
||||||
const editController = module.exports;
|
const editController = module.exports;
|
||||||
|
|
||||||
@@ -25,11 +26,13 @@ editController.get = async function (req, res, next) {
|
|||||||
allowMultipleBadges,
|
allowMultipleBadges,
|
||||||
} = userData;
|
} = userData;
|
||||||
|
|
||||||
const [canUseSignature, canManageUsers] = await Promise.all([
|
const [canUseSignature, canManageUsers, customUserFields] = await Promise.all([
|
||||||
privileges.global.can('signature', req.uid),
|
privileges.global.can('signature', req.uid),
|
||||||
privileges.admin.can('admin:users', req.uid),
|
privileges.admin.can('admin:users', req.uid),
|
||||||
|
accountHelpers.getCustomUserFields(userData),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
userData.customUserFields = customUserFields;
|
||||||
userData.maximumSignatureLength = meta.config.maximumSignatureLength;
|
userData.maximumSignatureLength = meta.config.maximumSignatureLength;
|
||||||
userData.maximumAboutMeLength = meta.config.maximumAboutMeLength;
|
userData.maximumAboutMeLength = meta.config.maximumAboutMeLength;
|
||||||
userData.maximumProfileImageSize = meta.config.maximumProfileImageSize;
|
userData.maximumProfileImageSize = meta.config.maximumProfileImageSize;
|
||||||
|
|||||||
@@ -134,6 +134,23 @@ helpers.getUserDataByUserSlug = async function (userslug, callerUID, query = {})
|
|||||||
return hookData.userData;
|
return hookData.userData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
helpers.getCustomUserFields = async function (userData) {
|
||||||
|
const keys = await db.getSortedSetRange('user-custom-fields', 0, -1);
|
||||||
|
const fields = (await db.getObjects(keys.map(k => `user-custom-field:${k}`))).filter(Boolean);
|
||||||
|
fields.forEach((f) => {
|
||||||
|
f['select-options'] = f['select-options'].split('\n').filter(Boolean).map(
|
||||||
|
opt => ({
|
||||||
|
value: opt,
|
||||||
|
selected: opt === userData[f.key],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (userData[f.key]) {
|
||||||
|
f.value = validator.escape(String(userData[f.key]));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return fields;
|
||||||
|
};
|
||||||
|
|
||||||
function escape(value) {
|
function escape(value) {
|
||||||
return translator.escape(validator.escape(String(value || '')));
|
return translator.escape(validator.escape(String(value || '')));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ const categories = require('../../categories');
|
|||||||
const plugins = require('../../plugins');
|
const plugins = require('../../plugins');
|
||||||
const privileges = require('../../privileges');
|
const privileges = require('../../privileges');
|
||||||
const helpers = require('../helpers');
|
const helpers = require('../helpers');
|
||||||
|
const accountHelpers = require('./helpers');
|
||||||
const utils = require('../../utils');
|
const utils = require('../../utils');
|
||||||
|
|
||||||
const profileController = module.exports;
|
const profileController = module.exports;
|
||||||
@@ -21,12 +22,13 @@ profileController.get = async function (req, res, next) {
|
|||||||
|
|
||||||
await incrementProfileViews(req, userData);
|
await incrementProfileViews(req, userData);
|
||||||
|
|
||||||
const [latestPosts, bestPosts] = await Promise.all([
|
const [latestPosts, bestPosts, customUserFields] = await Promise.all([
|
||||||
getLatestPosts(req.uid, userData),
|
getLatestPosts(req.uid, userData),
|
||||||
getBestPosts(req.uid, userData),
|
getBestPosts(req.uid, userData),
|
||||||
|
accountHelpers.getCustomUserFields(userData),
|
||||||
posts.parseSignature(userData, req.uid),
|
posts.parseSignature(userData, req.uid),
|
||||||
]);
|
]);
|
||||||
|
userData.customUserFields = customUserFields;
|
||||||
userData.posts = latestPosts; // for backwards compat.
|
userData.posts = latestPosts; // for backwards compat.
|
||||||
userData.latestPosts = latestPosts;
|
userData.latestPosts = latestPosts;
|
||||||
userData.bestPosts = bestPosts;
|
userData.bestPosts = bestPosts;
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ usersController.getCSV = async function (req, res, next) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
usersController.customFields = async function (req, res, next) {
|
usersController.customFields = async function (req, res) {
|
||||||
const keys = await db.getSortedSetRange('user-custom-fields', 0, -1);
|
const keys = await db.getSortedSetRange('user-custom-fields', 0, -1);
|
||||||
const fields = await db.getObjects(keys.map(k => `user-custom-field:${k}`));
|
const fields = await db.getObjects(keys.map(k => `user-custom-field:${k}`));
|
||||||
fields.forEach((field) => {
|
fields.forEach((field) => {
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ User.saveCustomFields = async function (socket, fields) {
|
|||||||
await db.setObjectBulk(
|
await db.setObjectBulk(
|
||||||
fields.map(field => [`user-custom-field:${field.key}`, field])
|
fields.map(field => [`user-custom-field:${field.key}`, field])
|
||||||
);
|
);
|
||||||
|
await user.reloadCustomFieldWhitelist();
|
||||||
};
|
};
|
||||||
|
|
||||||
User.deleteCustomField = async function (socket, key) {
|
User.deleteCustomField = async function (socket, key) {
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ module.exports = function (User) {
|
|||||||
'cover:position', 'groupTitle', 'mutedUntil', 'mutedReason',
|
'cover:position', 'groupTitle', 'mutedUntil', 'mutedReason',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let customFieldWhiteList = null;
|
||||||
|
|
||||||
User.guestData = {
|
User.guestData = {
|
||||||
uid: 0,
|
uid: 0,
|
||||||
username: '[[global:guest]]',
|
username: '[[global:guest]]',
|
||||||
@@ -46,6 +48,10 @@ module.exports = function (User) {
|
|||||||
|
|
||||||
let iconBackgrounds;
|
let iconBackgrounds;
|
||||||
|
|
||||||
|
User.reloadCustomFieldWhitelist = async () => {
|
||||||
|
customFieldWhiteList = await db.getSortedSetRange('user-custom-fields', 0, -1);
|
||||||
|
};
|
||||||
|
|
||||||
User.getUsersFields = async function (uids, fields) {
|
User.getUsersFields = async function (uids, fields) {
|
||||||
if (!Array.isArray(uids) || !uids.length) {
|
if (!Array.isArray(uids) || !uids.length) {
|
||||||
return [];
|
return [];
|
||||||
@@ -58,10 +64,12 @@ module.exports = function (User) {
|
|||||||
ensureRequiredFields(fields, fieldsToRemove);
|
ensureRequiredFields(fields, fieldsToRemove);
|
||||||
|
|
||||||
const uniqueUids = _.uniq(uids).filter(uid => uid > 0);
|
const uniqueUids = _.uniq(uids).filter(uid => uid > 0);
|
||||||
|
if (!customFieldWhiteList) {
|
||||||
|
await User.reloadCustomFieldWhitelist();
|
||||||
|
}
|
||||||
const results = await plugins.hooks.fire('filter:user.whitelistFields', {
|
const results = await plugins.hooks.fire('filter:user.whitelistFields', {
|
||||||
uids: uids,
|
uids: uids,
|
||||||
whitelist: fieldWhitelist.slice(),
|
whitelist: _.uniq(fieldWhitelist.concat(customFieldWhiteList)),
|
||||||
});
|
});
|
||||||
if (!fields.length) {
|
if (!fields.length) {
|
||||||
fields = results.whitelist;
|
fields = results.whitelist;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ module.exports = function (User) {
|
|||||||
let fields = [
|
let fields = [
|
||||||
'username', 'email', 'fullname', 'website', 'location',
|
'username', 'email', 'fullname', 'website', 'location',
|
||||||
'groupTitle', 'birthday', 'signature', 'aboutme',
|
'groupTitle', 'birthday', 'signature', 'aboutme',
|
||||||
|
...await db.getSortedSetRange('user-custom-fields', 0, -1),
|
||||||
];
|
];
|
||||||
if (Array.isArray(extraFields)) {
|
if (Array.isArray(extraFields)) {
|
||||||
fields = _.uniq(fields.concat(extraFields));
|
fields = _.uniq(fields.concat(extraFields));
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<label class="form-label">[[admin/manage/user-custom-fields:type-of-input]]</label>
|
<label class="form-label">[[admin/manage/user-custom-fields:type-of-input]]</label>
|
||||||
<select class="form-select" id="type-select" name="type">
|
<select class="form-select" id="type-select" name="type">
|
||||||
<option value="input-text" {{{ if (type == "input-text") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-text]]</option>
|
<option value="input-text" {{{ if (type == "input-text") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-text]]</option>
|
||||||
|
<option value="input-link" {{{ if (type == "input-link") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-link]]</option>
|
||||||
<option value="input-number" {{{ if (type == "input-number") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-number]]</option>
|
<option value="input-number" {{{ if (type == "input-number") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-number]]</option>
|
||||||
<option value="select" {{{ if (type == "select") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-select]]</option>
|
<option value="select" {{{ if (type == "select") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-select]]</option>
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
Reference in New Issue
Block a user