Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEW] Custom User Status #13933

Merged
merged 85 commits into from
Jun 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
dc62eea
Custom User Status
Hudell Jan 5, 2018
58c8d81
Set Chosen Custom User Status
Hudell Jan 5, 2018
c9538ff
Line Endings and Identation
Hudell Jan 8, 2018
bc7a5b8
Code Quality
Hudell Jan 8, 2018
6097fb4
Globals
Hudell Jan 8, 2018
0acbd45
Code Quality
Hudell Jan 8, 2018
67c4abd
Merge branch 'develop' into custom_user_status
Hudell Mar 5, 2018
02931ee
Adjusted for the new sidebar
Hudell Mar 6, 2018
89059f6
Applying the custom status
Hudell Mar 6, 2018
36ad8ed
Merge branch 'develop' into custom_user_status
pierre-lehnen-rc Mar 6, 2018
0d0e3b0
Adding user custom status
Hudell Mar 6, 2018
8224807
Completed the functionality
Hudell Mar 7, 2018
bc6560b
Merge branch 'develop' into custom_user_status
Hudell Mar 7, 2018
993b122
Merge branch 'develop' into custom_user_status
Hudell Mar 27, 2018
acdc533
Applied changes to user status capitalizations
Hudell Mar 27, 2018
948194a
Merge branch 'develop' into custom_user_status
Hudell Apr 17, 2018
d7e7e2e
Removed auto translation from popover
Hudell Apr 17, 2018
de14551
Merge branch 'develop' into custom_user_status
Hudell Apr 18, 2018
0898029
Merge branch 'develop' into custom_user_status
engelgabriel Apr 18, 2018
353e919
Fixed problems reported on review
Hudell Apr 18, 2018
ab0e6dc
Merge branch 'develop' into custom_user_status
Hudell Apr 18, 2018
95eef88
Merge branch 'custom_user_status' of github.com:Hudell/Rocket.Chat in…
Hudell Apr 18, 2018
98cc689
Merge branch 'develop' into custom_user_status
Hudell Apr 24, 2018
9425459
backward compatibility
Hudell Apr 24, 2018
2a4f1e8
Merge branch 'develop' into custom_user_status
pierre-lehnen-rc Oct 16, 2018
8fe2520
new eslint rules
pierre-lehnen-rc Oct 16, 2018
79b8005
Popover was being closed whenever the user typed anything, even if th…
pierre-lehnen-rc Oct 17, 2018
97b305f
User Status Messages
wreiske Mar 17, 2019
50bb92b
Added statusMessage to users api
wreiske Mar 17, 2019
e61b031
Added rocket.chat message to status slash command
wreiske Mar 17, 2019
83703b7
Added status message too long to slash command
wreiske Mar 17, 2019
2138728
Added maxlength to status on profile and edit status modal
wreiske Mar 17, 2019
c593690
Added edit status from admin user UI
wreiske Mar 17, 2019
bf95e1a
Merge branch 'develop' into develop
wreiske Mar 19, 2019
5952752
Merge branch 'develop' into develop
wreiske Mar 19, 2019
d7d2d67
Merge branch 'develop' into custom_user_status
pierre-lehnen-rc Mar 22, 2019
585136e
Updating code to new standards
pierre-lehnen-rc Mar 22, 2019
1a000ff
Merge branch 'develop' into custom_user_status
pierre-lehnen-rc Mar 22, 2019
ae46905
Merge branch 'custom-status-wreiske' into custom_user_status
pierre-lehnen-rc Mar 22, 2019
b47597d
Merge branch 'develop' into develop
wreiske Mar 23, 2019
6fdb54b
setStatus and getStatus rest API
wreiske Mar 23, 2019
8ecbe83
Fixed chimp test related to user status messages
wreiske Mar 25, 2019
ffa8e4d
Merge branch 'develop' into develop
wreiske Mar 25, 2019
1bcaba2
Merge branch 'develop' into develop
wreiske Mar 25, 2019
01df8a4
Merge branch 'develop' into develop
wreiske Mar 25, 2019
86e5cdb
Merging functionality between both Custom Status implementations
pierre-lehnen-rc Mar 25, 2019
d4c8d65
Merge branch 'custom-status-wreiske' into custom_user_status
pierre-lehnen-rc Mar 25, 2019
c2f6520
Working on the status type
pierre-lehnen-rc Mar 26, 2019
89b5c0d
All features of the new user status system are operational
pierre-lehnen-rc Mar 28, 2019
6d56ef2
Merge branch 'develop' into custom_user_status
pierre-lehnen-rc Apr 9, 2019
94629d2
Fixed Status Type color on Edit Status popup
pierre-lehnen-rc Apr 10, 2019
7079fdb
Added empty lines according to CSS styling rules
pierre-lehnen-rc Apr 10, 2019
d4e293d
Made type optional on Custom Status
pierre-lehnen-rc Apr 10, 2019
ab81809
Merge branch 'develop' into custom_user_status
pierre-lehnen-rc Apr 10, 2019
97f6b57
Removed duplicated methods
pierre-lehnen-rc Apr 11, 2019
32755fd
Removed Unused Vars
pierre-lehnen-rc Apr 11, 2019
3c37980
Merge branch 'develop' into custom_user_status
Hudell Apr 11, 2019
641f594
Merge branch 'develop' into custom_user_status
ggazzo Apr 17, 2019
4e25b58
Merge branch 'develop' into custom_user_status
Hudell Apr 20, 2019
0b18a40
Merge branch 'develop' into custom_user_status
Hudell Apr 23, 2019
bcd5de2
Merge branch 'develop' into custom_user_status
pierre-lehnen-rc May 7, 2019
ab7646c
Fixed file imports
pierre-lehnen-rc May 7, 2019
d246a60
Merge branch 'develop' into custom_user_status
Hudell May 7, 2019
135f90a
Merge branch 'develop' into custom_user_status
pierre-lehnen-rc May 10, 2019
dc350c7
Merge branch 'develop' into custom_user_status
Hudell May 10, 2019
914dfe0
Unnest conditions
tassoevan May 11, 2019
92350e4
Prefer findOneById over findOneByID
tassoevan May 11, 2019
538e4b3
Prefer findByNameExceptId over findByNameExceptID
tassoevan May 11, 2019
0b6ca02
Prefer removeById over removeByID
tassoevan May 11, 2019
0078723
Remove obsolete comment
tassoevan May 11, 2019
be5da6d
Ensure i18n for status text
tassoevan May 11, 2019
849b958
Fix "Chat Now" button on room leader bar
tassoevan May 11, 2019
8768884
Update app/ui/client/components/header/headerRoom.js
Hudell May 13, 2019
111872e
Removed Unused Components and Attributes
pierre-lehnen-rc May 14, 2019
0dc2399
Improved Code Quality
pierre-lehnen-rc May 14, 2019
b2e93b6
Merge branch 'develop' into custom_user_status
pierre-lehnen-rc May 14, 2019
8b3f5f4
Merge branch 'custom_user_status' of github.com:RocketChat/Rocket.Cha…
pierre-lehnen-rc May 14, 2019
976f499
Merge branch 'develop' into custom_user_status
Hudell May 15, 2019
bc010c9
Merge branch 'develop' into custom_user_status
pierre-lehnen-rc Jun 19, 2019
ff54c51
Removed emojione references
pierre-lehnen-rc Jun 19, 2019
36a3b00
Merge branch 'develop' into custom_user_status
sampaiodiego Jun 21, 2019
f0692c4
User status of the room leader was not displaying the proper status text
pierre-lehnen-rc Jun 21, 2019
a939d5c
fix crud
ggazzo Jun 21, 2019
155d6cb
Fix fields
sampaiodiego Jun 21, 2019
a12788a
Change field name
sampaiodiego Jun 21, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/api/server/v1/emoji-custom.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ API.v1.addRoute('emoji-custom.update', { authRequired: true }, {
if (!fields._id) {
return callback(new Meteor.Error('The required "_id" query param is missing.'));
}
const emojiToUpdate = EmojiCustom.findOneByID(fields._id);
const emojiToUpdate = EmojiCustom.findOneById(fields._id);
if (!emojiToUpdate) {
return callback(new Meteor.Error('Emoji not found.'));
}
Expand Down
72 changes: 72 additions & 0 deletions app/api/server/v1/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from '../../../lib';
import { getFullUserData } from '../../../lib/server/functions/getFullUserData';
import { API } from '../api';
import { setStatusMessage } from '../../../lib/server';

API.v1.addRoute('users.create', { authRequired: true }, {
post() {
Expand Down Expand Up @@ -325,6 +326,73 @@ API.v1.addRoute('users.setAvatar', { authRequired: true }, {
},
});

API.v1.addRoute('users.getStatus', { authRequired: true }, {
get() {
if (this.isUserFromParams()) {
const user = Users.findOneById(this.userId);
return API.v1.success({
message: user.statusText,
connectionStatus: user.statusConnection,
status: user.status,
});
}

const user = this.getUserFromParams();

return API.v1.success({
message: user.statusText,
status: user.status,
});
},
});

API.v1.addRoute('users.setStatus', { authRequired: true }, {
post() {
check(this.bodyParams, Match.ObjectIncluding({
status: Match.Maybe(String),
message: Match.Maybe(String),
}));

if (!settings.get('Accounts_AllowUserStatusMessageChange')) {
throw new Meteor.Error('error-not-allowed', 'Change status is not allowed', {
method: 'users.setStatus',
});
}

let user;
if (this.isUserFromParams()) {
user = Meteor.users.findOne(this.userId);
} else if (hasPermission(this.userId, 'edit-other-user-info')) {
user = this.getUserFromParams();
} else {
return API.v1.unauthorized();
}

Meteor.runAsUser(user._id, () => {
if (this.bodyParams.message) {
setStatusMessage(user._id, this.bodyParams.message);
}
if (this.bodyParams.status) {
const validStatus = ['online', 'away', 'offline', 'busy'];
if (validStatus.includes(this.bodyParams.status)) {
Meteor.users.update(this.userId, {
$set: {
status: this.bodyParams.status,
statusDefault: this.bodyParams.status,
},
});
} else {
throw new Meteor.Error('error-invalid-status', 'Valid status types include online, away, offline, and busy.', {
method: 'users.setStatus',
});
}
}
});

return API.v1.success();
},
});

API.v1.addRoute('users.update', { authRequired: true }, {
post() {
check(this.bodyParams, {
Expand All @@ -334,6 +402,7 @@ API.v1.addRoute('users.update', { authRequired: true }, {
name: Match.Maybe(String),
password: Match.Maybe(String),
username: Match.Maybe(String),
statusText: Match.Maybe(String),
active: Match.Maybe(Boolean),
roles: Match.Maybe(Array),
joinDefaultChannels: Match.Maybe(Boolean),
Expand Down Expand Up @@ -369,6 +438,7 @@ API.v1.addRoute('users.updateOwnBasicInfo', { authRequired: true }, {
email: Match.Maybe(String),
name: Match.Maybe(String),
username: Match.Maybe(String),
statusText: Match.Maybe(String),
currentPassword: Match.Maybe(String),
newPassword: Match.Maybe(String),
}),
Expand All @@ -379,6 +449,7 @@ API.v1.addRoute('users.updateOwnBasicInfo', { authRequired: true }, {
email: this.bodyParams.data.email,
realname: this.bodyParams.data.name,
username: this.bodyParams.data.username,
statusText: this.bodyParams.data.statusText,
newPassword: this.bodyParams.data.newPassword,
typedPassword: this.bodyParams.data.currentPassword,
};
Expand Down Expand Up @@ -581,6 +652,7 @@ API.v1.addRoute('users.presence', { authRequired: true }, {
name: 1,
status: 1,
utcOffset: 1,
statusText: 1,
},
};

Expand Down
1 change: 1 addition & 0 deletions app/authorization/server/startup.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Meteor.startup(function() {
{ _id: 'leave-p', roles: ['admin', 'user', 'bot', 'anonymous'] },
{ _id: 'manage-assets', roles: ['admin'] },
{ _id: 'manage-emoji', roles: ['admin'] },
{ _id: 'manage-user-status', roles: ['admin'] },
{ _id: 'manage-integrations', roles: ['admin'] },
{ _id: 'manage-own-integrations', roles: ['admin'] },
{ _id: 'manage-oauth-apps', roles: ['admin'] },
Expand Down
4 changes: 2 additions & 2 deletions app/custom-sounds/server/methods/deleteCustomSound.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Meteor.methods({
let sound = null;

if (hasPermission(this.userId, 'manage-sounds')) {
sound = CustomSounds.findOneByID(_id);
sound = CustomSounds.findOneById(_id);
} else {
throw new Meteor.Error('not_authorized');
}
Expand All @@ -20,7 +20,7 @@ Meteor.methods({
}

RocketChatFileCustomSoundsInstance.deleteFile(`${ sound._id }.${ sound.extension }`);
CustomSounds.removeByID(_id);
CustomSounds.removeById(_id);
Notifications.notifyAll('deleteCustomSound', { soundData: sound });

return true;
Expand Down
2 changes: 1 addition & 1 deletion app/custom-sounds/server/methods/insertOrUpdateSound.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Meteor.methods({
let matchingResults = [];

if (soundData._id) {
matchingResults = CustomSounds.findByNameExceptID(soundData.name, soundData._id).fetch();
matchingResults = CustomSounds.findByNameExceptId(soundData.name, soundData._id).fetch();
} else {
matchingResults = CustomSounds.findByName(soundData.name).fetch();
}
Expand Down
4 changes: 2 additions & 2 deletions app/emoji-custom/server/methods/deleteEmojiCustom.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Meteor.methods({
let emoji = null;

if (hasPermission(this.userId, 'manage-emoji')) {
emoji = EmojiCustom.findOneByID(emojiID);
emoji = EmojiCustom.findOneById(emojiID);
} else {
throw new Meteor.Error('not_authorized');
}
Expand All @@ -20,7 +20,7 @@ Meteor.methods({
}

RocketChatFileEmojiCustomInstance.deleteFile(encodeURIComponent(`${ emoji.name }.${ emoji.extension }`));
EmojiCustom.removeByID(emojiID);
EmojiCustom.removeById(emojiID);
Notifications.notifyLogged('deleteEmojiCustom', { emojiData: emoji });

return true;
Expand Down
10 changes: 9 additions & 1 deletion app/lib/lib/roomTypes/direct.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Meteor } from 'meteor/meteor';
import { Session } from 'meteor/session';

import { ChatRoom, Subscriptions } from '../../../models';
import { ChatRoom, Subscriptions, Users } from '../../../models';
import { openRoom } from '../../../ui-utils';
import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext } from '../../../utils';
import { hasPermission, hasAtLeastOnePermission } from '../../../authorization';
Expand Down Expand Up @@ -92,6 +92,14 @@ export class DirectMessageRoomType extends RoomTypeConfig {
return Session.get(`user_${ subscription.name }_status`);
}

getUserStatusText(roomId) {
const userId = roomId.replace(Meteor.userId(), '');
const userData = Users.findOne({ _id: userId });
if (userData && userData.statusText) {
return userData.statusText;
}
}

getDisplayName(room) {
return room.usernames.join(' x ');
}
Expand Down
1 change: 1 addition & 0 deletions app/lib/server/functions/getFullUserData.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const defaultFields = {
type: 1,
active: 1,
reason: 1,
statusText: 1,
};

const fullFields = {
Expand Down
1 change: 1 addition & 0 deletions app/lib/server/functions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export { saveUser } from './saveUser';
export { sendMessage } from './sendMessage';
export { setEmail } from './setEmail';
export { setRealName, _setRealName } from './setRealName';
export { setStatusMessage, _setStatusMessage } from './setStatusMessage';
export { setUserAvatar } from './setUserAvatar';
export { _setUsername, setUsername } from './setUsername';
export { unarchiveRoom } from './unarchiveRoom';
Expand Down
13 changes: 12 additions & 1 deletion app/lib/server/functions/saveUser.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { settings } from '../../../settings';
import PasswordPolicy from '../lib/PasswordPolicyClass';
import { validateEmailDomain } from '../lib';

import { checkEmailAvailability, checkUsernameAvailability, setUserAvatar, setEmail, setRealName, setUsername } from '.';
import { checkEmailAvailability, checkUsernameAvailability, setUserAvatar, setEmail, setRealName, setUsername, setStatusMessage } from '.';

const passwordPolicy = new PasswordPolicy();

Expand Down Expand Up @@ -133,6 +133,13 @@ function validateUserEditing(userId, userData) {
});
}

if (userData.statusText && !settings.get('Accounts_AllowUserStatusMessageChange') && (!canEditOtherUserInfo || editingMyself)) {
throw new Meteor.Error('error-action-not-allowed', 'Edit user status is not allowed', {
method: 'insertOrUpdateUser',
action: 'Update_user',
});
}

if (userData.name && !settings.get('Accounts_AllowRealNameChange') && (!canEditOtherUserInfo || editingMyself)) {
throw new Meteor.Error('error-action-not-allowed', 'Edit user real name is not allowed', {
method: 'insertOrUpdateUser',
Expand Down Expand Up @@ -248,6 +255,10 @@ export const saveUser = function(userId, userData) {
setRealName(userData._id, userData.name);
}

if (typeof userData.statusText === 'string') {
setStatusMessage(userData._id, userData.statusText);
}

if (userData.email) {
const shouldSendVerificationEmailToUser = userData.verified !== true;
setEmail(userData._id, userData.email, shouldSendVerificationEmailToUser);
Expand Down
45 changes: 45 additions & 0 deletions app/lib/server/functions/setStatusMessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Meteor } from 'meteor/meteor';
import s from 'underscore.string';

import { Users } from '../../../models';
import { Notifications } from '../../../notifications';
import { hasPermission } from '../../../authorization';
import { RateLimiter } from '../lib';

export const _setStatusMessage = function(userId, statusMessage) {
statusMessage = s.trim(statusMessage);
if (statusMessage.length > 120) {
statusMessage = statusMessage.substr(0, 120);
}

if (!userId) {
return false;
}

const user = Users.findOneById(userId);

// User already has desired statusMessage, return
if (user.statusText === statusMessage) {
return user;
}

// Set new statusMessage
Users.updateStatusText(user._id, statusMessage);
user.statusText = statusMessage;

Notifications.notifyLogged('Users:StatusMessageChanged', {
_id: user._id,
name: user.name,
username: user.username,
statusText: user.statusText,
});

return true;
};

export const setStatusMessage = RateLimiter.limitFunction(_setStatusMessage, 1, 60000, {
0() {
// Administrators have permission to change others status, so don't limit those
return !Meteor.userId() || !hasPermission(Meteor.userId(), 'edit-other-user-info');
},
});
4 changes: 4 additions & 0 deletions app/lib/server/startup/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ settings.addGroup('Accounts', function() {
type: 'boolean',
public: true,
});
this.add('Accounts_AllowUserStatusMessageChange', true, {
type: 'boolean',
public: true,
});
this.add('Accounts_AllowUsernameChange', true, {
type: 'boolean',
public: true,
Expand Down
2 changes: 2 additions & 0 deletions app/models/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { UserRoles } from './models/UserRoles';
import { AuthzCachedCollection, ChatPermissions } from './models/ChatPermissions';
import { WebdavAccounts } from './models/WebdavAccounts';
import CustomSounds from './models/CustomSounds';
import CustomUserStatus from './models/CustomUserStatus';
import EmojiCustom from './models/EmojiCustom';

const Users = _.extend({}, users, Meteor.users);
Expand Down Expand Up @@ -51,6 +52,7 @@ export {
ChatSubscription,
Rooms,
CustomSounds,
CustomUserStatus,
EmojiCustom,
WebdavAccounts,
};
10 changes: 10 additions & 0 deletions app/models/client/models/CustomUserStatus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Base } from './_Base';

class CustomUserStatus extends Base {
constructor() {
super();
this._initModel('custom_user_status');
}
}

export default new CustomUserStatus();
2 changes: 2 additions & 0 deletions app/models/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Statistics from './models/Statistics';
import Permissions from './models/Permissions';
import Roles from './models/Roles';
import CustomSounds from './models/CustomSounds';
import CustomUserStatus from './models/CustomUserStatus';
import Integrations from './models/Integrations';
import IntegrationHistory from './models/IntegrationHistory';
import CredentialTokens from './models/CredentialTokens';
Expand Down Expand Up @@ -58,6 +59,7 @@ export {
Permissions,
Roles,
CustomSounds,
CustomUserStatus,
Integrations,
IntegrationHistory,
CredentialTokens,
Expand Down
6 changes: 3 additions & 3 deletions app/models/server/models/CustomSounds.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class CustomSounds extends Base {
}

// find one
findOneByID(_id, options) {
findOneById(_id, options) {
return this.findOne(_id, options);
}

Expand All @@ -21,7 +21,7 @@ class CustomSounds extends Base {
return this.find(query, options);
}

findByNameExceptID(name, except, options) {
findByNameExceptId(name, except, options) {
const query = {
_id: { $nin: [except] },
name,
Expand All @@ -48,7 +48,7 @@ class CustomSounds extends Base {


// REMOVE
removeByID(_id) {
removeById(_id) {
return this.remove(_id);
}
}
Expand Down
Loading