mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat(writeapi): user settings API
This commit is contained in:
143
public/openapi/components/schemas/SettingsObj.yaml
Normal file
143
public/openapi/components/schemas/SettingsObj.yaml
Normal file
@@ -0,0 +1,143 @@
|
||||
Settings:
|
||||
type: object
|
||||
properties:
|
||||
showemail:
|
||||
type: boolean
|
||||
description: Show user email in profile page
|
||||
usePagination:
|
||||
type: boolean
|
||||
description: Toggles between pagination (when enabled), or infinite scrolling (when disabled)
|
||||
topicsPerPage:
|
||||
type: number
|
||||
description: Number of topics displayed on a category page
|
||||
postsPerPage:
|
||||
type: number
|
||||
description: Number of posts displayed on a topic page
|
||||
topicPostSort:
|
||||
type: string
|
||||
description: Default sorting strategy of the posts in of a topic
|
||||
openOutgoingLinksInNewTab:
|
||||
type: boolean
|
||||
description: Whether to automatically open all external links in a new tab
|
||||
dailyDigestFreq:
|
||||
type: string
|
||||
description: How often to receive the scheduled digest from this forum
|
||||
showfullname:
|
||||
type: boolean
|
||||
description: Show user full name in profile page
|
||||
followTopicsOnCreate:
|
||||
type: boolean
|
||||
description: Automatically be notified of new posts in a topic, when you create a topic
|
||||
followTopicsOnReply:
|
||||
type: boolean
|
||||
description:
|
||||
restrictChat:
|
||||
type: boolean
|
||||
description:
|
||||
topicSearchEnabled:
|
||||
type: boolean
|
||||
description:
|
||||
categoryTopicSort:
|
||||
type: string
|
||||
description:
|
||||
userLang:
|
||||
type: string
|
||||
description:
|
||||
bootswatchSkin:
|
||||
type: string
|
||||
description:
|
||||
homePageRoute:
|
||||
type: string
|
||||
description:
|
||||
scrollToMyPost:
|
||||
type: boolean
|
||||
description:
|
||||
notificationType_new-chat:
|
||||
type: string
|
||||
description:
|
||||
notificationType_new-reply:
|
||||
type: string
|
||||
description:
|
||||
notificationType_post-edit:
|
||||
type: string
|
||||
description:
|
||||
sendChatNotifications:
|
||||
nullable: true
|
||||
sendPostNotifications:
|
||||
nullable: true
|
||||
notificationType_upvote:
|
||||
type: string
|
||||
description:
|
||||
notificationType_new-topic:
|
||||
type: string
|
||||
description:
|
||||
notificationType_follow:
|
||||
type: string
|
||||
description:
|
||||
notificationType_group-invite:
|
||||
type: string
|
||||
description:
|
||||
upvoteNotifFreq:
|
||||
type: string
|
||||
description:
|
||||
notificationType_mention:
|
||||
type: string
|
||||
description:
|
||||
acpLang:
|
||||
type: string
|
||||
description:
|
||||
notificationType_new-register:
|
||||
type: string
|
||||
description:
|
||||
notificationType_post-queue:
|
||||
type: string
|
||||
description:
|
||||
notificationType_new-post-flag:
|
||||
type: string
|
||||
description:
|
||||
notificationType_new-user-flag:
|
||||
type: string
|
||||
description:
|
||||
categoryWatchState:
|
||||
type: string
|
||||
description:
|
||||
notificationType_group-request-membership:
|
||||
type: string
|
||||
description:
|
||||
uid:
|
||||
type: number
|
||||
description:
|
||||
description: A user identifier
|
||||
required:
|
||||
- showemail
|
||||
- usePagination
|
||||
- topicsPerPage
|
||||
- postsPerPage
|
||||
- topicPostSort
|
||||
- openOutgoingLinksInNewTab
|
||||
- dailyDigestFreq
|
||||
- showfullname
|
||||
- followTopicsOnCreate
|
||||
- followTopicsOnReply
|
||||
- restrictChat
|
||||
- topicSearchEnabled
|
||||
- categoryTopicSort
|
||||
- userLang
|
||||
- bootswatchSkin
|
||||
- homePageRoute
|
||||
- scrollToMyPost
|
||||
- notificationType_new-chat
|
||||
- notificationType_new-reply
|
||||
- notificationType_upvote
|
||||
- notificationType_new-topic
|
||||
- notificationType_follow
|
||||
- notificationType_group-invite
|
||||
- upvoteNotifFreq
|
||||
- acpLang
|
||||
- notificationType_new-register
|
||||
- notificationType_post-queue
|
||||
- notificationType_new-post-flag
|
||||
- notificationType_new-user-flag
|
||||
- categoryWatchState
|
||||
- notificationType_group-request-membership
|
||||
- uid
|
||||
@@ -20,114 +20,7 @@ get:
|
||||
- type: object
|
||||
properties:
|
||||
settings:
|
||||
type: object
|
||||
properties:
|
||||
showemail:
|
||||
type: boolean
|
||||
usePagination:
|
||||
type: boolean
|
||||
topicsPerPage:
|
||||
type: number
|
||||
postsPerPage:
|
||||
type: number
|
||||
topicPostSort:
|
||||
type: string
|
||||
openOutgoingLinksInNewTab:
|
||||
type: boolean
|
||||
dailyDigestFreq:
|
||||
type: string
|
||||
showfullname:
|
||||
type: boolean
|
||||
followTopicsOnCreate:
|
||||
type: boolean
|
||||
followTopicsOnReply:
|
||||
type: boolean
|
||||
restrictChat:
|
||||
type: boolean
|
||||
topicSearchEnabled:
|
||||
type: boolean
|
||||
categoryTopicSort:
|
||||
type: string
|
||||
userLang:
|
||||
type: string
|
||||
bootswatchSkin:
|
||||
type: string
|
||||
homePageRoute:
|
||||
type: string
|
||||
scrollToMyPost:
|
||||
type: boolean
|
||||
notificationType_new-chat:
|
||||
type: string
|
||||
notificationType_new-reply:
|
||||
type: string
|
||||
notificationType_post-edit:
|
||||
type: string
|
||||
sendChatNotifications:
|
||||
nullable: true
|
||||
sendPostNotifications:
|
||||
nullable: true
|
||||
notificationType_upvote:
|
||||
type: string
|
||||
notificationType_new-topic:
|
||||
type: string
|
||||
notificationType_follow:
|
||||
type: string
|
||||
notificationType_group-invite:
|
||||
type: string
|
||||
upvoteNotifFreq:
|
||||
type: string
|
||||
notificationType_mention:
|
||||
type: string
|
||||
acpLang:
|
||||
type: string
|
||||
notificationType_new-register:
|
||||
type: string
|
||||
notificationType_post-queue:
|
||||
type: string
|
||||
notificationType_new-post-flag:
|
||||
type: string
|
||||
notificationType_new-user-flag:
|
||||
type: string
|
||||
categoryWatchState:
|
||||
type: string
|
||||
notificationType_group-request-membership:
|
||||
type: string
|
||||
uid:
|
||||
type: number
|
||||
description: A user identifier
|
||||
required:
|
||||
- showemail
|
||||
- usePagination
|
||||
- topicsPerPage
|
||||
- postsPerPage
|
||||
- topicPostSort
|
||||
- openOutgoingLinksInNewTab
|
||||
- dailyDigestFreq
|
||||
- showfullname
|
||||
- followTopicsOnCreate
|
||||
- followTopicsOnReply
|
||||
- restrictChat
|
||||
- topicSearchEnabled
|
||||
- categoryTopicSort
|
||||
- userLang
|
||||
- bootswatchSkin
|
||||
- homePageRoute
|
||||
- scrollToMyPost
|
||||
- notificationType_new-chat
|
||||
- notificationType_new-reply
|
||||
- notificationType_upvote
|
||||
- notificationType_new-topic
|
||||
- notificationType_follow
|
||||
- notificationType_group-invite
|
||||
- upvoteNotifFreq
|
||||
- acpLang
|
||||
- notificationType_new-register
|
||||
- notificationType_post-queue
|
||||
- notificationType_new-post-flag
|
||||
- notificationType_new-user-flag
|
||||
- categoryWatchState
|
||||
- notificationType_group-request-membership
|
||||
- uid
|
||||
$ref: ../../../components/schemas/SettingsObj.yaml#/Settings
|
||||
languages:
|
||||
type: array
|
||||
items:
|
||||
|
||||
@@ -30,6 +30,10 @@ tags:
|
||||
paths:
|
||||
/users/{uid}:
|
||||
$ref: 'write/users/uid.yaml'
|
||||
/users/{uid}/settings:
|
||||
$ref: 'write/users/uid/settings.yaml'
|
||||
/users/{uid}/settings/{setting}:
|
||||
$ref: 'write/users/uid/settings/setting.yaml'
|
||||
/users/{uid}/password:
|
||||
$ref: 'write/users/uid/password.yaml'
|
||||
/users/{uid}/follow:
|
||||
|
||||
35
public/openapi/write/users/uid/settings.yaml
Normal file
35
public/openapi/write/users/uid/settings.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
put:
|
||||
tags:
|
||||
- users
|
||||
summary: update user settings
|
||||
parameters:
|
||||
- in: path
|
||||
name: uid
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
description: uid of the user
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
settings:
|
||||
type: object
|
||||
description: An object containing key-value pairs of user settings to update
|
||||
example:
|
||||
showemail: '0'
|
||||
showfullname: '1'
|
||||
responses:
|
||||
'200':
|
||||
description: successfully updated user settings
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
$ref: ../../../components/schemas/Status.yaml#/Status
|
||||
response:
|
||||
$ref: ../../../components/schemas/SettingsObj.yaml#/Settings
|
||||
40
public/openapi/write/users/uid/settings/setting.yaml
Normal file
40
public/openapi/write/users/uid/settings/setting.yaml
Normal file
@@ -0,0 +1,40 @@
|
||||
put:
|
||||
tags:
|
||||
- users
|
||||
summary: update one user setting
|
||||
parameters:
|
||||
- in: path
|
||||
name: uid
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
description: uid of the user
|
||||
example: '1'
|
||||
- in: path
|
||||
name: setting
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
description: name of the setting you wish to update
|
||||
example: 'showemail'
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
value:
|
||||
type: string
|
||||
example: '1'
|
||||
responses:
|
||||
'200':
|
||||
description: successfully updated user settings
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
$ref: ../../../../components/schemas/Status.yaml#/Status
|
||||
response:
|
||||
type: object
|
||||
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
define('forum/account/settings', ['forum/account/header', 'components', 'translator'], function (header, components, translator) {
|
||||
define('forum/account/settings', ['forum/account/header', 'components', 'translator', 'api'], function (header, components, translator, api) {
|
||||
var AccountSettings = {};
|
||||
|
||||
// If page skin is changed but not saved, switch the skin back
|
||||
@@ -67,11 +67,7 @@ define('forum/account/settings', ['forum/account/header', 'components', 'transla
|
||||
}
|
||||
|
||||
function saveSettings(settings) {
|
||||
socket.emit('user.saveSettings', { uid: ajaxify.data.theirid, settings: settings }, function (err, newSettings) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
api.put(`/users/${ajaxify.data.uid}/settings`, { settings }).then((newSettings) => {
|
||||
app.alertSuccess('[[success:settings-saved]]');
|
||||
var languageChanged = false;
|
||||
for (var key in newSettings) {
|
||||
|
||||
@@ -24,7 +24,7 @@ define('forum/category', [
|
||||
|
||||
topicList.init('category', loadTopicsAfter);
|
||||
|
||||
sort.handleSort('categoryTopicSort', 'user.setCategorySort', 'category/' + ajaxify.data.slug);
|
||||
sort.handleSort('categoryTopicSort', 'setCategorySort', 'category/' + ajaxify.data.slug);
|
||||
|
||||
if (!config.usePagination) {
|
||||
navigator.init('[component="category/topic"]', ajaxify.data.topic_count, Category.toTop, Category.toBottom, Category.navigatorCallback);
|
||||
|
||||
@@ -49,7 +49,7 @@ define('forum/topic', [
|
||||
threadTools.init(tid, $('.topic'));
|
||||
events.init();
|
||||
|
||||
sort.handleSort('topicPostSort', 'user.setTopicSort', 'topic/' + ajaxify.data.slug);
|
||||
sort.handleSort('topicPostSort', 'setTopicSort', 'topic/' + ajaxify.data.slug);
|
||||
|
||||
if (!config.usePagination) {
|
||||
infinitescroll.init($('[component="topic"]'), posts.loadMorePosts);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
define('sort', ['components'], function (components) {
|
||||
define('sort', ['components', 'api'], function (components, api) {
|
||||
var module = {};
|
||||
|
||||
module.handleSort = function (field, method, gotoOnSave) {
|
||||
module.handleSort = function (field, key, gotoOnSave) {
|
||||
var threadSort = components.get('thread/sort');
|
||||
threadSort.find('i').removeClass('fa-check');
|
||||
var currentSetting = threadSort.find('a[data-sort="' + config[field] + '"]');
|
||||
@@ -20,10 +20,9 @@ define('sort', ['components'], function (components) {
|
||||
}
|
||||
var newSetting = $(this).attr('data-sort');
|
||||
if (app.user.uid) {
|
||||
socket.emit(method, newSetting, function (err) {
|
||||
if (err) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
api.put(`/users/${app.user.uid}/settings/${key}`, {
|
||||
value: newSetting,
|
||||
}).then(() => {
|
||||
refresh(newSetting, utils.params());
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -89,6 +89,23 @@ usersAPI.deleteMany = async function (caller, data) {
|
||||
}
|
||||
};
|
||||
|
||||
usersAPI.updateSettings = async function (caller, data) {
|
||||
if (!caller.uid || !data || !data.settings) {
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
|
||||
const canEdit = await privileges.users.canEdit(caller.uid, data.uid);
|
||||
if (!canEdit) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
|
||||
return await user.saveSettings(data.uid, data.settings);
|
||||
};
|
||||
|
||||
usersAPI.updateSetting = async function (caller, data) {
|
||||
await user.setSetting(data.uid, data.setting, data.value);
|
||||
};
|
||||
|
||||
usersAPI.changePassword = async function (caller, data) {
|
||||
await user.changePassword(caller.uid, Object.assign(data, { ip: caller.ip }));
|
||||
await events.log({
|
||||
|
||||
@@ -28,6 +28,16 @@ Users.deleteMany = async (req, res) => {
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
Users.updateSettings = async (req, res) => {
|
||||
const settings = await api.users.updateSettings(req, { ...req.body, uid: req.params.uid });
|
||||
helpers.formatApiResponse(200, res, settings);
|
||||
};
|
||||
|
||||
Users.updateSetting = async (req, res) => {
|
||||
await api.users.updateSetting(req, { ...req.params, value: req.body.value });
|
||||
helpers.formatApiResponse(200, res);
|
||||
};
|
||||
|
||||
Users.changePassword = async (req, res) => {
|
||||
await api.users.changePassword(req, { ...req.body, uid: req.params.uid });
|
||||
helpers.formatApiResponse(200, res);
|
||||
|
||||
@@ -21,6 +21,9 @@ function authenticatedRoutes() {
|
||||
setupApiRoute(router, 'put', '/:uid', [...middlewares, middleware.assert.user], controllers.write.users.update);
|
||||
setupApiRoute(router, 'delete', '/:uid', [...middlewares, middleware.assert.user, middleware.exposePrivileges], controllers.write.users.delete);
|
||||
|
||||
setupApiRoute(router, 'put', '/:uid/settings', [...middlewares, middleware.checkRequired.bind(null, ['settings'])], controllers.write.users.updateSettings);
|
||||
setupApiRoute(router, 'put', '/:uid/settings/:setting', [...middlewares, middleware.checkRequired.bind(null, ['value'])], controllers.write.users.updateSetting);
|
||||
|
||||
setupApiRoute(router, 'put', '/:uid/password', [...middlewares, middleware.checkRequired.bind(null, ['newPassword']), middleware.assert.user], controllers.write.users.changePassword);
|
||||
|
||||
setupApiRoute(router, 'put', '/:uid/follow', [...middlewares, middleware.assert.user], controllers.write.users.follow);
|
||||
|
||||
@@ -168,22 +168,27 @@ SocketUser.unfollow = async function (socket, data) {
|
||||
};
|
||||
|
||||
SocketUser.saveSettings = async function (socket, data) {
|
||||
if (!socket.uid || !data || !data.settings) {
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
const canEdit = await privileges.users.canEdit(socket.uid, data.uid);
|
||||
if (!canEdit) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
return await user.saveSettings(data.uid, data.settings);
|
||||
sockets.warnDeprecated(socket, 'PUT /api/v3/users/:uid/settings');
|
||||
const settings = await api.users.updateSettings(socket, data);
|
||||
return settings;
|
||||
};
|
||||
|
||||
SocketUser.setTopicSort = async function (socket, sort) {
|
||||
await user.setSetting(socket.uid, 'topicPostSort', sort);
|
||||
sockets.warnDeprecated(socket, 'PUT /api/v3/users/:uid/setting/topicPostSort');
|
||||
await api.users.updateSetting(socket, {
|
||||
uid: socket.uid,
|
||||
setting: 'topicPostSort',
|
||||
value: sort,
|
||||
});
|
||||
};
|
||||
|
||||
SocketUser.setCategorySort = async function (socket, sort) {
|
||||
await user.setSetting(socket.uid, 'categoryTopicSort', sort);
|
||||
sockets.warnDeprecated(socket, 'PUT /api/v3/users/:uid/setting/categoryTopicSort');
|
||||
await api.users.updateSetting(socket, {
|
||||
uid: socket.uid,
|
||||
setting: 'categoryTopicSort',
|
||||
value: sort,
|
||||
});
|
||||
};
|
||||
|
||||
SocketUser.getUnreadCount = async function (socket) {
|
||||
|
||||
Reference in New Issue
Block a user