mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-05-07 22:06:07 +02:00
feat: move website/location fields into custom user fields
This commit is contained in:
@@ -38,7 +38,6 @@ editController.get = async function (req, res, next) {
|
||||
userData.maximumProfileImageSize = meta.config.maximumProfileImageSize;
|
||||
userData.allowMultipleBadges = meta.config.allowMultipleBadges === 1;
|
||||
userData.allowAccountDelete = meta.config.allowAccountDelete === 1;
|
||||
userData.allowWebsite = !isSelf || !!meta.config['reputation:disabled'] || reputation >= meta.config['min:rep:website'];
|
||||
userData.allowAboutMe = !isSelf || !!meta.config['reputation:disabled'] || reputation >= meta.config['min:rep:aboutme'];
|
||||
userData.allowSignature = canUseSignature && (!isSelf || !!meta.config['reputation:disabled'] || reputation >= meta.config['min:rep:signature']);
|
||||
userData.profileImageDimension = meta.config.profileImageDimension;
|
||||
|
||||
@@ -104,12 +104,7 @@ helpers.getUserDataByUserSlug = async function (userslug, callerUID, query = {})
|
||||
|
||||
userData.banned = Boolean(userData.banned);
|
||||
userData.muted = parseInt(userData.mutedUntil, 10) > Date.now();
|
||||
userData.website = escape(userData.website);
|
||||
userData.websiteLink = !userData.website.startsWith('http') ? `http://${userData.website}` : userData.website;
|
||||
userData.websiteName = userData.website.replace(validator.escape('http://'), '').replace(validator.escape('https://'), '');
|
||||
|
||||
userData.fullname = escape(userData.fullname);
|
||||
userData.location = escape(userData.location);
|
||||
userData.signature = escape(userData.signature);
|
||||
userData.birthday = validator.escape(String(userData.birthday || ''));
|
||||
userData.moderationNote = validator.escape(String(userData.moderationNote || ''));
|
||||
@@ -148,6 +143,9 @@ helpers.getCustomUserFields = async function (userData) {
|
||||
if (f.type === 'select-multi' && userValue) {
|
||||
userValue = JSON.parse(userValue || '[]');
|
||||
}
|
||||
if (f.type === 'input-link' && userValue) {
|
||||
f.linkValue = validator.escape(String(userValue.replace('http://', '').replace('https://', '')));
|
||||
}
|
||||
f['select-options'] = f['select-options'].split('\n').filter(Boolean).map(
|
||||
opt => ({
|
||||
value: opt,
|
||||
|
||||
@@ -94,9 +94,10 @@ async function getUsers(req, res) {
|
||||
|
||||
const set = buildSet();
|
||||
const uids = await getUids(set);
|
||||
const [count, users] = await Promise.all([
|
||||
const [count, users, customUserFields] = await Promise.all([
|
||||
getCount(set),
|
||||
loadUserInfo(req.uid, uids),
|
||||
getCustomUserFields(),
|
||||
]);
|
||||
|
||||
await render(req, res, {
|
||||
@@ -106,9 +107,15 @@ async function getUsers(req, res) {
|
||||
resultsPerPage: resultsPerPage,
|
||||
reverse: reverse,
|
||||
sortBy: sortBy,
|
||||
customUserFields,
|
||||
});
|
||||
}
|
||||
|
||||
async function getCustomUserFields() {
|
||||
const keys = await db.getSortedSetRange('user-custom-fields', 0, -1);
|
||||
return (await db.getObjects(keys.map(k => `user-custom-field:${k}`))).filter(Boolean);
|
||||
}
|
||||
|
||||
usersController.search = async function (req, res) {
|
||||
const sortDirection = req.query.sortDirection || 'desc';
|
||||
const reverse = sortDirection === 'desc';
|
||||
|
||||
44
src/upgrades/3.11.0/default-custom-profile-fields.js
Normal file
44
src/upgrades/3.11.0/default-custom-profile-fields.js
Normal file
@@ -0,0 +1,44 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
|
||||
'use strict';
|
||||
|
||||
const db = require('../../database');
|
||||
|
||||
module.exports = {
|
||||
name: 'Add website and location as custom profile fields',
|
||||
timestamp: Date.UTC(2024, 10, 25),
|
||||
method: async function () {
|
||||
const minRepWebsite = parseInt(await db.getObjectField('config', 'min:rep:website'), 10) || 0;
|
||||
|
||||
const website = {
|
||||
icon: 'fa-solid fa-globe',
|
||||
key: 'website',
|
||||
'min:rep': minRepWebsite,
|
||||
name: '[[user:website]]',
|
||||
'select-options': '',
|
||||
type: 'input-link',
|
||||
};
|
||||
|
||||
const location = {
|
||||
icon: 'fa-solid fa-map-pin',
|
||||
key: 'location',
|
||||
'min:rep': 0,
|
||||
name: '[[user:location]]',
|
||||
'select-options': '',
|
||||
type: 'input-text',
|
||||
};
|
||||
|
||||
await db.sortedSetAdd(
|
||||
`user-custom-fields`,
|
||||
[0, 1],
|
||||
['website', 'location']
|
||||
);
|
||||
|
||||
await db.setObjectBulk([
|
||||
[`user-custom-field:website`, website],
|
||||
[`user-custom-field:location`, location],
|
||||
]);
|
||||
|
||||
await db.deleteObjectField('config', 'min:rep:website');
|
||||
},
|
||||
};
|
||||
@@ -21,7 +21,7 @@ const intFields = [
|
||||
module.exports = function (User) {
|
||||
const fieldWhitelist = [
|
||||
'uid', 'username', 'userslug', 'email', 'email:confirmed', 'joindate',
|
||||
'lastonline', 'picture', 'icon:bgColor', 'fullname', 'location', 'birthday', 'website',
|
||||
'lastonline', 'picture', 'icon:bgColor', 'fullname', 'birthday',
|
||||
'aboutme', 'signature', 'uploadedpicture', 'profileviews', 'reputation',
|
||||
'postcount', 'topiccount', 'lastposttime', 'banned', 'banned:expire',
|
||||
'status', 'flags', 'followerCount', 'followingCount', 'cover:url',
|
||||
|
||||
@@ -77,11 +77,9 @@ module.exports = function (User) {
|
||||
async function validateData(callerUid, data) {
|
||||
await isEmailValid(data);
|
||||
await isUsernameAvailable(data, data.uid);
|
||||
await isWebsiteValid(callerUid, data);
|
||||
await isAboutMeValid(callerUid, data);
|
||||
await isSignatureValid(callerUid, data);
|
||||
isFullnameValid(data);
|
||||
isLocationValid(data);
|
||||
isBirthdayValid(data);
|
||||
isGroupTitleValid(data);
|
||||
await validateCustomFields(data);
|
||||
@@ -113,6 +111,10 @@ module.exports = function (User) {
|
||||
throw new Error(tx.compile(
|
||||
'error:custom-user-field-invalid-number', field.name
|
||||
));
|
||||
} else if (value && type === 'input-text' && validator.isURL(value)) {
|
||||
throw new Error(tx.compile(
|
||||
'error:custom-user-field-invalid-text', field.name
|
||||
));
|
||||
} else if (value && type === 'input-date' && !validator.isDate(value)) {
|
||||
throw new Error(tx.compile(
|
||||
'error:custom-user-field-invalid-date', field.name
|
||||
@@ -197,16 +199,6 @@ module.exports = function (User) {
|
||||
}
|
||||
User.checkUsername = async username => isUsernameAvailable({ username });
|
||||
|
||||
async function isWebsiteValid(callerUid, data) {
|
||||
if (!data.website) {
|
||||
return;
|
||||
}
|
||||
if (data.website.length > 255) {
|
||||
throw new Error('[[error:invalid-website]]');
|
||||
}
|
||||
await User.checkMinReputation(callerUid, data.uid, 'min:rep:website');
|
||||
}
|
||||
|
||||
async function isAboutMeValid(callerUid, data) {
|
||||
if (!data.aboutme) {
|
||||
return;
|
||||
@@ -235,12 +227,6 @@ module.exports = function (User) {
|
||||
}
|
||||
}
|
||||
|
||||
function isLocationValid(data) {
|
||||
if (data.location && (validator.isURL(data.location) || data.location.length > 255)) {
|
||||
throw new Error('[[error:invalid-location]]');
|
||||
}
|
||||
}
|
||||
|
||||
function isBirthdayValid(data) {
|
||||
if (!data.birthday) {
|
||||
return;
|
||||
|
||||
@@ -73,10 +73,6 @@
|
||||
<label class="form-label" for="min:rep:flag">[[admin/settings/reputation:min-rep-flag]]</label>
|
||||
<input type="number" class="form-control" placeholder="0" data-field="min:rep:flag" id="min:rep:flag">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="min:rep:website">[[admin/settings/reputation:min-rep-website]]</label>
|
||||
<input type="number" class="form-control" placeholder="0" data-field="min:rep:website" id="min:rep:website">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="min:rep:aboutme">[[admin/settings/reputation:min-rep-aboutme]]</label>
|
||||
<input type="number" class="form-control" placeholder="0" data-field="min:rep:aboutme" id="min:rep:aboutme">
|
||||
|
||||
Reference in New Issue
Block a user