Skip to content

Commit 9cf85ce

Browse files
committed
feat: add date and multiselect custom fields
1 parent e375038 commit 9cf85ce

File tree

8 files changed

+44
-8
lines changed

8 files changed

+44
-8
lines changed

public/language/en-GB/admin/manage/user-custom-fields.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
"input-type-text": "Input (Text)",
1313
"input-type-link": "Input (Link)",
1414
"input-type-number": "Input (Number)",
15+
"input-type-date": "Input (Date)",
1516
"input-type-select": "Select",
17+
"input-type-select-multi": "Select Multiple",
1618
"select-options": "Options",
1719
"select-options-help": "Add one option per line for the select element",
1820
"minimum-reputation": "Minimum reputation",

public/language/en-GB/error.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@
213213
"custom-user-field-select-value-invalid": "Custom field selected option is invalid, %1",
214214
"custom-user-field-invalid-link": "Custom field link is invalid, %1",
215215
"custom-user-field-invalid-number": "Custom field number is invalid, %1",
216+
"custom-user-field-invalid-date": "Custom field date is invalid, %1",
216217
"invalid-custom-user-field": "Invalid custom user field, \"%1\" is already used by NodeBB",
217218
"post-already-flagged": "You have already flagged this post",
218219
"user-already-flagged": "You have already flagged this user",

public/src/admin/manage/users/custom-fields.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ define('admin/manage/user/custom-fields', [
6969
label: '[[global:save]]',
7070
callback: function () {
7171
const formData = modal.find('form').serializeObject();
72-
if (formData.type === 'select') {
72+
if (formData.type === 'select' || formData.type === 'select-multi') {
7373
formData.selectOptionsFormatted = formData['select-options'].trim().split('\n').join(', ');
7474
}
7575

@@ -91,7 +91,7 @@ define('admin/manage/user/custom-fields', [
9191
modal.find('#type-select').on('change', function () {
9292
const type = $(this).val();
9393
modal.find(`[data-input-type]`).addClass('hidden');
94-
modal.find(`[data-input-type="${type}"]`).removeClass('hidden');
94+
modal.find(`[data-input-type-${type}]`).removeClass('hidden');
9595
});
9696

9797
modal.find('#icon-select').on('click', function () {

public/src/client/account/edit.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,18 @@ define('forum/account/edit', [
4646
const els = $('[component="group/badge/list"] [component="group/badge/item"][data-selected="true"]');
4747
return els.map((i, el) => $(el).attr('data-value')).get();
4848
}
49+
const editForm = $('form[component="profile/edit/form"]');
50+
const userData = editForm.serializeObject();
51+
52+
// stringify multi selects
53+
editForm.find('select[multiple]').each((i, el) => {
54+
const name = $(el).attr('name');
55+
if (userData[name] && !Array.isArray(userData[name])) {
56+
userData[name] = [userData[name]];
57+
}
58+
userData[name] = JSON.stringify(userData[name] || []);
59+
});
4960

50-
const userData = $('form[component="profile/edit/form"]').serializeObject();
5161
userData.uid = ajaxify.data.uid;
5262
userData.groupTitle = userData.groupTitle || '';
5363
userData.groupTitle = JSON.stringify(getGroupSelection());

src/controllers/accounts/helpers.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,23 @@ helpers.getCustomUserFields = async function (userData) {
144144
});
145145

146146
fields.forEach((f) => {
147+
let userValue = userData[f.key];
148+
if (f.type === 'select-multi' && userValue) {
149+
userValue = JSON.parse(userValue || '[]');
150+
}
147151
f['select-options'] = f['select-options'].split('\n').filter(Boolean).map(
148152
opt => ({
149153
value: opt,
150-
selected: opt === userData[f.key],
154+
selected: Array.isArray(userValue) ?
155+
userValue.includes(opt) :
156+
opt === userValue,
151157
})
152158
);
153-
if (userData[f.key]) {
154-
f.value = validator.escape(String(userData[f.key]));
159+
if (userValue) {
160+
if (Array.isArray(userValue)) {
161+
userValue = userValue.join(', ');
162+
}
163+
f.value = validator.escape(String(userValue));
155164
}
156165
});
157166
return fields;

src/user/profile.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ module.exports = function (User) {
113113
throw new Error(tx.compile(
114114
'error:custom-user-field-invalid-number', field.name
115115
));
116+
} else if (value && type === 'input-date' && !validator.isDate(value)) {
117+
throw new Error(tx.compile(
118+
'error:custom-user-field-invalid-date', field.name
119+
));
116120
} else if (value && field.type === 'input-link' && !validator.isURL(String(value))) {
117121
throw new Error(tx.compile(
118122
'error:custom-user-field-invalid-link', field.name
@@ -124,6 +128,14 @@ module.exports = function (User) {
124128
'error:custom-user-field-select-value-invalid', field.name
125129
));
126130
}
131+
} else if (field.type === 'select-multi') {
132+
const opts = field['select-options'].split('\n').filter(Boolean);
133+
const values = JSON.parse(value || '[]');
134+
if (!Array.isArray(values) || !values.every(value => opts.includes(value))) {
135+
throw new Error(tx.compile(
136+
'error:custom-user-field-select-value-invalid', field.name
137+
));
138+
}
127139
}
128140
}
129141
});

src/views/admin/manage/users/custom-fields.tpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
<td class="text-nowrap">{{{ if ./icon }}}<i class="text-muted {./icon}"></i> {{{ end }}}{./name}</td>
3636
<td>
3737
{./type}
38-
{{{ if (./type == "select") }}}
38+
{{{ if ((./type == "select") || (./type == "select-multi")) }}}
3939
<div class="text-muted">
4040
({./selectOptionsFormatted})
4141
</div>

src/views/admin/partials/manage-custom-user-fields-modal.tpl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
<option value="input-text" {{{ if (type == "input-text") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-text]]</option>
66
<option value="input-link" {{{ if (type == "input-link") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-link]]</option>
77
<option value="input-number" {{{ if (type == "input-number") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-number]]</option>
8+
<option value="input-date" {{{ if (type == "input-date") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-date]]</option>
89
<option value="select" {{{ if (type == "select") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-select]]</option>
10+
<option value="select-multi" {{{ if (type == "select-multi") }}}selected{{{ end }}}>[[admin/manage/user-custom-fields:input-type-select-multi]]</option>
911
</select>
1012
</div>
1113

@@ -33,7 +35,7 @@
3335
<p class="form-text">[[admin/manage/user-custom-fields:minimum-reputation-help]]</p>
3436
</div>
3537

36-
<div class="mb-3 {{{ if (type != "select") }}}hidden{{{ end }}}" data-input-type="select">
38+
<div class="mb-3 {{{ if ((type != "select") && (type != "select-multi")) }}}hidden{{{ end }}}" data-input-type data-input-type-select data-input-type-select-multi>
3739
<label class="form-label">[[admin/manage/user-custom-fields:select-options]]</label>
3840
<textarea class="form-control" name="select-options" rows="6">{./select-options}</textarea>
3941
<p class="form-text">[[admin/manage/user-custom-fields:select-options-help]]</p>

0 commit comments

Comments
 (0)