Compare commits

...

12 Commits

15 changed files with 209 additions and 85 deletions

View File

@ -1,3 +1,5 @@
import { IUser } from './IUser';
export interface IAttachment {
ts: string | Date;
title: string;
@ -23,3 +25,30 @@ export interface IAttachment {
color?: string;
thumb_url?: string;
}
export interface IServerAttachment {
_id: string;
name: string;
size: number;
type: string;
rid: string;
userId: string;
AmazonS3: { path: string };
store: string;
identify: {
format: string;
size: {
width: number;
height: number;
};
};
complete: boolean;
etag: string;
path: string;
progress: boolean;
token: string;
uploadedAt: string | Date;
uploading: boolean;
url: string;
user: Pick<IUser, '_id' | 'username' | 'name'>;
}

View File

@ -87,6 +87,18 @@ export interface IMessageFromServer {
drid?: string;
dcount?: number;
dml: string | Date;
starred?:
| {
_id: string;
}
| boolean;
pinned?: boolean;
pinnedAt?: string | Date;
pinnedBy?: {
_id: string;
username: string;
};
score?: number;
}
export interface ILoadMoreMessage {
@ -106,7 +118,11 @@ export interface IMessage extends IMessageFromServer {
emoji?: string;
status?: number;
pinned?: boolean;
starred?: boolean;
starred?:
| {
_id: string;
}
| boolean;
editedBy?: IEditedBy;
reactions?: IReaction[];
role?: string;

View File

@ -57,6 +57,14 @@ export interface IAvatar {
service?: any;
}
export interface IAvatarSuggestion {
[service: string]: {
url: string;
blob: string;
contentType: string;
};
}
export interface IProfileViewState {
saving: boolean;
name: string;
@ -66,13 +74,7 @@ export interface IProfileViewState {
currentPassword: string | null;
avatarUrl: string | null;
avatar: IAvatar;
avatarSuggestions: {
[service: string]: {
url: string;
blob: string;
contentType: string;
};
};
avatarSuggestions: IAvatarSuggestion;
customFields: {
[key: string | number]: string;
};

View File

@ -1,18 +1,15 @@
import { ITeam } from '../../ITeam';
import type { IMessage, IMessageFromServer } from '../../IMessage';
import type { IMessageFromServer } from '../../IMessage';
import type { IServerRoom } from '../../IRoom';
import type { IUser } from '../../IUser';
import { IServerAttachment } from '../../IAttachment';
export type ChannelsEndpoints = {
'channels.files': {
GET: (params: {
roomId: IServerRoom['_id'];
offset: number;
GET: (params: { roomId: IServerRoom['_id']; offset: number; sort: string | { uploadedAt: number } }) => {
files: IServerAttachment[];
count: number;
sort: string | { uploadedAt: number };
query: string;
}) => {
files: IMessage[];
offset: number;
total: number;
};
};
@ -99,4 +96,14 @@ export type ChannelsEndpoints = {
'channels.removeLeader': {
POST: (params: { roomId: string; userId: string }) => {};
};
'channels.messages': {
GET: (params: {
roomId: IServerRoom['_id'];
query: { 'mentions._id': { $in: string[] } } | { 'starred._id': { $in: string[] } } | { pinned: boolean };
offset: number;
sort: { ts: number };
}) => {
messages: IMessageFromServer[];
};
};
};

View File

@ -60,4 +60,9 @@ export type ChatEndpoints = {
'chat.ignoreUser': {
GET: (params: { rid: string; userId: string; ignore: boolean }) => {};
};
'chat.search': {
GET: (params: { roomId: IServerRoom['_id']; searchText: string; count: number; offset: number }) => {
messages: IMessageFromServer[];
};
};
};

View File

@ -1,12 +1,15 @@
import { ITeam } from '../../ITeam';
import type { IMessage, IMessageFromServer } from '../../IMessage';
import type { IMessageFromServer } from '../../IMessage';
import type { IServerRoom } from '../../IRoom';
import type { IUser } from '../../IUser';
import { IServerAttachment } from '../../IAttachment';
export type GroupsEndpoints = {
'groups.files': {
GET: (params: { roomId: IServerRoom['_id']; count: number; sort: string | { uploadedAt: number }; query: string }) => {
files: IMessage[];
GET: (params: { roomId: IServerRoom['_id']; offset: number; sort: string | { uploadedAt: number } }) => {
files: IServerAttachment[];
count: number;
offset: number;
total: number;
};
};
@ -69,4 +72,14 @@ export type GroupsEndpoints = {
'groups.leave': {
POST: (params: { roomId: string }) => {};
};
'groups.messages': {
GET: (params: {
roomId: IServerRoom['_id'];
query: { 'mentions._id': { $in: string[] } } | { 'starred._id': { $in: string[] } } | { pinned: boolean };
offset: number;
sort: { ts: number };
}) => {
messages: IMessageFromServer[];
};
};
};

View File

@ -1,6 +1,7 @@
import type { IMessage, IMessageFromServer } from '../../IMessage';
import type { IMessageFromServer } from '../../IMessage';
import type { IServerRoom, RoomID, RoomType } from '../../IRoom';
import type { IUser } from '../../IUser';
import { IServerAttachment } from '../../IAttachment';
export type ImEndpoints = {
'im.create': {
@ -25,8 +26,10 @@ export type ImEndpoints = {
};
};
'im.files': {
GET: (params: { roomId: IServerRoom['_id']; count: number; sort: string | { uploadedAt: number }; query: string }) => {
files: IMessage[];
GET: (params: { roomId: IServerRoom['_id']; offset: number; sort: string | { uploadedAt: number } }) => {
files: IServerAttachment[];
count: number;
offset: number;
total: number;
};
};
@ -55,4 +58,14 @@ export type ImEndpoints = {
'im.leave': {
POST: (params: { roomId: string }) => {};
};
'im.messages': {
GET: (params: {
roomId: IServerRoom['_id'];
query: { 'mentions._id': { $in: string[] } } | { 'starred._id': { $in: string[] } } | { pinned: boolean };
offset: number;
sort: { ts: number };
}) => {
messages: IMessageFromServer[];
};
};
};

View File

@ -43,4 +43,16 @@ export type UsersEndpoints = {
user: IUser;
};
};
'users.getUsernameSuggestion': {
GET: () => { result: string };
};
'users.resetAvatar': {
POST: (params: { userId: string }) => {};
};
'users.getPreferences': {
GET: (params: { userId: IUser['_id'] }) => {
preferences: INotificationPreferences;
success: boolean;
};
};
};

View File

@ -103,9 +103,16 @@ export default class RoomSubscription {
}
};
handleConnection = () => {
reduxStore.dispatch(clearUserTyping());
RocketChat.loadMissedMessages({ rid: this.rid }).catch(e => console.log(e));
handleConnection = async () => {
try {
reduxStore.dispatch(clearUserTyping());
await RocketChat.loadMissedMessages({ rid: this.rid });
const _lastOpen = new Date();
this.read(_lastOpen);
this.lastOpen = _lastOpen;
} catch (e) {
log(e);
}
};
handleNotifyRoomReceived = protectedFunction((ddpMessage: IDDPMessage) => {

View File

@ -3,7 +3,7 @@ import { TEAM_TYPE } from '../../../definitions/ITeam';
import roomTypeToApiType, { RoomTypes } from '../methods/roomTypeToApiType';
import { SubscriptionType, INotificationPreferences, IRoomNotifications } from '../../../definitions';
import { ISpotlight } from '../../../definitions/ISpotlight';
import { IParams } from '../../../definitions/IProfileViewInterfaces';
import { IAvatarSuggestion, IParams } from '../../../definitions/IProfileViewInterfaces';
export const createChannel = ({
name,
@ -290,10 +290,8 @@ export const getChannelInfo = (roomId: string) =>
// RC 0.48.0
sdk.get('channels.info', { roomId });
export const getUserPreferences = (userId: string): any =>
export const getUserPreferences = (userId: string) =>
// RC 0.62.0
// TODO: missing definitions from server
// @ts-ignore
sdk.get('users.getPreferences', { userId });
export const getRoomInfo = (roomId: string) =>
@ -568,14 +566,12 @@ export const getRoomRoles = (roomId: string, type: SubscriptionType): any =>
// @ts-ignore
sdk.get(`${roomTypeToApiType(type)}.roles`, { roomId });
export const getAvatarSuggestion = () =>
export const getAvatarSuggestion = (): Promise<IAvatarSuggestion> =>
// RC 0.51.0
sdk.methodCallWrapper('getAvatarSuggestion');
export const resetAvatar = (userId: string): any =>
export const resetAvatar = (userId: string) =>
// RC 0.55.0
// TODO: missing definitions from server
// @ts-ignore
sdk.post('users.resetAvatar', { userId });
export const setAvatarFromService = ({
@ -586,36 +582,39 @@ export const setAvatarFromService = ({
data: any;
contentType?: string;
service?: string | null;
}) =>
}): Promise<void> =>
// RC 0.51.0
sdk.methodCallWrapper('setAvatarFromService', data, contentType, service);
export const getUsernameSuggestion = (): any =>
export const getUsernameSuggestion = () =>
// RC 0.65.0
// TODO: missing definitions from server
// @ts-ignore
sdk.get('users.getUsernameSuggestion');
export const getFiles = (roomId: string, type: RoomTypes, offset: number): any =>
export const getFiles = (roomId: string, type: SubscriptionType, offset: number) => {
const t = type as SubscriptionType.DIRECT | SubscriptionType.CHANNEL | SubscriptionType.GROUP;
// RC 0.59.0
// TODO: missing definitions from server
// @ts-ignore
sdk.get(`${roomTypeToApiType(type)}.files`, {
return sdk.get(`${roomTypeToApiType(t)}.files`, {
roomId,
offset,
sort: { uploadedAt: -1 }
});
};
export const getMessages = (roomId: string, type: RoomTypes, query: any, offset: number): any =>
export const getMessages = (
roomId: string,
type: SubscriptionType,
query: { 'mentions._id': { $in: string[] } } | { 'starred._id': { $in: string[] } } | { pinned: boolean },
offset: number
) => {
const t = type as SubscriptionType.DIRECT | SubscriptionType.CHANNEL | SubscriptionType.GROUP;
// RC 0.59.0
// TODO: missing definitions from server
// @ts-ignore
sdk.get(`${roomTypeToApiType(type)}.messages`, {
return sdk.get(`${roomTypeToApiType(t)}.messages`, {
roomId,
query,
offset,
sort: { ts: -1 }
});
};
export const getReadReceipts = (messageId: string): any =>
// RC 0.63.0
@ -625,10 +624,8 @@ export const getReadReceipts = (messageId: string): any =>
messageId
});
export const searchMessages = (roomId: string, searchText: string, count: number, offset: number): any =>
export const searchMessages = (roomId: string, searchText: string, count: number, offset: number) =>
// RC 0.60.0
// TODO: missing definitions from server
// @ts-ignore
sdk.get('chat.search', {
roomId,
searchText,

View File

@ -9,8 +9,6 @@ import log from '../utils/log';
import mergeSubscriptionsRooms from '../lib/methods/helpers/mergeSubscriptionsRooms';
import RocketChat from '../lib/rocketchat';
import buildMessage from '../lib/methods/helpers/buildMessage';
import protectedFunction from '../lib/methods/helpers/protectedFunction';
import UserPreferences from '../lib/userPreferences';
const updateRooms = function* updateRooms({ server, newRoomsUpdatedAt }) {
const serversDB = database.servers;
@ -82,33 +80,46 @@ const handleRoomsRequest = function* handleRoomsRequest({ params }) {
})
),
...subsToUpdate.map(subscription => {
const newSub = subscriptions.find(s => s._id === subscription._id);
return subscription.prepareUpdate(() => {
if (newSub.announcement) {
if (newSub.announcement !== subscription.announcement) {
subscription.bannerClosed = false;
try {
const newSub = subscriptions.find(s => s._id === subscription._id);
return subscription.prepareUpdate(() => {
if (newSub.announcement) {
if (newSub.announcement !== subscription.announcement) {
subscription.bannerClosed = false;
}
}
}
Object.assign(subscription, newSub);
});
Object.assign(subscription, newSub);
});
} catch (e) {
log(e);
return null;
}
}),
...subsToDelete.map(subscription => {
try {
return subscription.prepareDestroyPermanently();
} catch (e) {
log(e);
return null;
}
}),
...subsToDelete.map(subscription => subscription.prepareDestroyPermanently()),
...messagesToCreate.map(message =>
messagesCollection.prepareCreate(
protectedFunction(m => {
m._raw = sanitizedRaw({ id: message._id }, messagesCollection.schema);
m.subscription.id = message.rid;
return Object.assign(m, message);
})
)
messagesCollection.prepareCreate(m => {
m._raw = sanitizedRaw({ id: message._id }, messagesCollection.schema);
m.subscription.id = message.rid;
return Object.assign(m, message);
})
),
...messagesToUpdate.map(message => {
const newMessage = lastMessages.find(m => m._id === message.id);
return message.prepareUpdate(
protectedFunction(() => {
Object.assign(message, newMessage);
})
);
return message.prepareUpdate(() => {
try {
return Object.assign(message, newMessage);
} catch (e) {
log(e);
return null;
}
});
})
];

View File

@ -196,9 +196,10 @@ class MessagesView extends React.Component<IMessagesViewProps, any> {
name: I18n.t('Files'),
fetchFunc: async () => {
const { messages } = this.state;
// @ts-ignore
const result = await RocketChat.getFiles(this.rid, this.t, messages.length);
return { ...result, messages: result.files };
if (result.success) {
return { ...result, messages: result.files };
}
},
noDataMsg: I18n.t('No_files'),
testID: 'room-files-view',
@ -226,7 +227,6 @@ class MessagesView extends React.Component<IMessagesViewProps, any> {
name: I18n.t('Mentions'),
fetchFunc: () => {
const { messages } = this.state;
// @ts-ignore
return RocketChat.getMessages(this.rid, this.t, { 'mentions._id': { $in: [user.id] } }, messages.length);
},
noDataMsg: I18n.t('No_mentioned_messages'),
@ -239,7 +239,6 @@ class MessagesView extends React.Component<IMessagesViewProps, any> {
name: I18n.t('Starred'),
fetchFunc: () => {
const { messages } = this.state;
// @ts-ignore
return RocketChat.getMessages(this.rid, this.t, { 'starred._id': { $in: [user.id] } }, messages.length);
},
noDataMsg: I18n.t('No_starred_messages'),
@ -260,7 +259,6 @@ class MessagesView extends React.Component<IMessagesViewProps, any> {
name: I18n.t('Pinned'),
fetchFunc: () => {
const { messages } = this.state;
// @ts-ignore
return RocketChat.getMessages(this.rid, this.t, { pinned: true }, messages.length);
},
noDataMsg: I18n.t('No_pinned_messages'),

View File

@ -157,11 +157,13 @@ class SearchMessagesView extends React.Component<ISearchMessagesViewProps, ISear
if (result.success) {
return result.messages;
}
};
return [];
};
getMessages = async (searchText: string, debounced?: boolean) => {
try {
const messages = await this.searchMessages(searchText);
// @ts-ignore TODO: find a way to deal with the difference between IMessageFromServer and TMessageModel expected by state
this.setState(prevState => ({
messages: debounced ? messages : [...prevState.messages, ...messages],
loading: false

View File

@ -15,6 +15,7 @@ import { getUserSelector } from '../../selectors/login';
import sharedStyles from '../Styles';
import { OPTIONS } from './options';
import { ProfileStackParamList } from '../../stacks/types';
import { INotificationPreferences } from '../../definitions';
const styles = StyleSheet.create({
pickerText: {
@ -26,11 +27,7 @@ const styles = StyleSheet.create({
type TKey = 'desktopNotifications' | 'pushNotifications' | 'emailNotificationMode';
interface IUserNotificationPreferencesViewState {
preferences: {
desktopNotifications?: string;
pushNotifications?: string;
emailNotificationMode?: string;
};
preferences: INotificationPreferences;
loading: boolean;
}
@ -53,7 +50,7 @@ class UserNotificationPreferencesView extends React.Component<
constructor(props: IUserNotificationPreferencesViewProps) {
super(props);
this.state = {
preferences: {},
preferences: {} as INotificationPreferences,
loading: false
};
}
@ -62,8 +59,10 @@ class UserNotificationPreferencesView extends React.Component<
const { user } = this.props;
const { id } = user;
const result = await RocketChat.getUserPreferences(id);
const { preferences } = result;
this.setState({ preferences, loading: true });
if (result.success) {
const { preferences } = result;
this.setState({ preferences, loading: true });
}
}
findDefaultOption = (key: TKey) => {

View File

@ -0,0 +1,13 @@
diff --git a/node_modules/@rocket.chat/sdk/lib/drivers/ddp.ts b/node_modules/@rocket.chat/sdk/lib/drivers/ddp.ts
index e751551..02703a0 100644
--- a/node_modules/@rocket.chat/sdk/lib/drivers/ddp.ts
+++ b/node_modules/@rocket.chat/sdk/lib/drivers/ddp.ts
@@ -298,7 +298,7 @@ export class Socket extends EventEmitter {
login = async (credentials: any) => {
const params = this.loginParams(credentials)
this.resume = (await this.call('login', params) as ILoginResult)
- await this.subscribeAll()
+ this.subscribeAll().catch(console.log)
this.emit('login', this.resume)
return this.resume
}