Chore: Add REST API definitions from server (#3721)

* create first definitions

* chore: implements get and post types

* fix lint

* add ts-ignore

* add teams.removeRoom method

* Remove unused endpoints

Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
Gleidson Daniel Silva 2022-02-14 13:20:29 -03:00 committed by GitHub
parent 88d33b42c2
commit 7866ec3f33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1486 additions and 20 deletions

View File

@ -0,0 +1,7 @@
import { IRocketChatRecord } from './IRocketChatRecord';
export interface ICustomEmojiDescriptor extends IRocketChatRecord {
name: string;
aliases: string[];
extension: string;
}

View File

@ -0,0 +1,11 @@
import { IRocketChatRecord } from './IRocketChatRecord';
export interface IInvite extends IRocketChatRecord {
days: number;
maxUses: number;
rid: string;
userId: string;
createdAt: Date;
expires: Date | null;
uses: number;
}

View File

@ -0,0 +1,16 @@
import { IUser } from './IUser';
export enum ILivechatAgentStatus {
AVAILABLE = 'available',
UNAVAILABLE = 'unavailable'
}
export interface ILivechatAgent extends IUser {
statusLivechat: ILivechatAgentStatus;
livechat: {
maxNumberSimultaneousChat: number;
};
livechatCount: number;
lastRoutingTime: Date;
livechatStatusSystemModified?: boolean;
}

View File

@ -0,0 +1,18 @@
export interface ILivechatDepartment {
_id: string;
name: string;
enabled: boolean;
description?: string;
showOnRegistration: boolean;
showOnOfflineForm: boolean;
requestTagBeforeClosingChat?: boolean;
email: string;
chatClosingTags?: string[];
offlineMessageChannelName: string;
numAgents: number;
_updatedAt?: Date;
businessHourId?: string;
fallbackForwardDepartment?: string;
// extra optional fields
[k: string]: any;
}

View File

@ -0,0 +1,9 @@
export interface ILivechatDepartmentAgents {
_id: string;
departmentId: string;
departmentEnabled: boolean;
agentId: string;
username: string;
count: number;
order: number;
}

View File

@ -0,0 +1,8 @@
export interface ILivechatMonitor {
_id: string;
name: string;
enabled: boolean;
numMonitors: number;
type: string;
visibility: string;
}

View File

@ -0,0 +1,7 @@
export interface ILivechatTag {
_id: string;
name: string;
description: string;
numDepartments: number;
departments: Array<string>;
}

View File

@ -0,0 +1,53 @@
import { IRocketChatRecord } from './IRocketChatRecord';
export interface IVisitorPhone {
phoneNumber: string;
}
export interface IVisitorLastChat {
_id: string;
ts: string;
}
export interface ILivechatVisitorConnectionData {
httpHeaders: {
[k: string]: string;
};
clientAddress: string;
}
export interface IVisitorEmail {
address: string;
}
export interface ILivechatVisitor extends IRocketChatRecord {
username: string;
ts: Date;
token: string;
department?: string;
name?: string;
phone?: IVisitorPhone[] | null;
lastChat?: IVisitorLastChat;
userAgent?: string;
ip?: string;
host?: string;
visitorEmails?: IVisitorEmail[];
}
export interface ILivechatVisitorDTO {
id: string;
token: string;
name: string;
email: string;
department: string;
phone: string | { number: string };
username: string;
customFields: {
key: string;
value: string;
overwrite: boolean;
}[];
connectionData: {
httpHeaders: Record<string, string>;
};
}

View File

@ -54,6 +54,7 @@ export interface ILastMessage {
}
export interface IMessage {
_id?: string;
msg?: string;
t?: SubscriptionType;
ts: Date;

View File

@ -4,6 +4,6 @@ type TRocketChat = typeof rocketchat;
export interface IRocketChat extends TRocketChat {
sdk: any;
activeUsersSubTimeout: any;
activeUsersSubTimeout: any;
roomsSub: any;
}

View File

@ -0,0 +1,10 @@
export interface IRocketChatRecord {
_id: string;
_updatedAt: Date;
}
export type RocketChatRecordDeleted<T> = T &
IRocketChatRecord & {
_deletedAt: Date;
__collection__: string;
};

View File

@ -3,6 +3,12 @@ import Model from '@nozbe/watermelondb/Model';
export interface IRole {
id: string;
description?: string;
mandatory2fa?: boolean;
name: string;
protected: boolean;
// scope?: string;
scope: 'Users' | 'Subscriptions';
_id: string;
}
export type TRoleModel = IRole & Model;

View File

@ -1,9 +1,20 @@
import Model from '@nozbe/watermelondb/Model';
import { IMessage } from './IMessage';
import { IServedBy } from './IServedBy';
import { SubscriptionType } from './ISubscription';
import { IUser } from './IUser';
interface IRequestTranscript {
email: string;
requestedAt: Date;
requestedBy: IUser;
subject: string;
}
export interface IRoom {
_id?: string;
fname?: string;
id: string;
rid: string;
prid: string;
@ -15,13 +26,77 @@ export interface IRoom {
broadcast: boolean;
encrypted: boolean;
ro: boolean;
v?: string[];
v?: {
_id?: string;
token?: string;
status: 'online' | 'busy' | 'away' | 'offline';
};
servedBy?: IServedBy;
departmentId?: string;
livechatData?: any;
tags?: string[];
e2eKeyId?: string;
avatarETag?: string;
default?: true;
featured?: true;
}
export enum OmnichannelSourceType {
WIDGET = 'widget',
EMAIL = 'email',
SMS = 'sms',
APP = 'app',
API = 'api',
OTHER = 'other' // catch-all source type
}
export interface IOmnichannelRoom extends Omit<IRoom, 'default' | 'featured' | 'broadcast' | ''> {
t: SubscriptionType.OMNICHANNEL;
v: {
_id?: string;
token?: string;
status: 'online' | 'busy' | 'away' | 'offline';
};
email?: {
// Data used when the room is created from an email, via email Integration.
inbox: string;
thread: string;
replyTo: string;
subject: string;
};
source: {
// TODO: looks like this is not so required as the definition suggests
// The source, or client, which created the Omnichannel room
type: OmnichannelSourceType;
// An optional identification of external sources, such as an App
id?: string;
// A human readable alias that goes with the ID, for post analytical purposes
alias?: string;
// A label to be shown in the room info
label?: string;
// The sidebar icon
sidebarIcon?: string;
// The default sidebar icon
defaultIcon?: string;
};
transcriptRequest?: IRequestTranscript;
servedBy?: IServedBy;
onHold?: boolean;
departmentId?: string;
lastMessage?: IMessage & { token?: string };
tags: any;
closedAt: any;
metrics: any;
waitingResponse: any;
responseBy: any;
priorityId: any;
livechatData: any;
queuedAt?: Date;
ts: Date;
label?: string;
crmData?: unknown;
}
export type TRoomModel = IRoom & Model;

237
app/definitions/ISetting.ts Normal file
View File

@ -0,0 +1,237 @@
export type SettingId = string;
export type GroupId = SettingId;
export type TabId = SettingId;
export type SectionName = string;
export enum SettingEditor {
COLOR = 'color',
EXPRESSION = 'expression'
}
type AssetValue = { defaultUrl?: string };
export type SettingValueMultiSelect = (string | number)[];
export type SettingValueRoomPick = Array<{ _id: string; name: string }> | string;
export type SettingValue = string | boolean | number | SettingValueMultiSelect | Date | AssetValue | undefined;
export interface ISettingSelectOption {
key: string | number;
i18nLabel: string;
}
export type ISetting = ISettingBase | ISettingEnterprise | ISettingColor | ISettingCode | ISettingAction;
export interface ISettingBase {
_id: SettingId;
type:
| 'boolean'
| 'timezone'
| 'string'
| 'relativeUrl'
| 'password'
| 'int'
| 'select'
| 'multiSelect'
| 'language'
| 'color'
| 'font'
| 'code'
| 'action'
| 'asset'
| 'roomPick'
| 'group'
| 'date';
public: boolean;
env: boolean;
group?: GroupId;
section?: SectionName;
tab?: TabId;
i18nLabel: string;
value: SettingValue;
packageValue: SettingValue;
blocked: boolean;
// enableQuery?: string | FilterQuery<ISetting> | FilterQuery<ISetting>[];
// displayQuery?: string | FilterQuery<ISetting> | FilterQuery<ISetting>[];
sorter: number;
properties?: unknown;
enterprise?: boolean;
requiredOnWizard?: boolean;
hidden?: boolean;
modules?: Array<string>;
invalidValue?: SettingValue;
valueSource?: string;
secret?: boolean;
i18nDescription?: string;
autocomplete?: boolean;
processEnvValue?: SettingValue;
meteorSettingsValue?: SettingValue;
ts: Date;
createdAt: Date;
_updatedAt?: Date;
multiline?: boolean;
values?: Array<ISettingSelectOption>;
placeholder?: string;
wizard?: {
step: number;
order: number;
} | null;
persistent?: boolean; // todo: remove
readonly?: boolean; // todo: remove
alert?: string; // todo: check if this is still used
private?: boolean; // todo: remove
}
export interface ISettingGroup {
_id: string;
hidden: boolean;
blocked: boolean;
ts?: Date;
sorter: number;
i18nLabel: string;
// displayQuery?: string | FilterQuery<ISetting> | FilterQuery<ISetting>[];
i18nDescription: string;
value?: undefined;
type: 'group';
alert?: string; // todo: check if this is needed
}
export interface ISettingEnterprise extends ISettingBase {
enterprise: true;
invalidValue: SettingValue;
}
export interface ISettingColor extends ISettingBase {
type: 'color';
editor: SettingEditor;
packageEditor?: SettingEditor;
}
export interface ISettingCode extends ISettingBase {
type: 'code';
code?: string;
}
export interface ISettingAction extends ISettingBase {
type: 'action';
value: string;
actionText?: string;
}
export interface ISettingAsset extends ISettingBase {
type: 'asset';
value: AssetValue;
}
export interface ISettingDate extends ISettingBase {
type: 'date';
value: Date;
}
export const isDateSetting = (setting: ISetting): setting is ISettingDate => setting.type === 'date';
export const isSettingEnterprise = (setting: ISettingBase): setting is ISettingEnterprise => setting.enterprise === true;
export const isSettingColor = (setting: ISettingBase): setting is ISettingColor => setting.type === 'color';
export const isSettingCode = (setting: ISettingBase): setting is ISettingCode => setting.type === 'code';
export const isSettingAction = (setting: ISettingBase): setting is ISettingAction => setting.type === 'action';
export const isSettingAsset = (setting: ISettingBase): setting is ISettingAsset => setting.type === 'asset';
export interface ISettingStatistics {
account2fa?: boolean;
cannedResponsesEnabled?: boolean;
e2e?: boolean;
e2eDefaultDirectRoom?: boolean;
e2eDefaultPrivateRoom?: boolean;
smtpHost?: string;
smtpPort?: string;
fromEmail?: string;
frameworkDevMode?: boolean;
frameworkEnable?: boolean;
surveyEnabled?: boolean;
updateChecker?: boolean;
liveStream?: boolean;
broadcasting?: boolean;
allowEditing?: boolean;
allowDeleting?: boolean;
allowUnrecognizedSlashCommand?: boolean;
allowBadWordsFilter?: boolean;
readReceiptEnabled?: boolean;
readReceiptStoreUsers?: boolean;
otrEnable?: boolean;
pushEnable?: boolean;
globalSearchEnabled?: boolean;
threadsEnabled?: boolean;
bigBlueButton?: boolean;
jitsiEnabled?: boolean;
webRTCEnableChannel?: boolean;
webRTCEnablePrivate?: boolean;
webRTCEnableDirect?: boolean;
}
export interface ISettingStatisticsObject {
accounts?: {
account2fa?: boolean;
};
cannedResponses?: {
cannedResponsesEnabled?: boolean;
};
e2ee?: {
e2e?: boolean;
e2eDefaultDirectRoom?: boolean;
e2eDefaultPrivateRoom?: boolean;
};
email?: {
smtp?: {
smtpHost?: string;
smtpPort?: string;
fromEmail?: string;
};
};
general?: {
apps?: {
frameworkDevMode?: boolean;
frameworkEnable?: boolean;
};
nps?: {
surveyEnabled?: boolean;
};
update?: {
updateChecker?: boolean;
};
};
liveStreamAndBroadcasting?: {
liveStream?: boolean;
broadcasting?: boolean;
};
message?: {
allowEditing?: boolean;
allowDeleting?: boolean;
allowUnrecognizedSlashCommand?: boolean;
allowBadWordsFilter?: boolean;
readReceiptEnabled?: boolean;
readReceiptStoreUsers?: boolean;
};
otr?: {
otrEnable?: boolean;
};
push?: {
pushEnable?: boolean;
};
search?: {
defaultProvider?: {
globalSearchEnabled?: boolean;
};
};
threads?: {
threadsEnabled?: boolean;
};
videoConference?: {
bigBlueButton?: boolean;
jitsiEnabled?: boolean;
};
webRTC?: {
webRTCEnableChannel?: boolean;
webRTCEnablePrivate?: boolean;
webRTCEnableDirect?: boolean;
};
}

View File

@ -1,5 +1,48 @@
// https://github.com/RocketChat/Rocket.Chat/blob/develop/definition/ITeam.ts
import { IRocketChatRecord } from './IRocketChatRecord';
import { IUser } from './IUser';
export enum TEAM_TYPE {
PUBLIC = 0,
PRIVATE = 1
}
export type SortType = -1 | 1;
export interface ITeam extends IRocketChatRecord {
name: string;
type: TEAM_TYPE;
roomId: string;
createdBy: Pick<IUser, '_id' | 'username'>;
createdAt: Date;
}
export interface ITeamMember extends IRocketChatRecord {
teamId: string;
userId: string;
roles?: Array<string>;
createdBy: Pick<IUser, '_id' | 'username'>;
createdAt: Date;
}
export interface IPaginationOptions {
offset: number;
count: number;
}
export interface IRecordsWithTotal<T> {
records: Array<T>;
total: number;
}
export interface ITeamStatData {
teamId: string;
mainRoom: string;
totalRooms: number;
totalMessages: number;
totalPublicRooms: number;
totalPrivateRooms: number;
totalDefaultRooms: number;
totalMembers: number;
}
export interface ITeamStats {
totalTeams: number;
teamStats: Array<ITeamStatData>;
}

View File

@ -1,10 +1,155 @@
import Model from '@nozbe/watermelondb/Model';
export interface IUser {
_id: string;
name?: string;
username: string;
avatarETag?: string;
import { UserStatus } from './UserStatus';
import { IRocketChatRecord } from './IRocketChatRecord';
export interface ILoginToken {
hashedToken: string;
twoFactorAuthorizedUntil?: Date;
twoFactorAuthorizedHash?: string;
}
export interface IMeteorLoginToken extends ILoginToken {
when: Date;
}
export interface IPersonalAccessToken extends ILoginToken {
type: 'personalAccessToken';
createdAt: Date;
lastTokenPart: string;
name?: string;
bypassTwoFactor?: boolean;
}
export interface IUserEmailVerificationToken {
token: string;
address: string;
when: Date;
}
export interface IUserEmailCode {
code: string;
expire: Date;
}
type LoginToken = IMeteorLoginToken & IPersonalAccessToken;
export type Username = string;
export type ILoginUsername =
| {
username: string;
}
| {
email: string;
};
export type LoginUsername = string | ILoginUsername;
export interface IUserServices {
password?: {
bcrypt: string;
};
passwordHistory?: string[];
email?: {
verificationTokens?: IUserEmailVerificationToken[];
};
resume?: {
loginTokens?: LoginToken[];
};
google?: any;
facebook?: any;
github?: any;
totp?: {
enabled: boolean;
hashedBackup: string[];
secret: string;
};
email2fa?: {
enabled: boolean;
changedAt: Date;
};
emailCode: IUserEmailCode[];
saml?: {
inResponseTo?: string;
provider?: string;
idp?: string;
idpSession?: string;
nameID?: string;
};
ldap?: {
id: string;
idAttribute?: string;
};
}
export interface IUserEmail {
address: string;
verified: boolean;
}
export interface IUserSettings {
profile: any;
preferences: {
[key: string]: any;
};
}
export interface IUser extends IRocketChatRecord {
_id: string;
createdAt: Date;
roles: string[];
type: string;
active: boolean;
username?: string;
name?: string;
services?: IUserServices;
emails?: IUserEmail[];
status?: UserStatus;
statusConnection?: string;
lastLogin?: Date;
avatarOrigin?: string;
avatarETag?: string;
utcOffset?: number;
language?: string;
statusDefault?: UserStatus;
statusText?: string;
oauth?: {
authorizedClients: string[];
};
_updatedAt: Date;
statusLivechat?: string;
e2e?: {
private_key: string;
public_key: string;
};
requirePasswordChange?: boolean;
customFields?: {
[key: string]: any;
};
settings?: IUserSettings;
defaultRoom?: string;
ldap?: boolean;
}
export interface IRegisterUser extends IUser {
username: string;
name: string;
}
export const isRegisterUser = (user: IUser): user is IRegisterUser => user.username !== undefined && user.name !== undefined;
export type IUserDataEvent = {
id: unknown;
} & (
| ({
type: 'inserted';
} & IUser)
| {
type: 'removed';
}
| {
type: 'updated';
diff: Partial<IUser>;
unset: Record<keyof IUser, boolean | 0 | 1>;
}
);
export type TUserModel = IUser & Model;

View File

@ -0,0 +1,6 @@
export enum UserStatus {
ONLINE = 'online',
AWAY = 'away',
OFFLINE = 'offline',
BUSY = 'busy'
}

View File

@ -0,0 +1,5 @@
export type PaginatedRequest<T = {}, S extends string = string> = {
count?: number;
offset?: number;
sort?: `{ "${S}": ${1 | -1} }` | string;
} & T;

View File

@ -0,0 +1,5 @@
export type PaginatedResult<T = {}> = {
count: number;
offset: number;
total: number;
} & T;

View File

@ -0,0 +1,93 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Endpoints } from '../v1';
type ReplacePlaceholders<TPath extends string> = string extends TPath
? TPath
: TPath extends `${infer Start}:${infer _Param}/${infer Rest}`
? `${Start}${string}/${ReplacePlaceholders<Rest>}`
: TPath extends `${infer Start}:${infer _Param}`
? `${Start}${string}`
: TPath;
type KeyOfEach<T> = T extends any ? keyof T : never;
type GetParams<TOperation> = TOperation extends (...args: any) => any
? Parameters<TOperation>[0] extends void
? void
: Parameters<TOperation>[0]
: never;
type GetResult<TOperation> = TOperation extends (...args: any) => any ? ReturnType<TOperation> : never;
type OperationsByPathPatternAndMethod<
TPathPattern extends keyof Endpoints,
TMethod extends KeyOfEach<Endpoints[TPathPattern]> = KeyOfEach<Endpoints[TPathPattern]>
> = TMethod extends any
? {
pathPattern: TPathPattern;
method: TMethod;
path: ReplacePlaceholders<TPathPattern>;
params: GetParams<Endpoints[TPathPattern][TMethod]>;
result: GetResult<Endpoints[TPathPattern][TMethod]>;
}
: never;
type OperationsByPathPattern<TPathPattern extends keyof Endpoints> = TPathPattern extends any
? OperationsByPathPatternAndMethod<TPathPattern>
: never;
type Operations = OperationsByPathPattern<keyof Endpoints>;
type Method = Operations['method'];
export type PathPattern = Operations['pathPattern'];
type Path = Operations['path'];
//
export type Serialized<T> = T extends Date
? Exclude<T, Date> | string
: T extends boolean | number | string | null | undefined
? T
: T extends {}
? {
[K in keyof T]: Serialized<T[K]>;
}
: null;
export type MatchPathPattern<TPath extends Path> = TPath extends any
? Extract<Operations, { path: TPath }>['pathPattern']
: never;
export type OperationResult<
TMethod extends Method,
TPathPattern extends PathPattern
> = TMethod extends keyof Endpoints[TPathPattern] ? GetResult<Endpoints[TPathPattern][TMethod]> : never;
export type PathFor<TMethod extends Method> = TMethod extends any ? Extract<Operations, { method: TMethod }>['path'] : never;
export type OperationParams<
TMethod extends Method,
TPathPattern extends PathPattern
> = TMethod extends keyof Endpoints[TPathPattern] ? GetParams<Endpoints[TPathPattern][TMethod]> : never;
type SuccessResult<T> = T & { success: true };
type FailureResult<T, TStack = undefined, TErrorType = undefined, TErrorDetails = undefined> = {
success: false;
error: T;
stack: TStack;
errorType: TErrorType;
details: TErrorDetails;
};
type UnauthorizedResult<T> = {
success: false;
error: T | 'unauthorized';
};
export type ResultFor<TMethod extends Method, TPathPattern extends PathPattern> =
| SuccessResult<OperationResult<TMethod, TPathPattern>>
| FailureResult<unknown, unknown, unknown, unknown>
| UnauthorizedResult<unknown>;

View File

@ -0,0 +1,20 @@
import type { IMessage } from '../../IMessage';
import type { IRoom } from '../../IRoom';
import type { IUser } from '../../IUser';
export type ChannelsEndpoints = {
'channels.files': {
GET: (params: { roomId: IRoom['_id']; offset: number; count: number; sort: string; query: string }) => {
files: IMessage[];
total: number;
};
};
'channels.members': {
GET: (params: { roomId: IRoom['_id']; offset?: number; count?: number; filter?: string; status?: string[] }) => {
count: number;
offset: number;
members: IUser[];
total: number;
};
};
};

View File

@ -0,0 +1,28 @@
import type { IMessage } from '../../IMessage';
import type { IRoom } from '../../IRoom';
export type ChatEndpoints = {
'chat.getMessage': {
GET: (params: { msgId: IMessage['_id'] }) => {
message: IMessage;
};
};
'chat.followMessage': {
POST: (params: { mid: IMessage['_id'] }) => void;
};
'chat.unfollowMessage': {
POST: (params: { mid: IMessage['_id'] }) => void;
};
'chat.getDiscussions': {
GET: (params: { roomId: IRoom['_id']; text?: string; offset: number; count: number }) => {
messages: IMessage[];
total: number;
};
};
'chat.getThreadsList': {
GET: (params: { rid: IRoom['_id']; type: 'unread' | 'following' | 'all'; text?: string; offset: number; count: number }) => {
threads: IMessage[];
total: number;
};
};
};

View File

@ -0,0 +1,7 @@
export type CustomUserStatusEndpoints = {
'custom-user-status.list': {
GET: (params: { query: string }) => {
statuses: unknown[];
};
};
};

View File

@ -0,0 +1,21 @@
import type { IRoom } from '../../IRoom';
import type { IUser } from '../../IUser';
export type DmEndpoints = {
'dm.create': {
POST: (
params: (
| {
username: Exclude<IUser['username'], undefined>;
}
| {
usernames: string;
}
) & {
excludeSelf?: boolean;
}
) => {
room: IRoom & { rid: IRoom['_id'] };
};
};
};

View File

@ -0,0 +1,21 @@
import type { ICustomEmojiDescriptor } from '../../ICustomEmojiDescriptor';
import { PaginatedRequest } from '../helpers/PaginatedRequest';
import { PaginatedResult } from '../helpers/PaginatedResult';
export type EmojiCustomEndpoints = {
'emoji-custom.all': {
GET: (params: PaginatedRequest<{ query: string }, 'name'>) => {
emojis: ICustomEmojiDescriptor[];
} & PaginatedResult;
};
'emoji-custom.list': {
GET: (params: { query: string }) => {
emojis?: {
update: ICustomEmojiDescriptor[];
};
};
};
'emoji-custom.delete': {
POST: (params: { emojiId: ICustomEmojiDescriptor['_id'] }) => void;
};
};

View File

@ -0,0 +1,20 @@
import type { IMessage } from '../../IMessage';
import type { IRoom } from '../../IRoom';
import type { IUser } from '../../IUser';
export type GroupsEndpoints = {
'groups.files': {
GET: (params: { roomId: IRoom['_id']; count: number; sort: string; query: string }) => {
files: IMessage[];
total: number;
};
};
'groups.members': {
GET: (params: { roomId: IRoom['_id']; offset?: number; count?: number; filter?: string; status?: string[] }) => {
count: number;
offset: number;
members: IUser[];
total: number;
};
};
};

View File

@ -0,0 +1,36 @@
import type { IMessage } from '../../IMessage';
import type { IRoom } from '../../IRoom';
import type { IUser } from '../../IUser';
export type ImEndpoints = {
'im.create': {
POST: (
params: (
| {
username: Exclude<IUser['username'], undefined>;
}
| {
usernames: string;
}
) & {
excludeSelf?: boolean;
}
) => {
room: IRoom;
};
};
'im.files': {
GET: (params: { roomId: IRoom['_id']; count: number; sort: string; query: string }) => {
files: IMessage[];
total: number;
};
};
'im.members': {
GET: (params: { roomId: IRoom['_id']; offset?: number; count?: number; filter?: string; status?: string[] }) => {
count: number;
offset: number;
members: IUser[];
total: number;
};
};
};

View File

@ -0,0 +1,33 @@
import { ChannelsEndpoints } from './channels';
import { ChatEndpoints } from './chat';
import { CustomUserStatusEndpoints } from './customUserStatus';
import { DmEndpoints } from './dm';
import { EmojiCustomEndpoints } from './emojiCustom';
import { GroupsEndpoints } from './groups';
import { ImEndpoints } from './im';
import { InvitesEndpoints } from './invites';
import { OmnichannelEndpoints } from './omnichannel';
import { PermissionsEndpoints } from './permissions';
import { RolesEndpoints } from './roles';
import { RoomsEndpoints } from './rooms';
import { OauthCustomConfiguration } from './settings';
import { UserEndpoints } from './user';
import { UsersEndpoints } from './users';
import { TeamsEndpoints } from './teams';
export type Endpoints = ChannelsEndpoints &
ChatEndpoints &
CustomUserStatusEndpoints &
DmEndpoints &
EmojiCustomEndpoints &
GroupsEndpoints &
ImEndpoints &
InvitesEndpoints &
OmnichannelEndpoints &
PermissionsEndpoints &
RolesEndpoints &
RoomsEndpoints &
OauthCustomConfiguration &
UserEndpoints &
UsersEndpoints &
TeamsEndpoints;

View File

@ -0,0 +1,25 @@
import type { IInvite } from '../../IInvite';
import type { IRoom } from '../../IRoom';
export type InvitesEndpoints = {
listInvites: {
GET: () => Array<IInvite>;
};
'removeInvite/:_id': {
DELETE: () => void;
};
'/v1/useInviteToken': {
POST: (params: { token: string }) => {
room: {
rid: IRoom['_id'];
prid: IRoom['prid'];
fname: IRoom['fname'];
name: IRoom['name'];
t: IRoom['t'];
};
};
};
'/v1/validateInviteToken': {
POST: (params: { token: string }) => { valid: boolean };
};
};

View File

@ -0,0 +1,194 @@
import { ILivechatAgent } from '../../ILivechatAgent';
import { ILivechatDepartment } from '../../ILivechatDepartment';
import { ILivechatDepartmentAgents } from '../../ILivechatDepartmentAgents';
import { ILivechatMonitor } from '../../ILivechatMonitor';
import { ILivechatTag } from '../../ILivechatTag';
import { ILivechatVisitor, ILivechatVisitorDTO } from '../../ILivechatVisitor';
import { IMessage } from '../../IMessage';
import { IOmnichannelRoom, IRoom } from '../../IRoom';
import { ISetting } from '../../ISetting';
import { PaginatedRequest } from '../helpers/PaginatedRequest';
import { PaginatedResult } from '../helpers/PaginatedResult';
type booleanString = 'true' | 'false';
export type OmnichannelEndpoints = {
'livechat/appearance': {
GET: () => {
appearance: ISetting[];
};
};
'livechat/visitors.info': {
GET: (params: { visitorId: string }) => {
visitor: {
visitorEmails: Array<{
address: string;
}>;
};
};
};
'livechat/room.onHold': {
POST: (params: { roomId: IRoom['_id'] }) => void;
};
'livechat/monitors.list': {
GET: (params: PaginatedRequest<{ text: string }>) => PaginatedResult<{
monitors: ILivechatMonitor[];
}>;
};
'livechat/tags.list': {
GET: (params: PaginatedRequest<{ text: string }, 'name'>) => PaginatedResult<{
tags: ILivechatTag[];
}>;
};
'livechat/department': {
GET: (
params: PaginatedRequest<{
text: string;
onlyMyDepartments?: booleanString;
enabled?: boolean;
excludeDepartmentId?: string;
}>
) => PaginatedResult<{
departments: ILivechatDepartment[];
}>;
POST: (params: { department: Partial<ILivechatDepartment>; agents: string[] }) => {
department: ILivechatDepartment;
agents: any[];
};
};
'livechat/department/:_id': {
GET: (params: { onlyMyDepartments?: booleanString; includeAgents?: booleanString }) => {
department: ILivechatDepartment | null;
agents?: any[];
};
PUT: (params: { department: Partial<ILivechatDepartment>[]; agents: any[] }) => {
department: ILivechatDepartment;
agents: any[];
};
DELETE: () => void;
};
'livechat/department.autocomplete': {
GET: (params: { selector: string; onlyMyDepartments: booleanString }) => {
items: ILivechatDepartment[];
};
};
'livechat/department/:departmentId/agents': {
GET: (params: { sort: string }) => PaginatedResult<{ agents: ILivechatDepartmentAgents[] }>;
POST: (params: { upsert: string[]; remove: string[] }) => void;
};
'livechat/departments.available-by-unit/:id': {
GET: (params: PaginatedRequest<{ text: string }>) => PaginatedResult<{
departments: ILivechatDepartment[];
}>;
};
'livechat/departments.by-unit/': {
GET: (params: PaginatedRequest<{ text: string }>) => PaginatedResult<{
departments: ILivechatDepartment[];
}>;
};
'livechat/departments.by-unit/:id': {
GET: (params: PaginatedRequest<{ text: string }>) => PaginatedResult<{
departments: ILivechatDepartment[];
}>;
};
'livechat/department.listByIds': {
GET: (params: { ids: string[]; fields?: Record<string, unknown> }) => { departments: ILivechatDepartment[] };
};
'livechat/custom-fields': {
GET: (params: PaginatedRequest<{ text: string }>) => PaginatedResult<{
customFields: [
{
_id: string;
label: string;
}
];
}>;
};
'livechat/rooms': {
GET: (params: {
guest: string;
fname: string;
servedBy: string[];
status: string;
department: string;
from: string;
to: string;
customFields: any;
current: number;
itemsPerPage: number;
tags: string[];
}) => PaginatedResult<{
rooms: IOmnichannelRoom[];
}>;
};
'livechat/:rid/messages': {
GET: (params: PaginatedRequest<{ query: string }>) => PaginatedResult<{
messages: IMessage[];
}>;
};
'livechat/users/agent': {
GET: (params: PaginatedRequest<{ text?: string }>) => PaginatedResult<{
users: {
_id: string;
emails: {
address: string;
verified: boolean;
}[];
status: string;
name: string;
username: string;
statusLivechat: string;
livechat: {
maxNumberSimultaneousChat: number;
};
}[];
}>;
};
'livechat/visitor': {
POST: (params: { visitor: ILivechatVisitorDTO }) => { visitor: ILivechatVisitor };
};
'livechat/visitor/:token': {
GET: (params: { token: string }) => { visitor: ILivechatVisitor };
DELETE: (params: { token: string }) => { visitor: { _id: string; ts: string } };
};
'livechat/visitor/:token/room': {
GET: (params: { token: string }) => { rooms: IOmnichannelRoom[] };
};
'livechat/visitor.callStatus': {
POST: (params: { token: string; callStatus: string; rid: string; callId: string }) => {
token: string;
callStatus: string;
};
};
'livechat/visitor.status': {
POST: (params: { token: string; status: string }) => { token: string; status: string };
};
'livechat/queue': {
GET: (params: {
agentId?: ILivechatAgent['_id'];
includeOfflineAgents?: boolean;
departmentId?: ILivechatAgent['_id'];
offset: number;
count: number;
sort: string;
}) => {
queue: {
chats: number;
department: { _id: string; name: string };
user: { _id: string; username: string; status: string };
}[];
count: number;
offset: number;
total: number;
};
};
};

View File

@ -0,0 +1,17 @@
import { IPermission } from '../../IPermission';
type PermissionsUpdateProps = { permissions: { _id: string; roles: string[] }[] };
export type PermissionsEndpoints = {
'permissions.listAll': {
GET: (params: { updatedSince?: string }) => {
update: IPermission[];
remove: IPermission[];
};
};
'permissions.update': {
POST: (params: PermissionsUpdateProps) => {
permissions: IPermission[];
};
};
};

View File

@ -0,0 +1,76 @@
import { IRole } from '../../IRole';
import { RocketChatRecordDeleted } from '../../IRocketChatRecord';
import { IUser } from '../../IUser';
type RoleCreateProps = Pick<IRole, 'name'> & Partial<Pick<IRole, 'description' | 'scope' | 'mandatory2fa'>>;
type RoleUpdateProps = { roleId: IRole['_id']; name: IRole['name'] } & Partial<RoleCreateProps>;
type RoleDeleteProps = { roleId: IRole['_id'] };
type RoleAddUserToRoleProps = {
username: string;
roleName: string;
roomId?: string;
};
type RoleRemoveUserFromRoleProps = {
username: string;
roleName: string;
roomId?: string;
scope?: string;
};
type RoleSyncProps = {
updatedSince?: string;
};
export type RolesEndpoints = {
'roles.list': {
GET: () => {
roles: IRole[];
};
};
'roles.sync': {
GET: (params: RoleSyncProps) => {
roles: {
update: IRole[];
remove: RocketChatRecordDeleted<IRole>[];
};
};
};
'roles.create': {
POST: (params: RoleCreateProps) => {
role: IRole;
};
};
'roles.addUserToRole': {
POST: (params: RoleAddUserToRoleProps) => {
role: IRole;
};
};
'roles.getUsersInRole': {
GET: (params: { roomId: string; role: string; offset: number; count: number }) => {
users: IUser[];
total: number;
};
};
'roles.update': {
POST: (role: RoleUpdateProps) => {
role: IRole;
};
};
'roles.delete': {
POST: (prop: RoleDeleteProps) => void;
};
'roles.removeUserFromRole': {
POST: (props: RoleRemoveUserFromRoleProps) => {
role: IRole;
};
};
};

View File

@ -0,0 +1,44 @@
import type { IMessage } from '../../IMessage';
import type { IRoom } from '../../IRoom';
import type { IUser } from '../../IUser';
export type RoomsEndpoints = {
'rooms.autocomplete.channelAndPrivate': {
GET: (params: { selector: string }) => {
items: IRoom[];
};
};
'rooms.autocomplete.channelAndPrivate.withPagination': {
GET: (params: { selector: string; offset?: number; count?: number; sort?: string }) => {
items: IRoom[];
count: number;
offset: number;
total: number;
};
};
'rooms.autocomplete.availableForTeams': {
GET: (params: { name: string }) => {
items: IRoom[];
};
};
'rooms.info': {
GET: (params: { roomId: string } | { roomName: string }) => {
room: IRoom;
};
};
'rooms.createDiscussion': {
POST: (params: {
prid: IRoom['_id'];
pmid?: IMessage['_id'];
t_name: IRoom['fname'];
users?: IUser['username'][];
encrypted?: boolean;
reply?: string;
}) => {
discussion: IRoom;
};
};
'rooms.favorite': {
POST: (params: { roomId: string; favorite: boolean }) => {};
};
};

View File

@ -0,0 +1,103 @@
import { ISetting, ISettingColor } from '../../ISetting';
import { PaginatedResult } from '../helpers/PaginatedResult';
type SettingsUpdateProps = SettingsUpdatePropDefault | SettingsUpdatePropsActions | SettingsUpdatePropsColor;
type SettingsUpdatePropsActions = {
execute: boolean;
};
export type OauthCustomConfiguration = {
_id: string;
clientId?: string;
custom: unknown;
service?: string;
serverURL: unknown;
tokenPath: unknown;
identityPath: unknown;
authorizePath: unknown;
scope: unknown;
loginStyle: 'popup' | 'redirect';
tokenSentVia: unknown;
identityTokenSentVia: unknown;
keyField: unknown;
usernameField: unknown;
emailField: unknown;
nameField: unknown;
avatarField: unknown;
rolesClaim: unknown;
groupsClaim: unknown;
mapChannels: unknown;
channelsMap: unknown;
channelsAdmin: unknown;
mergeUsers: unknown;
mergeRoles: unknown;
accessTokenParam: unknown;
showButton: unknown;
appId: unknown;
consumerKey?: string;
clientConfig: unknown;
buttonLabelText: unknown;
buttonLabelColor: unknown;
buttonColor: unknown;
};
export const isOauthCustomConfiguration = (config: any): config is OauthCustomConfiguration => Boolean(config);
export const isSettingsUpdatePropsActions = (props: Partial<SettingsUpdateProps>): props is SettingsUpdatePropsActions =>
'execute' in props;
type SettingsUpdatePropsColor = {
editor: ISettingColor['editor'];
value: ISetting['value'];
};
export const isSettingsUpdatePropsColor = (props: Partial<SettingsUpdateProps>): props is SettingsUpdatePropsColor =>
'editor' in props && 'value' in props;
type SettingsUpdatePropDefault = {
value: ISetting['value'];
};
export const isSettingsUpdatePropDefault = (props: Partial<SettingsUpdateProps>): props is SettingsUpdatePropDefault =>
'value' in props;
export type SettingsEndpoints = {
'settings.public': {
GET: () => PaginatedResult & {
settings: Array<ISetting>;
};
};
'settings.oauth': {
GET: () => {
services: Partial<OauthCustomConfiguration>[];
};
};
'settings.addCustomOAuth': {
POST: (params: { name: string }) => void;
};
settings: {
GET: () => {
settings: ISetting[];
};
};
'settings/:_id': {
GET: () => Pick<ISetting, '_id' | 'value'>;
POST: (params: SettingsUpdateProps) => void;
};
'service.configurations': {
GET: () => {
configurations: Array<{
appId: string;
secret: string;
}>;
};
};
};

View File

@ -0,0 +1,7 @@
import { IRoom } from '../../IRoom';
export type TeamsEndpoints = {
'teams.removeRoom': {
POST: (params: { roomId: string; teamId: string }) => { room: IRoom };
};
};

View File

@ -0,0 +1,14 @@
import { IUser } from '../../IUser';
export type UserEndpoints = {
'users.info': {
GET: (params: { userId: IUser['_id'] }) => {
user: IUser;
success: boolean;
};
POST: (params: { userId: IUser['_id'] }) => {
user: IUser;
success: boolean;
};
};
};

View File

@ -0,0 +1,14 @@
import type { ITeam } from '../../ITeam';
import type { IUser } from '../../IUser';
export type UsersEndpoints = {
'users.2fa.sendEmailCode': {
POST: (params: { emailOrUsername: string }) => void;
};
'users.autocomplete': {
GET: (params: { selector: string }) => { items: IUser[] };
};
'users.listTeams': {
GET: (params: { userId: IUser['_id'] }) => { teams: Array<ITeam> };
};
};

View File

@ -777,7 +777,7 @@ const RocketChat = {
createDirectMessage(username) {
// RC 0.59.0
return this.post('im.create', { username });
return sdk.post('im.create', { username });
},
createGroupChat() {
@ -831,7 +831,7 @@ const RocketChat = {
},
removeTeamRoom({ roomId, teamId }) {
// RC 3.13.0
return this.post('teams.removeRoom', { roomId, teamId });
return sdk.post('teams.removeRoom', { roomId, teamId });
},
leaveTeam({ teamId, rooms }) {
// RC 3.13.0

View File

@ -1,10 +1,18 @@
import { Rocketchat } from '@rocket.chat/sdk';
import isEmpty from 'lodash/isEmpty';
import EJSON from 'ejson';
import isEmpty from 'lodash/isEmpty';
import reduxStore from '../../createStore';
import { useSsl } from '../../../utils/url';
import { twoFactor } from '../../../utils/twoFactor';
import { useSsl } from '../../../utils/url';
import reduxStore from '../../createStore';
import {
Serialized,
OperationResult,
MatchPathPattern,
OperationParams,
PathFor,
ResultFor
} from '../../../definitions/rest/helpers';
class Sdk {
private sdk: typeof Rocketchat;
@ -31,15 +39,35 @@ class Sdk {
return null;
}
get(...args: any[]): Promise<any> {
return this.sdk.get(...args);
get<TPath extends PathFor<'GET'>>(
endpoint: TPath,
params: void extends OperationParams<'GET', MatchPathPattern<TPath>>
? void
: Serialized<OperationParams<'GET', MatchPathPattern<TPath>>> = undefined as void extends OperationParams<
'GET',
MatchPathPattern<TPath>
>
? void
: Serialized<OperationParams<'GET', MatchPathPattern<TPath>>>
): Promise<Serialized<OperationResult<'GET', MatchPathPattern<TPath>>>> {
return this.sdk.get(endpoint, params);
}
post(...args: any[]): Promise<any> {
post<TPath extends PathFor<'POST'>>(
endpoint: TPath,
params: void extends OperationParams<'POST', MatchPathPattern<TPath>>
? void
: Serialized<OperationParams<'POST', MatchPathPattern<TPath>>> = undefined as void extends OperationParams<
'POST',
MatchPathPattern<TPath>
>
? void
: Serialized<OperationParams<'POST', MatchPathPattern<TPath>>>
): Promise<ResultFor<'POST', MatchPathPattern<TPath>>> {
return new Promise(async (resolve, reject) => {
const isMethodCall = args[0]?.startsWith('method.call/');
const isMethodCall = endpoint?.startsWith('method.call/');
try {
const result = await this.sdk.post(...args);
const result = await this.sdk.post(endpoint, params);
/**
* if API_Use_REST_For_DDP_Calls is enabled and it's a method call,
@ -61,10 +89,10 @@ class Sdk {
const { details } = isMethodCall ? e : e?.data;
try {
await twoFactor({ method: details?.method, invalid: errorType === totpInvalid });
return resolve(this.post(...args));
return resolve(this.post(endpoint, params));
} catch {
// twoFactor was canceled
return resolve({});
return resolve({} as any);
}
} else {
reject(e);
@ -100,6 +128,7 @@ class Sdk {
const { user } = reduxStore.getState().login;
if (API_Use_REST_For_DDP_Calls) {
const url = isEmpty(user) ? 'method.callAnon' : 'method.call';
// @ts-ignore
return this.post(`${url}/${method}`, {
message: EJSON.stringify({ method, params })
});

View File

@ -136,6 +136,8 @@ class AddExistingChannelView extends React.Component<IAddExistingChannelViewProp
const result = await RocketChat.addRoomsToTeam({ rooms: selected, teamId: this.teamId });
if (result.success) {
this.setState({ loading: false });
// @ts-ignore
// TODO: Verify goRoom interface for return of call
goRoom({ item: result, isMasterDetail });
}
} catch (e: any) {