mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-02-13 18:17:42 +01:00
refactor: add createFieldChecker (#13973)
* refactor: add createFieldChecker * refactor: use hasField in topic/data.js * refactor: use hasField in categories/data.js * test: fix category nickname logic * test: fix spec
This commit is contained in:
@@ -8,6 +8,9 @@ CategoryObject:
|
||||
name:
|
||||
type: string
|
||||
description: The category's name/title
|
||||
nickname:
|
||||
type: string
|
||||
description: A nickname for the category.
|
||||
handle:
|
||||
type: string
|
||||
description: |
|
||||
|
||||
@@ -42,6 +42,8 @@ get:
|
||||
type: string
|
||||
bgColor:
|
||||
type: string
|
||||
backgroundImage:
|
||||
type: string
|
||||
descriptionParsed:
|
||||
type: string
|
||||
depth:
|
||||
|
||||
@@ -321,7 +321,12 @@ const utils = {
|
||||
}
|
||||
return tag;
|
||||
},
|
||||
|
||||
createFieldChecker: function (fields = []) {
|
||||
const allFields = !fields.length;
|
||||
return function hasField(field) {
|
||||
return allFields || fields.includes(field);
|
||||
};
|
||||
},
|
||||
removePunctuation: function (str) {
|
||||
return str.replace(/[.,-/#!$%^&*;:{}=\-_`<>'"~()?]/g, '');
|
||||
},
|
||||
|
||||
@@ -95,8 +95,8 @@ module.exports = function (Categories) {
|
||||
};
|
||||
};
|
||||
|
||||
function defaultIntField(category, fields, fieldName, defaultField) {
|
||||
if (!fields.length || fields.includes(fieldName)) {
|
||||
function defaultIntField(category, hasField, fieldName, defaultField) {
|
||||
if (hasField(fieldName)) {
|
||||
const useDefault = !category.hasOwnProperty(fieldName) ||
|
||||
category[fieldName] === null ||
|
||||
category[fieldName] === '' ||
|
||||
@@ -111,32 +111,37 @@ function modifyCategory(category, fields) {
|
||||
return;
|
||||
}
|
||||
|
||||
defaultIntField(category, fields, 'minTags', 'minimumTagsPerTopic');
|
||||
defaultIntField(category, fields, 'maxTags', 'maximumTagsPerTopic');
|
||||
defaultIntField(category, fields, 'postQueue', 'postQueue');
|
||||
const hasField = utils.createFieldChecker(fields);
|
||||
|
||||
defaultIntField(category, hasField, 'minTags', 'minimumTagsPerTopic');
|
||||
defaultIntField(category, hasField, 'maxTags', 'maximumTagsPerTopic');
|
||||
defaultIntField(category, hasField, 'postQueue', 'postQueue');
|
||||
|
||||
db.parseIntFields(category, intFields, fields);
|
||||
|
||||
const escapeFields = ['name', 'nickname', 'description', 'color', 'bgColor', 'backgroundImage', 'imageClass', 'class', 'link'];
|
||||
const escapeFields = [
|
||||
'name', 'nickname', 'description', 'color', 'bgColor',
|
||||
'backgroundImage', 'imageClass', 'class', 'link',
|
||||
];
|
||||
escapeFields.forEach((field) => {
|
||||
if (category.hasOwnProperty(field)) {
|
||||
if (hasField(field)) {
|
||||
category[field] = validator.escape(String(category[field] || ''));
|
||||
}
|
||||
});
|
||||
|
||||
if (category.hasOwnProperty('icon')) {
|
||||
if (hasField('icon')) {
|
||||
category.icon = category.icon || 'hidden';
|
||||
}
|
||||
|
||||
if (category.hasOwnProperty('post_count')) {
|
||||
if (hasField('post_count')) {
|
||||
category.totalPostCount = category.post_count;
|
||||
}
|
||||
|
||||
if (category.hasOwnProperty('topic_count')) {
|
||||
if (hasField('topic_count')) {
|
||||
category.totalTopicCount = category.topic_count;
|
||||
}
|
||||
|
||||
if (category.description) {
|
||||
if (hasField('description')) {
|
||||
category.descriptionParsed = category.descriptionParsed || category.description;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,38 +72,70 @@ module.exports = function (Groups) {
|
||||
|
||||
function modifyGroup(group, fields) {
|
||||
if (group) {
|
||||
const hasField = utils.createFieldChecker(fields);
|
||||
|
||||
if (hasField('private')) {
|
||||
// Default to private if not set, as groups are private by default
|
||||
group.private = ([null, undefined].includes(group.private)) ? 1 : group.private;
|
||||
}
|
||||
|
||||
db.parseIntFields(group, intFields, fields);
|
||||
|
||||
escapeGroupData(group);
|
||||
group.userTitleEnabled = ([null, undefined].includes(group.userTitleEnabled)) ? 1 : group.userTitleEnabled;
|
||||
group.labelColor = validator.escape(String(group.labelColor || '#000000'));
|
||||
group.textColor = validator.escape(String(group.textColor || '#ffffff'));
|
||||
group.icon = validator.escape(String(group.icon || ''));
|
||||
group.createtimeISO = utils.toISOString(group.createtime);
|
||||
group.private = ([null, undefined].includes(group.private)) ? 1 : group.private;
|
||||
group.memberPostCids = group.memberPostCids || '';
|
||||
group.memberPostCidsArray = group.memberPostCids.split(',').map(cid => parseInt(cid, 10)).filter(Boolean);
|
||||
escapeGroupData(group, hasField);
|
||||
|
||||
group['cover:thumb:url'] = group['cover:thumb:url'] || group['cover:url'];
|
||||
if (hasField('labelColor')) {
|
||||
group.labelColor = validator.escape(String(group.labelColor || '#000000'));
|
||||
}
|
||||
|
||||
group['cover:url'] = group['cover:url'] ?
|
||||
prependRelativePath(group['cover:url']) :
|
||||
coverPhoto.getDefaultGroupCover(group.name);
|
||||
if (hasField('textColor')) {
|
||||
group.textColor = validator.escape(String(group.textColor || '#ffffff'));
|
||||
}
|
||||
|
||||
group['cover:thumb:url'] = group['cover:thumb:url'] ?
|
||||
prependRelativePath(group['cover:thumb:url']) :
|
||||
coverPhoto.getDefaultGroupCover(group.name);
|
||||
if (hasField('icon')) {
|
||||
group.icon = validator.escape(String(group.icon || ''));
|
||||
}
|
||||
|
||||
group['cover:position'] = validator.escape(String(group['cover:position'] || '50% 50%'));
|
||||
if (hasField('createtime')) {
|
||||
group.createtimeISO = utils.toISOString(group.createtime);
|
||||
}
|
||||
|
||||
if (hasField('memberPostCids')) {
|
||||
group.memberPostCids = group.memberPostCids || '';
|
||||
group.memberPostCidsArray = group.memberPostCids.split(',').map(cid => parseInt(cid, 10)).filter(Boolean);
|
||||
}
|
||||
|
||||
if (hasField('cover:thumb:url')) {
|
||||
group['cover:thumb:url'] = group['cover:thumb:url'] || group['cover:url'];
|
||||
|
||||
group['cover:thumb:url'] = group['cover:thumb:url'] ?
|
||||
prependRelativePath(group['cover:thumb:url']) :
|
||||
coverPhoto.getDefaultGroupCover(group.name);
|
||||
}
|
||||
|
||||
if (hasField('cover:url')) {
|
||||
group['cover:url'] = group['cover:url'] ?
|
||||
prependRelativePath(group['cover:url']) :
|
||||
coverPhoto.getDefaultGroupCover(group.name);
|
||||
}
|
||||
|
||||
if (hasField('cover:position')) {
|
||||
group['cover:position'] = validator.escape(String(group['cover:position'] || '50% 50%'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function escapeGroupData(group) {
|
||||
function escapeGroupData(group, hasField) {
|
||||
if (group) {
|
||||
group.nameEncoded = encodeURIComponent(group.name);
|
||||
group.displayName = validator.escape(String(group.name));
|
||||
group.description = validator.escape(String(group.description || ''));
|
||||
group.userTitle = validator.escape(String(group.userTitle || ''));
|
||||
group.userTitleEscaped = translator.escape(group.userTitle);
|
||||
if (hasField('name')) {
|
||||
group.nameEncoded = encodeURIComponent(group.name);
|
||||
group.displayName = validator.escape(String(group.name));
|
||||
}
|
||||
if (hasField('description')) {
|
||||
group.description = validator.escape(String(group.description || ''));
|
||||
}
|
||||
if (hasField('userTitle')) {
|
||||
group.userTitle = validator.escape(String(group.userTitle || ''));
|
||||
group.userTitleEscaped = translator.escape(group.userTitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,11 +196,12 @@ module.exports = function (Messaging) {
|
||||
|
||||
async function modifyMessage(message, fields, mid) {
|
||||
if (message) {
|
||||
const hasField = utils.createFieldChecker(fields);
|
||||
db.parseIntFields(message, intFields, fields);
|
||||
if (message.hasOwnProperty('timestamp')) {
|
||||
if (hasField('timestamp')) {
|
||||
message.timestampISO = utils.toISOString(message.timestamp);
|
||||
}
|
||||
if (message.hasOwnProperty('edited')) {
|
||||
if (hasField('edited')) {
|
||||
message.editedISO = utils.toISOString(message.edited);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,20 +58,26 @@ module.exports = function (Posts) {
|
||||
function modifyPost(post, fields) {
|
||||
if (post) {
|
||||
db.parseIntFields(post, intFields, fields);
|
||||
if (post.hasOwnProperty('upvotes') && post.hasOwnProperty('downvotes')) {
|
||||
|
||||
const hasField = utils.createFieldChecker(fields);
|
||||
|
||||
if (hasField('upvotes') && hasField('downvotes')) {
|
||||
post.votes = post.upvotes - post.downvotes;
|
||||
}
|
||||
if (post.hasOwnProperty('timestamp')) {
|
||||
|
||||
if (hasField('timestamp')) {
|
||||
post.timestampISO = utils.toISOString(post.timestamp);
|
||||
}
|
||||
if (post.hasOwnProperty('edited')) {
|
||||
|
||||
if (hasField('edited')) {
|
||||
post.editedISO = post.edited !== 0 ? utils.toISOString(post.edited) : '';
|
||||
}
|
||||
if (!fields.length || fields.includes('attachments')) {
|
||||
|
||||
if (hasField('attachments')) {
|
||||
post.attachments = (post.attachments || '').split(',').filter(Boolean);
|
||||
}
|
||||
|
||||
if (!fields.length || fields.includes('uploads')) {
|
||||
if (hasField('uploads')) {
|
||||
try {
|
||||
post.uploads = post.uploads ? JSON.parse(post.uploads) : [];
|
||||
} catch (err) {
|
||||
|
||||
@@ -80,13 +80,11 @@ module.exports = function (Topics) {
|
||||
};
|
||||
};
|
||||
|
||||
function escapeTitle(topicData) {
|
||||
function escapeTitle(topicData, hasField) {
|
||||
if (topicData) {
|
||||
if (topicData.title) {
|
||||
if (hasField('title')) {
|
||||
topicData.title = translator.escape(validator.escape(topicData.title));
|
||||
}
|
||||
if (topicData.titleRaw) {
|
||||
topicData.titleRaw = translator.escape(topicData.titleRaw);
|
||||
topicData.titleRaw = translator.escape(topicData.titleRaw || '');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,39 +94,41 @@ function modifyTopic(topic, fields) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hasField = utils.createFieldChecker(fields);
|
||||
|
||||
db.parseIntFields(topic, intFields, fields);
|
||||
|
||||
if (topic.hasOwnProperty('title')) {
|
||||
if (hasField('title')) {
|
||||
topic.titleRaw = topic.title;
|
||||
topic.title = String(topic.title);
|
||||
}
|
||||
|
||||
escapeTitle(topic);
|
||||
escapeTitle(topic, hasField);
|
||||
|
||||
if (topic.hasOwnProperty('timestamp')) {
|
||||
if (hasField('timestamp')) {
|
||||
topic.timestampISO = utils.toISOString(topic.timestamp);
|
||||
if (!fields.length || fields.includes('scheduled')) {
|
||||
if (hasField('scheduled')) {
|
||||
topic.scheduled = topic.timestamp > Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
if (topic.hasOwnProperty('lastposttime')) {
|
||||
if (hasField('lastposttime')) {
|
||||
topic.lastposttimeISO = utils.toISOString(topic.lastposttime);
|
||||
}
|
||||
|
||||
if (topic.hasOwnProperty('pinExpiry')) {
|
||||
if (hasField('pinExpiry')) {
|
||||
topic.pinExpiryISO = utils.toISOString(topic.pinExpiry);
|
||||
}
|
||||
|
||||
if (topic.hasOwnProperty('upvotes') && topic.hasOwnProperty('downvotes')) {
|
||||
if (hasField('upvotes') && hasField('downvotes')) {
|
||||
topic.votes = topic.upvotes - topic.downvotes;
|
||||
}
|
||||
|
||||
if (fields.includes('teaserPid') || !fields.length) {
|
||||
if (hasField('teaserPid')) {
|
||||
topic.teaserPid = topic.teaserPid || null;
|
||||
}
|
||||
|
||||
if (fields.includes('tags') || !fields.length) {
|
||||
if (hasField('tags')) {
|
||||
const tags = String(topic.tags || '');
|
||||
topic.tags = tags.split(',').filter(Boolean).map((tag) => {
|
||||
const escaped = validator.escape(String(tag));
|
||||
@@ -141,7 +141,7 @@ function modifyTopic(topic, fields) {
|
||||
});
|
||||
}
|
||||
|
||||
if (fields.includes('thumbs') || !fields.length) {
|
||||
if (hasField('thumbs')) {
|
||||
try {
|
||||
topic.thumbs = topic.thumbs ? JSON.parse(String(topic.thumbs || '[]')) : [];
|
||||
} catch (e) {
|
||||
|
||||
@@ -131,6 +131,18 @@ describe('Groups', () => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return only requested fields', async () => {
|
||||
await Groups.create({
|
||||
name: 'groupfields',
|
||||
description: 'desc',
|
||||
userTitle: 'utitle',
|
||||
});
|
||||
const data = await Groups.getGroupFields('groupfields', ['description', 'icon']);
|
||||
assert.strictEqual(Object.keys(data).length, 2);
|
||||
assert.strictEqual(data.description, 'desc');
|
||||
assert.strictEqual(data.icon, '');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.search()', () => {
|
||||
@@ -139,7 +151,7 @@ describe('Groups', () => {
|
||||
it('should return empty array if query is falsy', (done) => {
|
||||
Groups.search(null, {}, (err, groups) => {
|
||||
assert.ifError(err);
|
||||
assert.equal(0, groups.length);
|
||||
assert.equal(groups.length, 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -147,7 +159,7 @@ describe('Groups', () => {
|
||||
it('should return the groups when search query is empty', (done) => {
|
||||
socketGroups.search({ uid: adminUid }, { query: '' }, (err, groups) => {
|
||||
assert.ifError(err);
|
||||
assert.equal(5, groups.length);
|
||||
assert.equal(groups.length, 6);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -155,8 +167,8 @@ describe('Groups', () => {
|
||||
it('should return the "Test" group when searched for', (done) => {
|
||||
socketGroups.search({ uid: adminUid }, { query: 'test' }, (err, groups) => {
|
||||
assert.ifError(err);
|
||||
assert.equal(2, groups.length);
|
||||
assert.strictEqual('Test', groups[0].name);
|
||||
assert.equal(groups.length, 2);
|
||||
assert.strictEqual(groups[0].name, 'Test');
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -164,8 +176,8 @@ describe('Groups', () => {
|
||||
it('should return the "Test" group when searched for and sort by member count', (done) => {
|
||||
Groups.search('test', { filterHidden: true, sort: 'count' }, (err, groups) => {
|
||||
assert.ifError(err);
|
||||
assert.equal(2, groups.length);
|
||||
assert.strictEqual('Test', groups[0].name);
|
||||
assert.equal(groups.length, 2);
|
||||
assert.strictEqual(groups[0].name, 'Test');
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -173,8 +185,8 @@ describe('Groups', () => {
|
||||
it('should return the "Test" group when searched for and sort by creation time', (done) => {
|
||||
Groups.search('test', { filterHidden: true, sort: 'date' }, (err, groups) => {
|
||||
assert.ifError(err);
|
||||
assert.equal(2, groups.length);
|
||||
assert.strictEqual('Test', groups[1].name);
|
||||
assert.equal(groups.length, 2);
|
||||
assert.strictEqual(groups[1].name, 'Test');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user