Skip to content

Commit

Permalink
Service Account Subscription (#59)
Browse files Browse the repository at this point in the history
* Service Account broadcast room callback added

* Service Account Callback completed

* CLI errors fixed

* [NEW] Service Account one-tap login complete

* Callbacks modified

* Service Accounts directory tab added

* [NEW] Service Accounts Login method

* Typo fixed

* CLI errors fixed

* CLI errors fixed

* [FIX] Anonymous chat read (RocketChat#14717)

* Prevent errors when allowing anonymous read

* getSingleMessage for anonymous users

* Fix register user when allow read and write anonymous is enabled

* Fix anonymous with sidebar extended as default

Co-authored-by: ubergeekzone <ubergeekzone@gmail.com>

* [New] Service Account directory feature

* CLI errors fixed

* UsernameExists meteor method fixed

* Sync commit

* [NEW] Add loading animation to webdav file picker (RocketChat#14759)

* [NEW] Service Account subscription method added

* [NEW] Service account subscription sidenav type

* changed mongo version for snap from 3.2.7 to 3.4.20 (RocketChat#14838)

* add _hidden for messages loaded by thread (RocketChat#14837)

* Regression: thread loading parent msg if is not loaded (RocketChat#14839)

* [IMPROVE] Layout of livechat manager pages to new style (RocketChat#13900)

* [FIX] Removes E2E action button, icon and banner when E2E is disabled. (RocketChat#14810)

* [IMPROVE] Adds link to download generated user data file (RocketChat#14175)

* [FIX] Error when using Download My Data or Export My Data (RocketChat#14645)

* [NEW] Custom User Status (RocketChat#13933)

Co-Authored-By: Tasso Evangelista <tasso@tassoevan.me>
Co-Authored-By: Guilherme Gazzo <guilhermegazzo@gmail.com>
Co-Authored-By: wreiske <wreiske@mieweb.com>

* Allow debugging of cached collections by name (RocketChat#14859)

* Regression: Allow debugging of cached collections by name (RocketChat#14862)

* Regression: Fix desktop notifications not being sent (RocketChat#14860)

* Broadcast Room name change handled

* Lint errors fixed

* getLoginToken method refactored

* Console statements removed

* Sidebar header permission modified

* Merge branch service-accounts

* Added service account directory search translation key

* Subscribers count added

* [NEW] Service Account sidenav type

* Synced with base branch
  • Loading branch information
bhardwajaditya authored and Kailash0311 committed Jun 29, 2019
1 parent ab1274f commit ee44209
Show file tree
Hide file tree
Showing 144 changed files with 3,061 additions and 769 deletions.
4 changes: 2 additions & 2 deletions .snapcraft/resources/preparemongo
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

if [[ $(uname -m) == "x86_64" ]]
then
wget --backups=0 "https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-3.2.7.tgz"
tar -zxf ./mongodb-linux-x86_64-ubuntu1604-3.2.7.tgz --strip-components=1
wget --backups=0 "https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.4.20.tgz"
tar -zxf ./mongodb-linux-x86_64-3.4.20.tgz --strip-components=1
else
IFS=" " read -a links <<< $(apt-get -y --print-uris install mongodb | egrep -o "https?://[^']+")
for link in ${links[@]}
Expand Down
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
73 changes: 73 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 @@ -451,6 +522,7 @@ API.v1.addRoute('users.setPreferences', { authRequired: true }, {
sidebarHideAvatar: Match.Optional(Boolean),
sidebarGroupByType: Match.Optional(Boolean),
sidebarShowDiscussion: Match.Optional(Boolean),
sidebarShowServiceAccounts: Match.Optional(Boolean),
muteFocusedConversations: Match.Optional(Boolean),
}),
});
Expand Down Expand Up @@ -581,6 +653,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
1 change: 1 addition & 0 deletions app/e2e/client/rocketchat.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ Meteor.startup(function() {
e2e.enabled.set(true);
} else {
e2e.enabled.set(false);
e2e.closeAlert();
}
}
});
Expand Down
32 changes: 20 additions & 12 deletions app/e2e/client/tabbar.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
import { Meteor } from 'meteor/meteor';
import { Session } from 'meteor/session';
import { Tracker } from 'meteor/tracker';

import { hasAllPermission } from '../../authorization';
import { call, TabBar } from '../../ui-utils';
import { ChatRoom } from '../../models';
import { settings } from '../../settings';

Meteor.startup(() => {
TabBar.addButton({
groups: ['direct', 'group'],
id: 'e2e',
i18nTitle: 'E2E',
icon: 'key',
class: () => (ChatRoom.findOne(Session.get('openedRoom')) || {}).encrypted && 'enabled',
action: () => {
const room = ChatRoom.findOne(Session.get('openedRoom'));
call('saveRoomSettings', room._id, 'encrypted', !room.encrypted);
},
order: 10,
condition: () => hasAllPermission('edit-room', Session.get('openedRoom')),
Tracker.autorun(() => {
if (settings.get('E2E_Enable')) {
TabBar.addButton({
groups: ['direct', 'group'],
id: 'e2e',
i18nTitle: 'E2E',
icon: 'key',
class: () => (ChatRoom.findOne(Session.get('openedRoom')) || {}).encrypted && 'enabled',
action: () => {
const room = ChatRoom.findOne(Session.get('openedRoom'));
call('saveRoomSettings', room._id, 'encrypted', !room.encrypted);
},
order: 10,
condition: () => hasAllPermission('edit-room', Session.get('openedRoom')),
});
} else {
TabBar.removeButton('e2e');
}
});
});
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
2 changes: 1 addition & 1 deletion app/emoji/client/emojiPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const getEmojiElement = (emoji, image) => image && `<li class="emoji-${ emoji }

const createEmojiList = (category, actualTone) => {
const html = Object.values(emoji.packages).map((emojiPackage) => {
if (!emojiPackage.emojisByCategory[category]) {
if (!emojiPackage.emojisByCategory || !emojiPackage.emojisByCategory[category]) {
return;
}

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 @@ -258,6 +265,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');
},
});
2 changes: 2 additions & 0 deletions app/lib/server/functions/setUsername.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ export const _setUsername = function(userId, u) {
Rooms.replaceUsername(previousUsername, username);
Rooms.replaceMutedUsername(previousUsername, username);
Rooms.replaceUsernameOfUserByUserId(user._id, username);
Rooms.replaceServiceAccountBroadcastRoomName(previousUsername, username);
Subscriptions.setUserUsernameByUserId(user._id, username);
Subscriptions.setNameForDirectRoomsWithOldName(previousUsername, username);
Subscriptions.replaceServiceAccountBroadcastRoomName(previousUsername, username);
LivechatDepartmentAgents.replaceUsernameOfAgentByUserId(user._id, username);
Users.setOwnerUsernameByUserId(user._id, username);

Expand Down
4 changes: 0 additions & 4 deletions app/lib/server/methods/getSingleMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ Meteor.methods({
getSingleMessage(msgId) {
check(msgId, String);

if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getSingleMessage' });
}

const msg = Messages.findOneById(msgId);

if (!msg || !msg.rid) {
Expand Down
Loading

0 comments on commit ee44209

Please sign in to comment.