The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
Rocket.Chat/packages/rocketchat-api/server/v1/users.js

484 lines
14 KiB

import _ from 'underscore';
import Busboy from 'busboy';
RocketChat.API.v1.addRoute('users.create', { authRequired: true }, {
post() {
check(this.bodyParams, {
email: String,
name: String,
password: String,
username: String,
active: Match.Maybe(Boolean),
roles: Match.Maybe(Array),
joinDefaultChannels: Match.Maybe(Boolean),
requirePasswordChange: Match.Maybe(Boolean),
sendWelcomeEmail: Match.Maybe(Boolean),
verified: Match.Maybe(Boolean),
customFields: Match.Maybe(Object),
});
// New change made by pull request #5152
if (typeof this.bodyParams.joinDefaultChannels === 'undefined') {
this.bodyParams.joinDefaultChannels = true;
}
if (this.bodyParams.customFields) {
RocketChat.validateCustomFields(this.bodyParams.customFields);
}
const newUserId = RocketChat.saveUser(this.userId, this.bodyParams);
if (this.bodyParams.customFields) {
RocketChat.saveCustomFieldsWithoutValidation(newUserId, this.bodyParams.customFields);
}
if (typeof this.bodyParams.active !== 'undefined') {
Meteor.runAsUser(this.userId, () => {
Meteor.call('setUserActiveStatus', newUserId, this.bodyParams.active);
});
}
return RocketChat.API.v1.success({ user: RocketChat.models.Users.findOneById(newUserId, { fields: RocketChat.API.v1.defaultFieldsToExclude }) });
},
});
RocketChat.API.v1.addRoute('users.delete', { authRequired: true }, {
post() {
if (!RocketChat.authz.hasPermission(this.userId, 'delete-user')) {
return RocketChat.API.v1.unauthorized();
}
const user = this.getUserFromParams();
Meteor.runAsUser(this.userId, () => {
Meteor.call('deleteUser', user._id);
});
return RocketChat.API.v1.success();
},
});
RocketChat.API.v1.addRoute('users.deleteOwnAccount', { authRequired: true }, {
post() {
const { password } = this.bodyParams;
if (!password) {
return RocketChat.API.v1.failure('Body parameter "password" is required.');
}
if (!RocketChat.settings.get('Accounts_AllowDeleteOwnAccount')) {
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
Meteor.runAsUser(this.userId, () => {
Meteor.call('deleteUserOwnAccount', password);
});
return RocketChat.API.v1.success();
},
});
RocketChat.API.v1.addRoute('users.getAvatar', { authRequired: false }, {
get() {
const user = this.getUserFromParams();
const url = RocketChat.getURL(`/avatar/${ user.username }`, { cdn: false, full: true });
this.response.setHeader('Location', url);
return {
statusCode: 307,
body: url,
};
},
});
RocketChat.API.v1.addRoute('users.getPresence', { authRequired: true }, {
get() {
if (this.isUserFromParams()) {
const user = RocketChat.models.Users.findOneById(this.userId);
return RocketChat.API.v1.success({
presence: user.status,
connectionStatus: user.statusConnection,
lastLogin: user.lastLogin,
});
}
const user = this.getUserFromParams();
return RocketChat.API.v1.success({
presence: user.status,
});
},
});
RocketChat.API.v1.addRoute('users.info', { authRequired: true }, {
get() {
const { username } = this.getUserFromParams();
let result;
Meteor.runAsUser(this.userId, () => {
result = Meteor.call('getFullUserData', { username, limit: 1 });
});
if (!result || result.length !== 1) {
return RocketChat.API.v1.failure(`Failed to get the user data for the userId of "${ username }".`);
}
return RocketChat.API.v1.success({
user: result[0],
});
},
});
RocketChat.API.v1.addRoute('users.list', { authRequired: true }, {
get() {
if (!RocketChat.authz.hasPermission(this.userId, 'view-d-room')) {
return RocketChat.API.v1.unauthorized();
}
const { offset, count } = this.getPaginationItems();
const { sort, fields, query } = this.parseJsonQuery();
const users = RocketChat.models.Users.find(query, {
sort: sort ? sort : { username: 1 },
skip: offset,
limit: count,
fields,
}).fetch();
return RocketChat.API.v1.success({
users,
count: users.length,
offset,
total: RocketChat.models.Users.find(query).count(),
});
},
});
RocketChat.API.v1.addRoute('users.register', { authRequired: false }, {
post() {
if (this.userId) {
return RocketChat.API.v1.failure('Logged in users can not register again.');
}
// We set their username here, so require it
// The `registerUser` checks for the other requirements
check(this.bodyParams, Match.ObjectIncluding({
username: String,
}));
// Register the user
const userId = Meteor.call('registerUser', this.bodyParams);
// Now set their username
Meteor.runAsUser(userId, () => Meteor.call('setUsername', this.bodyParams.username));
return RocketChat.API.v1.success({ user: RocketChat.models.Users.findOneById(userId, { fields: RocketChat.API.v1.defaultFieldsToExclude }) });
},
});
RocketChat.API.v1.addRoute('users.resetAvatar', { authRequired: true }, {
post() {
const user = this.getUserFromParams();
if (user._id === this.userId) {
Meteor.runAsUser(this.userId, () => Meteor.call('resetAvatar'));
} else if (RocketChat.authz.hasPermission(this.userId, 'edit-other-user-info')) {
Meteor.runAsUser(user._id, () => Meteor.call('resetAvatar'));
} else {
return RocketChat.API.v1.unauthorized();
}
return RocketChat.API.v1.success();
},
});
RocketChat.API.v1.addRoute('users.setAvatar', { authRequired: true }, {
post() {
check(this.bodyParams, Match.ObjectIncluding({
avatarUrl: Match.Maybe(String),
userId: Match.Maybe(String),
username: Match.Maybe(String),
}));
if (!RocketChat.settings.get('Accounts_AllowUserAvatarChange')) {
throw new Meteor.Error('error-not-allowed', 'Change avatar is not allowed', {
method: 'users.setAvatar',
});
}
let user;
if (this.isUserFromParams()) {
user = Meteor.users.findOne(this.userId);
} else if (RocketChat.authz.hasPermission(this.userId, 'edit-other-user-info')) {
user = this.getUserFromParams();
} else {
return RocketChat.API.v1.unauthorized();
}
Meteor.runAsUser(user._id, () => {
if (this.bodyParams.avatarUrl) {
RocketChat.setUserAvatar(user, this.bodyParams.avatarUrl, '', 'url');
} else {
const busboy = new Busboy({ headers: this.request.headers });
Meteor.wrapAsync((callback) => {
busboy.on('file', Meteor.bindEnvironment((fieldname, file, filename, encoding, mimetype) => {
if (fieldname !== 'image') {
return callback(new Meteor.Error('invalid-field'));
}
const imageData = [];
file.on('data', Meteor.bindEnvironment((data) => {
imageData.push(data);
}));
file.on('end', Meteor.bindEnvironment(() => {
RocketChat.setUserAvatar(user, Buffer.concat(imageData), mimetype, 'rest');
callback();
}));
}));
this.request.pipe(busboy);
})();
}
});
return RocketChat.API.v1.success();
},
});
RocketChat.API.v1.addRoute('users.update', { authRequired: true }, {
post() {
check(this.bodyParams, {
userId: String,
data: Match.ObjectIncluding({
email: Match.Maybe(String),
name: Match.Maybe(String),
password: Match.Maybe(String),
username: Match.Maybe(String),
active: Match.Maybe(Boolean),
roles: Match.Maybe(Array),
joinDefaultChannels: Match.Maybe(Boolean),
requirePasswordChange: Match.Maybe(Boolean),
sendWelcomeEmail: Match.Maybe(Boolean),
verified: Match.Maybe(Boolean),
customFields: Match.Maybe(Object),
}),
});
const userData = _.extend({ _id: this.bodyParams.userId }, this.bodyParams.data);
Meteor.runAsUser(this.userId, () => RocketChat.saveUser(this.userId, userData));
if (this.bodyParams.data.customFields) {
RocketChat.saveCustomFields(this.bodyParams.userId, this.bodyParams.data.customFields);
}
if (typeof this.bodyParams.data.active !== 'undefined') {
Meteor.runAsUser(this.userId, () => {
Meteor.call('setUserActiveStatus', this.bodyParams.userId, this.bodyParams.data.active);
});
}
return RocketChat.API.v1.success({ user: RocketChat.models.Users.findOneById(this.bodyParams.userId, { fields: RocketChat.API.v1.defaultFieldsToExclude }) });
},
});
RocketChat.API.v1.addRoute('users.updateOwnBasicInfo', { authRequired: true }, {
post() {
check(this.bodyParams, {
data: Match.ObjectIncluding({
email: Match.Maybe(String),
name: Match.Maybe(String),
username: Match.Maybe(String),
currentPassword: Match.Maybe(String),
newPassword: Match.Maybe(String),
}),
customFields: Match.Maybe(Object),
});
const userData = {
email: this.bodyParams.data.email,
realname: this.bodyParams.data.name,
username: this.bodyParams.data.username,
newPassword: this.bodyParams.data.newPassword,
typedPassword: this.bodyParams.data.currentPassword,
};
Meteor.runAsUser(this.userId, () => Meteor.call('saveUserProfile', userData, this.bodyParams.customFields));
return RocketChat.API.v1.success({ user: RocketChat.models.Users.findOneById(this.userId, { fields: RocketChat.API.v1.defaultFieldsToExclude }) });
},
});
RocketChat.API.v1.addRoute('users.createToken', { authRequired: true }, {
post() {
const user = this.getUserFromParams();
let data;
Meteor.runAsUser(this.userId, () => {
data = Meteor.call('createToken', user._id);
});
return data ? RocketChat.API.v1.success({ data }) : RocketChat.API.v1.unauthorized();
},
});
RocketChat.API.v1.addRoute('users.getPreferences', { authRequired: true }, {
get() {
const user = RocketChat.models.Users.findOneById(this.userId);
if (user.settings) {
const { preferences } = user.settings;
preferences.language = user.language;
return RocketChat.API.v1.success({
preferences,
});
} else {
return RocketChat.API.v1.failure(TAPi18n.__('Accounts_Default_User_Preferences_not_available').toUpperCase());
}
},
});
RocketChat.API.v1.addRoute('users.setPreferences', { authRequired: true }, {
post() {
check(this.bodyParams, {
userId: Match.Maybe(String),
data: Match.ObjectIncluding({
newRoomNotification: Match.Maybe(String),
newMessageNotification: Match.Maybe(String),
useEmojis: Match.Maybe(Boolean),
convertAsciiEmoji: Match.Maybe(Boolean),
saveMobileBandwidth: Match.Maybe(Boolean),
collapseMediaByDefault: Match.Maybe(Boolean),
autoImageLoad: Match.Maybe(Boolean),
emailNotificationMode: Match.Maybe(String),
unreadAlert: Match.Maybe(Boolean),
notificationsSoundVolume: Match.Maybe(Number),
desktopNotifications: Match.Maybe(String),
mobileNotifications: Match.Maybe(String),
enableAutoAway: Match.Maybe(Boolean),
highlights: Match.Maybe(Array),
desktopNotificationDuration: Match.Maybe(Number),
messageViewMode: Match.Maybe(Number),
hideUsernames: Match.Maybe(Boolean),
hideRoles: Match.Maybe(Boolean),
hideAvatars: Match.Maybe(Boolean),
hideFlexTab: Match.Maybe(Boolean),
sendOnEnter: Match.Maybe(String),
roomCounterSidebar: Match.Maybe(Boolean),
language: Match.Maybe(String),
sidebarShowFavorites: Match.Optional(Boolean),
sidebarShowUnread: Match.Optional(Boolean),
sidebarSortby: Match.Optional(String),
sidebarViewMode: Match.Optional(String),
sidebarHideAvatar: Match.Optional(Boolean),
sidebarGroupByType: Match.Optional(Boolean),
muteFocusedConversations: Match.Optional(Boolean),
}),
});
const userId = this.bodyParams.userId ? this.bodyParams.userId : this.userId;
const userData = {
_id: userId,
settings: {
preferences: this.bodyParams.data,
},
};
if (this.bodyParams.data.language) {
const { language } = this.bodyParams.data;
delete this.bodyParams.data.language;
userData.language = language;
}
Meteor.runAsUser(this.userId, () => RocketChat.saveUser(this.userId, userData));
return RocketChat.API.v1.success({
user: RocketChat.models.Users.findOneById(userId, {
fields: {
'settings.preferences': 1,
},
}),
});
},
});
RocketChat.API.v1.addRoute('users.forgotPassword', { authRequired: false }, {
post() {
const { email } = this.bodyParams;
if (!email) {
return RocketChat.API.v1.failure('The \'email\' param is required');
}
const emailSent = Meteor.call('sendForgotPasswordEmail', email);
if (emailSent) {
return RocketChat.API.v1.success();
}
return RocketChat.API.v1.failure('User not found');
},
});
RocketChat.API.v1.addRoute('users.getUsernameSuggestion', { authRequired: true }, {
get() {
const result = Meteor.runAsUser(this.userId, () => Meteor.call('getUsernameSuggestion'));
return RocketChat.API.v1.success({ result });
},
});
RocketChat.API.v1.addRoute('users.generatePersonalAccessToken', { authRequired: true }, {
post() {
const { tokenName } = this.bodyParams;
if (!tokenName) {
return RocketChat.API.v1.failure('The \'tokenName\' param is required');
}
const token = Meteor.runAsUser(this.userId, () => Meteor.call('personalAccessTokens:generateToken', { tokenName }));
return RocketChat.API.v1.success({ token });
},
});
RocketChat.API.v1.addRoute('users.regeneratePersonalAccessToken', { authRequired: true }, {
post() {
const { tokenName } = this.bodyParams;
if (!tokenName) {
return RocketChat.API.v1.failure('The \'tokenName\' param is required');
}
const token = Meteor.runAsUser(this.userId, () => Meteor.call('personalAccessTokens:regenerateToken', { tokenName }));
return RocketChat.API.v1.success({ token });
},
});
RocketChat.API.v1.addRoute('users.getPersonalAccessTokens', { authRequired: true }, {
get() {
if (!RocketChat.settings.get('API_Enable_Personal_Access_Tokens')) {
throw new Meteor.Error('error-personal-access-tokens-are-current-disabled', 'Personal Access Tokens are currently disabled');
}
const loginTokens = RocketChat.models.Users.getLoginTokensByUserId(this.userId).fetch()[0];
const getPersonalAccessTokens = () => loginTokens.services.resume.loginTokens
.filter((loginToken) => loginToken.type && loginToken.type === 'personalAccessToken')
.map((loginToken) => ({
name: loginToken.name,
createdAt: loginToken.createdAt,
lastTokenPart: loginToken.lastTokenPart,
}));
return RocketChat.API.v1.success({
tokens: getPersonalAccessTokens(),
});
},
});
RocketChat.API.v1.addRoute('users.removePersonalAccessToken', { authRequired: true }, {
post() {
const { tokenName } = this.bodyParams;
if (!tokenName) {
return RocketChat.API.v1.failure('The \'tokenName\' param is required');
}
Meteor.runAsUser(this.userId, () => Meteor.call('personalAccessTokens:removeToken', {
tokenName,
}));
return RocketChat.API.v1.success();
},
});