mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-05-07 12:16:54 +02: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:
|
name:
|
||||||
type: string
|
type: string
|
||||||
description: The category's name/title
|
description: The category's name/title
|
||||||
|
nickname:
|
||||||
|
type: string
|
||||||
|
description: A nickname for the category.
|
||||||
handle:
|
handle:
|
||||||
type: string
|
type: string
|
||||||
description: |
|
description: |
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ get:
|
|||||||
type: string
|
type: string
|
||||||
bgColor:
|
bgColor:
|
||||||
type: string
|
type: string
|
||||||
|
backgroundImage:
|
||||||
|
type: string
|
||||||
descriptionParsed:
|
descriptionParsed:
|
||||||
type: string
|
type: string
|
||||||
depth:
|
depth:
|
||||||
|
|||||||
@@ -321,7 +321,12 @@ const utils = {
|
|||||||
}
|
}
|
||||||
return tag;
|
return tag;
|
||||||
},
|
},
|
||||||
|
createFieldChecker: function (fields = []) {
|
||||||
|
const allFields = !fields.length;
|
||||||
|
return function hasField(field) {
|
||||||
|
return allFields || fields.includes(field);
|
||||||
|
};
|
||||||
|
},
|
||||||
removePunctuation: function (str) {
|
removePunctuation: function (str) {
|
||||||
return str.replace(/[.,-/#!$%^&*;:{}=\-_`<>'"~()?]/g, '');
|
return str.replace(/[.,-/#!$%^&*;:{}=\-_`<>'"~()?]/g, '');
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -95,8 +95,8 @@ module.exports = function (Categories) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
function defaultIntField(category, fields, fieldName, defaultField) {
|
function defaultIntField(category, hasField, fieldName, defaultField) {
|
||||||
if (!fields.length || fields.includes(fieldName)) {
|
if (hasField(fieldName)) {
|
||||||
const useDefault = !category.hasOwnProperty(fieldName) ||
|
const useDefault = !category.hasOwnProperty(fieldName) ||
|
||||||
category[fieldName] === null ||
|
category[fieldName] === null ||
|
||||||
category[fieldName] === '' ||
|
category[fieldName] === '' ||
|
||||||
@@ -111,32 +111,37 @@ function modifyCategory(category, fields) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultIntField(category, fields, 'minTags', 'minimumTagsPerTopic');
|
const hasField = utils.createFieldChecker(fields);
|
||||||
defaultIntField(category, fields, 'maxTags', 'maximumTagsPerTopic');
|
|
||||||
defaultIntField(category, fields, 'postQueue', 'postQueue');
|
defaultIntField(category, hasField, 'minTags', 'minimumTagsPerTopic');
|
||||||
|
defaultIntField(category, hasField, 'maxTags', 'maximumTagsPerTopic');
|
||||||
|
defaultIntField(category, hasField, 'postQueue', 'postQueue');
|
||||||
|
|
||||||
db.parseIntFields(category, intFields, fields);
|
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) => {
|
escapeFields.forEach((field) => {
|
||||||
if (category.hasOwnProperty(field)) {
|
if (hasField(field)) {
|
||||||
category[field] = validator.escape(String(category[field] || ''));
|
category[field] = validator.escape(String(category[field] || ''));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (category.hasOwnProperty('icon')) {
|
if (hasField('icon')) {
|
||||||
category.icon = category.icon || 'hidden';
|
category.icon = category.icon || 'hidden';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (category.hasOwnProperty('post_count')) {
|
if (hasField('post_count')) {
|
||||||
category.totalPostCount = category.post_count;
|
category.totalPostCount = category.post_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (category.hasOwnProperty('topic_count')) {
|
if (hasField('topic_count')) {
|
||||||
category.totalTopicCount = category.topic_count;
|
category.totalTopicCount = category.topic_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (category.description) {
|
if (hasField('description')) {
|
||||||
category.descriptionParsed = category.descriptionParsed || category.description;
|
category.descriptionParsed = category.descriptionParsed || category.description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,38 +72,70 @@ module.exports = function (Groups) {
|
|||||||
|
|
||||||
function modifyGroup(group, fields) {
|
function modifyGroup(group, fields) {
|
||||||
if (group) {
|
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);
|
db.parseIntFields(group, intFields, fields);
|
||||||
|
|
||||||
escapeGroupData(group);
|
escapeGroupData(group, hasField);
|
||||||
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);
|
|
||||||
|
|
||||||
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'] ?
|
if (hasField('textColor')) {
|
||||||
prependRelativePath(group['cover:url']) :
|
group.textColor = validator.escape(String(group.textColor || '#ffffff'));
|
||||||
coverPhoto.getDefaultGroupCover(group.name);
|
}
|
||||||
|
|
||||||
group['cover:thumb:url'] = group['cover:thumb:url'] ?
|
if (hasField('icon')) {
|
||||||
prependRelativePath(group['cover:thumb:url']) :
|
group.icon = validator.escape(String(group.icon || ''));
|
||||||
coverPhoto.getDefaultGroupCover(group.name);
|
}
|
||||||
|
|
||||||
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) {
|
if (group) {
|
||||||
group.nameEncoded = encodeURIComponent(group.name);
|
if (hasField('name')) {
|
||||||
group.displayName = validator.escape(String(group.name));
|
group.nameEncoded = encodeURIComponent(group.name);
|
||||||
group.description = validator.escape(String(group.description || ''));
|
group.displayName = validator.escape(String(group.name));
|
||||||
group.userTitle = validator.escape(String(group.userTitle || ''));
|
}
|
||||||
group.userTitleEscaped = translator.escape(group.userTitle);
|
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) {
|
async function modifyMessage(message, fields, mid) {
|
||||||
if (message) {
|
if (message) {
|
||||||
|
const hasField = utils.createFieldChecker(fields);
|
||||||
db.parseIntFields(message, intFields, fields);
|
db.parseIntFields(message, intFields, fields);
|
||||||
if (message.hasOwnProperty('timestamp')) {
|
if (hasField('timestamp')) {
|
||||||
message.timestampISO = utils.toISOString(message.timestamp);
|
message.timestampISO = utils.toISOString(message.timestamp);
|
||||||
}
|
}
|
||||||
if (message.hasOwnProperty('edited')) {
|
if (hasField('edited')) {
|
||||||
message.editedISO = utils.toISOString(message.edited);
|
message.editedISO = utils.toISOString(message.edited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,20 +58,26 @@ module.exports = function (Posts) {
|
|||||||
function modifyPost(post, fields) {
|
function modifyPost(post, fields) {
|
||||||
if (post) {
|
if (post) {
|
||||||
db.parseIntFields(post, intFields, fields);
|
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;
|
post.votes = post.upvotes - post.downvotes;
|
||||||
}
|
}
|
||||||
if (post.hasOwnProperty('timestamp')) {
|
|
||||||
|
if (hasField('timestamp')) {
|
||||||
post.timestampISO = utils.toISOString(post.timestamp);
|
post.timestampISO = utils.toISOString(post.timestamp);
|
||||||
}
|
}
|
||||||
if (post.hasOwnProperty('edited')) {
|
|
||||||
|
if (hasField('edited')) {
|
||||||
post.editedISO = post.edited !== 0 ? utils.toISOString(post.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);
|
post.attachments = (post.attachments || '').split(',').filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fields.length || fields.includes('uploads')) {
|
if (hasField('uploads')) {
|
||||||
try {
|
try {
|
||||||
post.uploads = post.uploads ? JSON.parse(post.uploads) : [];
|
post.uploads = post.uploads ? JSON.parse(post.uploads) : [];
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -80,13 +80,11 @@ module.exports = function (Topics) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
function escapeTitle(topicData) {
|
function escapeTitle(topicData, hasField) {
|
||||||
if (topicData) {
|
if (topicData) {
|
||||||
if (topicData.title) {
|
if (hasField('title')) {
|
||||||
topicData.title = translator.escape(validator.escape(topicData.title));
|
topicData.title = translator.escape(validator.escape(topicData.title));
|
||||||
}
|
topicData.titleRaw = translator.escape(topicData.titleRaw || '');
|
||||||
if (topicData.titleRaw) {
|
|
||||||
topicData.titleRaw = translator.escape(topicData.titleRaw);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,39 +94,41 @@ function modifyTopic(topic, fields) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasField = utils.createFieldChecker(fields);
|
||||||
|
|
||||||
db.parseIntFields(topic, intFields, fields);
|
db.parseIntFields(topic, intFields, fields);
|
||||||
|
|
||||||
if (topic.hasOwnProperty('title')) {
|
if (hasField('title')) {
|
||||||
topic.titleRaw = topic.title;
|
topic.titleRaw = topic.title;
|
||||||
topic.title = String(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);
|
topic.timestampISO = utils.toISOString(topic.timestamp);
|
||||||
if (!fields.length || fields.includes('scheduled')) {
|
if (hasField('scheduled')) {
|
||||||
topic.scheduled = topic.timestamp > Date.now();
|
topic.scheduled = topic.timestamp > Date.now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (topic.hasOwnProperty('lastposttime')) {
|
if (hasField('lastposttime')) {
|
||||||
topic.lastposttimeISO = utils.toISOString(topic.lastposttime);
|
topic.lastposttimeISO = utils.toISOString(topic.lastposttime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (topic.hasOwnProperty('pinExpiry')) {
|
if (hasField('pinExpiry')) {
|
||||||
topic.pinExpiryISO = utils.toISOString(topic.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;
|
topic.votes = topic.upvotes - topic.downvotes;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fields.includes('teaserPid') || !fields.length) {
|
if (hasField('teaserPid')) {
|
||||||
topic.teaserPid = topic.teaserPid || null;
|
topic.teaserPid = topic.teaserPid || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fields.includes('tags') || !fields.length) {
|
if (hasField('tags')) {
|
||||||
const tags = String(topic.tags || '');
|
const tags = String(topic.tags || '');
|
||||||
topic.tags = tags.split(',').filter(Boolean).map((tag) => {
|
topic.tags = tags.split(',').filter(Boolean).map((tag) => {
|
||||||
const escaped = validator.escape(String(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 {
|
try {
|
||||||
topic.thumbs = topic.thumbs ? JSON.parse(String(topic.thumbs || '[]')) : [];
|
topic.thumbs = topic.thumbs ? JSON.parse(String(topic.thumbs || '[]')) : [];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -131,6 +131,18 @@ describe('Groups', () => {
|
|||||||
done();
|
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()', () => {
|
describe('.search()', () => {
|
||||||
@@ -139,7 +151,7 @@ describe('Groups', () => {
|
|||||||
it('should return empty array if query is falsy', (done) => {
|
it('should return empty array if query is falsy', (done) => {
|
||||||
Groups.search(null, {}, (err, groups) => {
|
Groups.search(null, {}, (err, groups) => {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.equal(0, groups.length);
|
assert.equal(groups.length, 0);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -147,7 +159,7 @@ describe('Groups', () => {
|
|||||||
it('should return the groups when search query is empty', (done) => {
|
it('should return the groups when search query is empty', (done) => {
|
||||||
socketGroups.search({ uid: adminUid }, { query: '' }, (err, groups) => {
|
socketGroups.search({ uid: adminUid }, { query: '' }, (err, groups) => {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.equal(5, groups.length);
|
assert.equal(groups.length, 6);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -155,8 +167,8 @@ describe('Groups', () => {
|
|||||||
it('should return the "Test" group when searched for', (done) => {
|
it('should return the "Test" group when searched for', (done) => {
|
||||||
socketGroups.search({ uid: adminUid }, { query: 'test' }, (err, groups) => {
|
socketGroups.search({ uid: adminUid }, { query: 'test' }, (err, groups) => {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.equal(2, groups.length);
|
assert.equal(groups.length, 2);
|
||||||
assert.strictEqual('Test', groups[0].name);
|
assert.strictEqual(groups[0].name, 'Test');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -164,8 +176,8 @@ describe('Groups', () => {
|
|||||||
it('should return the "Test" group when searched for and sort by member count', (done) => {
|
it('should return the "Test" group when searched for and sort by member count', (done) => {
|
||||||
Groups.search('test', { filterHidden: true, sort: 'count' }, (err, groups) => {
|
Groups.search('test', { filterHidden: true, sort: 'count' }, (err, groups) => {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.equal(2, groups.length);
|
assert.equal(groups.length, 2);
|
||||||
assert.strictEqual('Test', groups[0].name);
|
assert.strictEqual(groups[0].name, 'Test');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -173,8 +185,8 @@ describe('Groups', () => {
|
|||||||
it('should return the "Test" group when searched for and sort by creation time', (done) => {
|
it('should return the "Test" group when searched for and sort by creation time', (done) => {
|
||||||
Groups.search('test', { filterHidden: true, sort: 'date' }, (err, groups) => {
|
Groups.search('test', { filterHidden: true, sort: 'date' }, (err, groups) => {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.equal(2, groups.length);
|
assert.equal(groups.length, 2);
|
||||||
assert.strictEqual('Test', groups[1].name);
|
assert.strictEqual(groups[1].name, 'Test');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user