918 lines
29 KiB
TypeScript
918 lines
29 KiB
TypeScript
/*
|
||
* https://github.com/morethanwords/tweb
|
||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||
*
|
||
* Originally from:
|
||
* https://github.com/zhukov/webogram
|
||
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
|
||
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
||
*/
|
||
|
||
import deepEqual from '../../helpers/object/deepEqual';
|
||
import isObject from '../../helpers/object/isObject';
|
||
import safeReplaceObject from '../../helpers/object/safeReplaceObject';
|
||
import {ChannelParticipant, ChannelsCreateChannel, Chat, ChatAdminRights, ChatBannedRights, ChatInvite, ChatPhoto, ChatReactions, InputChannel, InputChatPhoto, InputFile, InputPeer, MessagesSponsoredMessages, SponsoredMessage, Update, Updates} from '../../layer';
|
||
import {isRestricted} from '../../helpers/restrictions';
|
||
import {AppManager} from './manager';
|
||
import hasRights from './utils/chats/hasRights';
|
||
import getParticipantPeerId from './utils/chats/getParticipantPeerId';
|
||
import {AppStoragesManager} from './appStoragesManager';
|
||
import getServerMessageId from './utils/messageId/getServerMessageId';
|
||
import {randomLong} from '../../helpers/random';
|
||
import generateMessageId from './utils/messageId/generateMessageId';
|
||
|
||
export type Channel = Chat.channel;
|
||
export type ChatRights = keyof ChatBannedRights['pFlags'] | keyof ChatAdminRights['pFlags'] | 'change_type' | 'change_permissions' | 'delete_chat' | 'view_participants';
|
||
|
||
export class AppChatsManager extends AppManager {
|
||
private storage: AppStoragesManager['storages']['chats'];
|
||
|
||
private chats: {[id: ChatId]: Exclude<Chat, Chat.chatEmpty>};
|
||
// private usernames: any;
|
||
// private channelAccess: any;
|
||
// private megagroups: {[id: number]: true};
|
||
|
||
protected after() {
|
||
this.clear(true);
|
||
|
||
this.apiUpdatesManager.addMultipleEventsListeners({
|
||
/* updateChannel: (update) => {
|
||
const channelId = update.channel_id;
|
||
//console.log('updateChannel:', update);
|
||
rootScope.broadcast('channel_settings', {channelId});
|
||
}, */
|
||
|
||
updateChannelParticipant: (update) => {
|
||
this.apiManager.clearCache('channels.getParticipants', (params) => {
|
||
return (params.channel as InputChannel.inputChannel).channel_id === update.channel_id;
|
||
});
|
||
},
|
||
|
||
updateChatDefaultBannedRights: (update) => {
|
||
const chatId = this.appPeersManager.getPeerId(update.peer).toChatId();
|
||
const chat = this.chats[chatId] as Chat.chat;
|
||
if(chat) {
|
||
chat.default_banned_rights = update.default_banned_rights;
|
||
this.rootScope.dispatchEvent('chat_update', chatId);
|
||
}
|
||
}
|
||
});
|
||
|
||
return Promise.all([
|
||
this.appStateManager.getState(),
|
||
this.appStoragesManager.loadStorage('chats')
|
||
]).then(([state, {results: chats, storage}]) => {
|
||
this.storage = storage;
|
||
|
||
this.saveApiChats(chats);
|
||
|
||
this.peersStorage.addEventListener('peerNeeded', (peerId) => {
|
||
if(peerId.isUser() || this.storage.getFromCache(peerId.toChatId())) {
|
||
return;
|
||
}
|
||
|
||
this.storage.set({
|
||
[peerId.toChatId()]: this.getChat(peerId.toChatId())
|
||
});
|
||
});
|
||
|
||
this.peersStorage.addEventListener('peerUnneeded', (peerId) => {
|
||
if(peerId.isUser() || !this.storage.getFromCache(peerId.toChatId())) {
|
||
return;
|
||
}
|
||
|
||
this.storage.delete(peerId.toChatId());
|
||
});
|
||
});
|
||
}
|
||
|
||
public clear = (init = false) => {
|
||
if(!init) {
|
||
for(const chatId in this.chats) {
|
||
if(!chatId) continue;
|
||
if(!this.peersStorage.isPeerNeeded(chatId.toPeerId(true))) {
|
||
const chat = this.chats[chatId];
|
||
this.appUsersManager.modifyUsernamesCache(chat, false);
|
||
|
||
this.storage.delete(chatId);
|
||
delete this.chats[chatId];
|
||
}
|
||
}
|
||
} else {
|
||
this.chats = {};
|
||
}
|
||
};
|
||
|
||
public saveApiChats(apiChats: any[], override?: boolean) {
|
||
if((apiChats as any).saved) return;
|
||
(apiChats as any).saved = true;
|
||
apiChats.forEach((chat) => this.saveApiChat(chat, override));
|
||
}
|
||
|
||
public saveApiChat(chat: Chat, override?: boolean) {
|
||
if(!chat || chat._ === 'chatEmpty') return;
|
||
/* if(chat._ !== 'chat' && chat._ !== 'channel') {
|
||
return;
|
||
} */
|
||
|
||
// * exclude from state
|
||
// defineNotNumerableProperties(chat, ['rTitle', 'initials']);
|
||
|
||
const oldChat = this.chats[chat.id];
|
||
|
||
/* if(oldChat && !override) {
|
||
return;
|
||
} */
|
||
|
||
(chat as Chat.chat).pFlags ??= {};
|
||
|
||
if((chat as Chat.channel).pFlags.min && oldChat !== undefined) {
|
||
return;
|
||
}
|
||
|
||
if(chat._ === 'channel' &&
|
||
chat.participants_count === undefined &&
|
||
oldChat !== undefined &&
|
||
(oldChat as Chat.channel).participants_count) {
|
||
chat.participants_count = (oldChat as Chat.channel).participants_count;
|
||
}
|
||
|
||
if((chat as Chat.channel).photo?._ === 'chatPhotoEmpty') {
|
||
delete (chat as Chat.channel).photo;
|
||
}
|
||
|
||
const changedUsername = this.appUsersManager.setUsernameToCache(chat, oldChat);
|
||
|
||
/* if(chat.username) {
|
||
let searchUsername = searchIndexManager.cleanUsername(chat.username);
|
||
this.usernames[searchUsername] = chat.id;
|
||
} */
|
||
|
||
const peerId = chat.id.toPeerId(true);
|
||
if(oldChat === undefined) {
|
||
this.chats[chat.id] = chat;
|
||
} else {
|
||
const oldPhotoId = ((oldChat as Chat.chat).photo as ChatPhoto.chatPhoto)?.photo_id;
|
||
const newPhotoId = ((chat as Chat.chat).photo as ChatPhoto.chatPhoto)?.photo_id;
|
||
const toggledForum = (oldChat as Chat.channel).pFlags.forum !== (chat as Chat.channel).pFlags.forum;
|
||
const changedPhoto = oldPhotoId !== newPhotoId || toggledForum;
|
||
|
||
const changedTitle = oldChat.title !== chat.title || changedUsername;
|
||
|
||
const changedAnyBadge = (oldChat as Chat.channel).pFlags.verified !== (chat as Chat.channel).pFlags.verified ||
|
||
(oldChat as Chat.channel).pFlags.scam !== (chat as Chat.channel).pFlags.scam ||
|
||
(oldChat as Chat.channel).pFlags.fake !== (chat as Chat.channel).pFlags.fake;
|
||
|
||
safeReplaceObject(oldChat, chat);
|
||
this.rootScope.dispatchEvent('chat_update', chat.id);
|
||
|
||
if(changedPhoto) {
|
||
this.rootScope.dispatchEvent('avatar_update', {peerId});
|
||
}
|
||
|
||
if(changedTitle || changedAnyBadge) {
|
||
this.rootScope.dispatchEvent('peer_title_edit', {peerId});
|
||
}
|
||
|
||
if(toggledForum) {
|
||
this.rootScope.dispatchEvent('chat_toggle_forum', {chatId: chat.id, enabled: !!(chat as Chat.channel).pFlags.forum});
|
||
}
|
||
}
|
||
|
||
if(this.peersStorage.isPeerNeeded(peerId)) {
|
||
this.storage.set({
|
||
[chat.id]: chat
|
||
});
|
||
}
|
||
}
|
||
|
||
public getChat(id: ChatId) {
|
||
return this.chats[id];
|
||
}
|
||
|
||
/**
|
||
* Check the user's ability to do an action in chat
|
||
* @param id
|
||
* @param action creator can still send messages to left channel. so this function shows server rights. see canSendToPeer for local rights in messages manager.
|
||
* @param rights do not provide this parameter when checking rights for self
|
||
* @param isThread
|
||
* @returns
|
||
*/
|
||
public hasRights(id: ChatId, action: ChatRights, rights?: ChatAdminRights | ChatBannedRights, isThread?: boolean) {
|
||
return hasRights(this.getChat(id), action, rights, isThread);
|
||
}
|
||
|
||
public editChatDefaultBannedRights(id: ChatId, banned_rights: ChatBannedRights) {
|
||
const chat = this.getChat(id) as Chat.chat;
|
||
if(chat.default_banned_rights) {
|
||
if(chat.default_banned_rights.until_date === banned_rights.until_date && deepEqual(chat.default_banned_rights.pFlags, banned_rights.pFlags)) {
|
||
return Promise.resolve();
|
||
}
|
||
}
|
||
|
||
return this.apiManager.invokeApi('messages.editChatDefaultBannedRights', {
|
||
peer: this.appPeersManager.getInputPeerById(id.toPeerId(true)),
|
||
banned_rights
|
||
}).then(this.onChatUpdated.bind(this, id));
|
||
}
|
||
|
||
/* public resolveUsername(username: string) {
|
||
return this.usernames[username] || 0;
|
||
} */
|
||
|
||
/* public saveChannelAccess(id: ChatId, accessHash: string) {
|
||
this.channelAccess[id] = accessHash;
|
||
} */
|
||
|
||
/* public saveIsMegagroup(id: ChatId) {
|
||
this.megagroups[id] = true;
|
||
} */
|
||
|
||
public isChannel(id: ChatId) {
|
||
const chat = this.chats[id];
|
||
return !!(chat && (chat._ === 'channel' || chat._ === 'channelForbidden')/* || this.channelAccess[id] */);
|
||
}
|
||
|
||
public isMegagroup(id: ChatId) {
|
||
/* if(this.megagroups[id]) {
|
||
return true;
|
||
} */
|
||
|
||
const chat: Chat = this.chats[id];
|
||
return !!(chat as Chat.channel)?.pFlags?.megagroup;
|
||
}
|
||
|
||
public isForum(id: ChatId) {
|
||
const chat = this.chats[id];
|
||
return !!(chat as Chat.channel)?.pFlags?.forum;
|
||
}
|
||
|
||
public isBroadcast(id: ChatId) {
|
||
return this.isChannel(id) && !this.isMegagroup(id);
|
||
}
|
||
|
||
public isInChat(id: ChatId) {
|
||
let good = true;
|
||
const chat: Chat = this.getChat(id);
|
||
if(!chat ||
|
||
chat._ === 'channelForbidden' ||
|
||
chat._ === 'chatForbidden' ||
|
||
(chat as any as Chat.chatEmpty)._ === 'chatEmpty' ||
|
||
(chat as Chat.chat).pFlags.left ||
|
||
// || (chat as any).pFlags.kicked
|
||
(chat as Chat.chat).pFlags.deactivated) {
|
||
good = false;
|
||
}
|
||
|
||
return good;
|
||
}
|
||
|
||
public getChannelInput(id: ChatId): InputChannel {
|
||
const chat: Chat = this.getChat(id);
|
||
if(!chat || !(chat as Chat.channel).access_hash) {
|
||
return {
|
||
_: 'inputChannelEmpty'
|
||
};
|
||
} else {
|
||
return {
|
||
_: 'inputChannel',
|
||
channel_id: id,
|
||
access_hash: (chat as Chat.channel).access_hash/* || this.channelAccess[id] */ || '0'
|
||
};
|
||
}
|
||
}
|
||
|
||
public getInputPeer(id: ChatId) {
|
||
return this.isChannel(id) ? this.getChannelInputPeer(id) : this.getChatInputPeer(id);
|
||
}
|
||
|
||
public getChatInputPeer(id: ChatId): InputPeer.inputPeerChat {
|
||
return {
|
||
_: 'inputPeerChat',
|
||
chat_id: id
|
||
};
|
||
}
|
||
|
||
public getChannelInputPeer(id: ChatId): InputPeer.inputPeerChannel {
|
||
return {
|
||
_: 'inputPeerChannel',
|
||
channel_id: id,
|
||
access_hash: (this.getChat(id) as Chat.channel).access_hash/* || this.channelAccess[id] */ || 0
|
||
};
|
||
}
|
||
|
||
public hasChat(id: ChatId, allowMin?: true) {
|
||
const chat = this.chats[id];
|
||
return isObject(chat) && (allowMin || !(chat as Chat.channel).pFlags.min);
|
||
}
|
||
|
||
public getChatString(id: ChatId) {
|
||
const chat = this.getChat(id);
|
||
if(this.isChannel(id)) {
|
||
return (this.isMegagroup(id) ? 's' : 'c') + id + '_' + (chat as Chat.channel).access_hash;
|
||
}
|
||
return 'g' + id;
|
||
}
|
||
|
||
/* public wrapForFull(id: number, fullChat: any) {
|
||
const chatFull = copy(fullChat);
|
||
const chat = this.getChat(id);
|
||
|
||
if(!chatFull.participants_count) {
|
||
chatFull.participants_count = chat.participants_count;
|
||
}
|
||
|
||
if(chatFull.participants &&
|
||
chatFull.participants._ === 'chatParticipants') {
|
||
chatFull.participants.participants = this.wrapParticipants(id, chatFull.participants.participants);
|
||
}
|
||
|
||
if(chatFull.about) {
|
||
chatFull.rAbout = wrapRichText(chatFull.about, {noLinebreaks: true});
|
||
}
|
||
|
||
//chatFull.peerString = this.getChatString(id);
|
||
chatFull.chat = chat;
|
||
|
||
return chatFull;
|
||
}
|
||
|
||
public wrapParticipants(id: number, participants: any[]) {
|
||
const chat = this.getChat(id);
|
||
const myId = appUsersManager.getSelf().id;
|
||
if(this.isChannel(id)) {
|
||
const isAdmin = chat.pFlags.creator;
|
||
participants.forEach((participant) => {
|
||
participant.canLeave = myId === participant.user_id;
|
||
participant.canKick = isAdmin && participant._ === 'channelParticipant';
|
||
|
||
// just for order by last seen
|
||
participant.user = appUsersManager.getUser(participant.user_id);
|
||
});
|
||
} else {
|
||
const isAdmin = chat.pFlags.creator || chat.pFlags.admins_enabled && chat.pFlags.admin;
|
||
participants.forEach((participant) => {
|
||
participant.canLeave = myId === participant.user_id;
|
||
participant.canKick = !participant.canLeave && (
|
||
chat.pFlags.creator ||
|
||
participant._ === 'chatParticipant' && (isAdmin || myId === participant.inviter_id)
|
||
);
|
||
|
||
// just for order by last seen
|
||
participant.user = appUsersManager.getUser(participant.user_id);
|
||
});
|
||
}
|
||
|
||
return participants;
|
||
} */
|
||
|
||
public createChannel(options: ChannelsCreateChannel): Promise<ChatId> {
|
||
return this.apiManager.invokeApi('channels.createChannel', options).then((updates) => {
|
||
this.apiUpdatesManager.processUpdateMessage(updates);
|
||
|
||
const channelId = (updates as any).chats[0].id;
|
||
return channelId;
|
||
});
|
||
}
|
||
|
||
public inviteToChannel(id: ChatId, userIds: UserId[]) {
|
||
const input = this.getChannelInput(id);
|
||
const usersInputs = userIds.map((u) => this.appUsersManager.getUserInput(u));
|
||
|
||
return this.apiManager.invokeApi('channels.inviteToChannel', {
|
||
channel: input,
|
||
users: usersInputs
|
||
}).then(this.onChatUpdated.bind(this, id));
|
||
}
|
||
|
||
public createChat(title: string, userIds: UserId[]): Promise<ChatId> {
|
||
return this.apiManager.invokeApi('messages.createChat', {
|
||
users: userIds.map((u) => this.appUsersManager.getUserInput(u)),
|
||
title
|
||
}).then((updates) => {
|
||
this.apiUpdatesManager.processUpdateMessage(updates);
|
||
|
||
const chatId = (updates as any as Updates.updates).chats[0].id;
|
||
return chatId;
|
||
});
|
||
}
|
||
|
||
private onChatUpdated = (chatId: ChatId, updates?: Updates) => {
|
||
// console.log('onChatUpdated', chatId, updates);
|
||
|
||
this.apiUpdatesManager.processUpdateMessage(updates);
|
||
if((updates as Updates.updates)?.updates?.length && this.isChannel(chatId)) {
|
||
this.rootScope.dispatchEvent('invalidate_participants', chatId);
|
||
}
|
||
};
|
||
|
||
public leaveChannel(id: ChatId) {
|
||
return this.apiManager.invokeApi('channels.leaveChannel', {
|
||
channel: this.getChannelInput(id)
|
||
}).then(this.onChatUpdated.bind(this, id));
|
||
}
|
||
|
||
public joinChannel(id: ChatId) {
|
||
return this.apiManager.invokeApi('channels.joinChannel', {
|
||
channel: this.getChannelInput(id)
|
||
}).then(this.onChatUpdated.bind(this, id));
|
||
}
|
||
|
||
public addChatUser(id: ChatId, userId: UserId, fwdLimit = 100) {
|
||
return this.apiManager.invokeApi('messages.addChatUser', {
|
||
chat_id: id,
|
||
user_id: this.appUsersManager.getUserInput(userId),
|
||
fwd_limit: fwdLimit
|
||
}).then(this.onChatUpdated.bind(this, id));
|
||
}
|
||
|
||
public deleteChatUser(id: ChatId, userId: UserId) {
|
||
return this.apiManager.invokeApi('messages.deleteChatUser', {
|
||
chat_id: id,
|
||
user_id: this.appUsersManager.getUserInput(userId)
|
||
}).then(this.onChatUpdated.bind(this, id));
|
||
}
|
||
|
||
public leaveChat(id: ChatId) {
|
||
return this.deleteChatUser(id, this.appUsersManager.getSelf().id);
|
||
}
|
||
|
||
public leave(id: ChatId) {
|
||
return this.isChannel(id) ? this.leaveChannel(id) : this.leaveChat(id);
|
||
}
|
||
|
||
public delete(id: ChatId) {
|
||
return this.isChannel(id) ? this.deleteChannel(id) : this.deleteChat(id);
|
||
}
|
||
|
||
public deleteChannel(id: ChatId) {
|
||
return this.apiManager.invokeApi('channels.deleteChannel', {
|
||
channel: this.getChannelInput(id)
|
||
}).then(this.onChatUpdated.bind(this, id));
|
||
}
|
||
|
||
public deleteChat(id: ChatId) {
|
||
// return this.leaveChat(id).then(() => {
|
||
return this.apiManager.invokeApi('messages.deleteChat', {
|
||
chat_id: id
|
||
});
|
||
// });
|
||
}
|
||
|
||
public migrateChat(id: ChatId): Promise<ChatId> {
|
||
const chat: Chat = this.getChat(id);
|
||
if(chat._ === 'channel') return Promise.resolve(chat.id);
|
||
return this.apiManager.invokeApi('messages.migrateChat', {
|
||
chat_id: id
|
||
}).then((updates) => {
|
||
this.onChatUpdated(id, updates);
|
||
const update: Update.updateChannel = (updates as Updates.updates).updates.find((u) => u._ === 'updateChannel') as any;
|
||
return update.channel_id;
|
||
});
|
||
}
|
||
|
||
public updateUsername(id: ChatId, username: string, doNotRefresh?: boolean) {
|
||
const promise = this.apiManager.invokeApi('channels.updateUsername', {
|
||
channel: this.getChannelInput(id),
|
||
username
|
||
});
|
||
|
||
return this.refreshChatAfterRequest(id, promise, doNotRefresh);
|
||
}
|
||
|
||
public editPhoto(id: ChatId, inputFile: InputFile) {
|
||
const inputChatPhoto: InputChatPhoto = {
|
||
_: 'inputChatUploadedPhoto',
|
||
file: inputFile
|
||
};
|
||
|
||
let promise: any;
|
||
if(this.isChannel(id)) {
|
||
promise = this.apiManager.invokeApi('channels.editPhoto', {
|
||
channel: this.getChannelInput(id),
|
||
photo: inputChatPhoto
|
||
});
|
||
} else {
|
||
promise = this.apiManager.invokeApi('messages.editChatPhoto', {
|
||
chat_id: id,
|
||
photo: inputChatPhoto
|
||
});
|
||
}
|
||
|
||
return promise.then((updates: any) => {
|
||
this.apiUpdatesManager.processUpdateMessage(updates);
|
||
});
|
||
}
|
||
|
||
public editTitle(id: ChatId, title: string) {
|
||
let promise: any;
|
||
|
||
if(this.isChannel(id)) {
|
||
promise = this.apiManager.invokeApi('channels.editTitle', {
|
||
channel: this.getChannelInput(id),
|
||
title
|
||
});
|
||
} else {
|
||
promise = this.apiManager.invokeApi('messages.editChatTitle', {
|
||
chat_id: id,
|
||
title
|
||
});
|
||
}
|
||
|
||
return promise.then((updates: any) => {
|
||
this.apiUpdatesManager.processUpdateMessage(updates);
|
||
});
|
||
}
|
||
|
||
public editAbout(id: ChatId, about: string) {
|
||
const peerId = id.toPeerId(true);
|
||
return this.apiManager.invokeApi('messages.editChatAbout', {
|
||
peer: this.appPeersManager.getInputPeerById(peerId),
|
||
about
|
||
}).then((bool) => {
|
||
if(bool) {
|
||
this.rootScope.dispatchEvent('peer_bio_edit', peerId);
|
||
}
|
||
|
||
return bool;
|
||
});
|
||
}
|
||
|
||
public editBanned(id: ChatId, participant: PeerId | ChannelParticipant, banned_rights: ChatBannedRights) {
|
||
const peerId = typeof(participant) !== 'object' ? participant : getParticipantPeerId(participant);
|
||
return this.apiManager.invokeApi('channels.editBanned', {
|
||
channel: this.getChannelInput(id),
|
||
participant: this.appPeersManager.getInputPeerById(peerId),
|
||
banned_rights
|
||
}).then((updates) => {
|
||
this.onChatUpdated(id, updates);
|
||
|
||
if(typeof(participant) === 'object') {
|
||
const timestamp = Date.now() / 1000 | 0;
|
||
this.apiUpdatesManager.processLocalUpdate({
|
||
_: 'updateChannelParticipant',
|
||
channel_id: id,
|
||
date: timestamp,
|
||
actor_id: undefined,
|
||
qts: undefined,
|
||
user_id: peerId,
|
||
prev_participant: participant,
|
||
new_participant: Object.keys(banned_rights.pFlags).length ? {
|
||
_: 'channelParticipantBanned',
|
||
date: timestamp,
|
||
banned_rights,
|
||
kicked_by: this.appUsersManager.getSelf().id,
|
||
peer: this.appPeersManager.getOutputPeer(peerId),
|
||
pFlags: {}
|
||
} : undefined
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
public clearChannelParticipantBannedRights(id: ChatId, participant: PeerId | ChannelParticipant) {
|
||
return this.editBanned(id, participant, {
|
||
_: 'chatBannedRights',
|
||
until_date: 0,
|
||
pFlags: {}
|
||
});
|
||
}
|
||
|
||
public kickFromChannel(id: ChatId, participant: PeerId | ChannelParticipant) {
|
||
return this.editBanned(id, participant, {
|
||
_: 'chatBannedRights',
|
||
until_date: 0,
|
||
pFlags: {
|
||
view_messages: true
|
||
}
|
||
});
|
||
}
|
||
|
||
public kickFromChat(id: ChatId, participant: PeerId | ChannelParticipant) {
|
||
if(this.isChannel(id)) return this.kickFromChannel(id, participant);
|
||
else return this.deleteChatUser(id, (participant as PeerId).toUserId());
|
||
}
|
||
|
||
public resolveChannel(id: ChatId) {
|
||
return this.apiManager.invokeApiSingle('channels.getChannels', {
|
||
id: [{
|
||
_: 'inputChannel',
|
||
channel_id: id,
|
||
access_hash: '0'
|
||
}]
|
||
}).then((messagesChats) => {
|
||
this.saveApiChats(messagesChats.chats);
|
||
});
|
||
}
|
||
|
||
public togglePreHistoryHidden(id: ChatId, enabled: boolean) {
|
||
return this.migrateChat(id).then((channelId) => {
|
||
return this.apiManager.invokeApi('channels.togglePreHistoryHidden', {
|
||
channel: this.getChannelInput(channelId),
|
||
enabled
|
||
}).then(this.onChatUpdated.bind(this, channelId));
|
||
});
|
||
}
|
||
|
||
public toggleSignatures(id: ChatId, enabled: boolean) {
|
||
return this.apiManager.invokeApi('channels.toggleSignatures', {
|
||
channel: this.getChannelInput(id),
|
||
enabled
|
||
}).then((updates) => {
|
||
this.apiUpdatesManager.processUpdateMessage(updates);
|
||
});
|
||
}
|
||
|
||
public toggleNoForwards(id: ChatId, enabled: boolean) {
|
||
return this.apiManager.invokeApi('messages.toggleNoForwards', {
|
||
peer: this.getInputPeer(id),
|
||
enabled
|
||
}).then((updates) => {
|
||
this.apiUpdatesManager.processUpdateMessage(updates);
|
||
});
|
||
}
|
||
|
||
public setChatAvailableReactions(id: ChatId, reactions: ChatReactions) {
|
||
const chatFull = this.appProfileManager.getCachedFullChat(id);
|
||
if(chatFull) {
|
||
chatFull.available_reactions = reactions;
|
||
this.rootScope.dispatchEvent('chat_full_update', id);
|
||
}
|
||
|
||
return this.apiManager.invokeApi('messages.setChatAvailableReactions', {
|
||
peer: this.getInputPeer(id),
|
||
available_reactions: reactions
|
||
}).then((updates) => {
|
||
this.apiUpdatesManager.processUpdateMessage(updates);
|
||
});
|
||
}
|
||
|
||
public getSendAs(channelId: ChatId) {
|
||
return this.apiManager.invokeApiSingleProcess({
|
||
method: 'channels.getSendAs',
|
||
params: {
|
||
peer: this.getChannelInputPeer(channelId)
|
||
},
|
||
processResult: (sendAsPeers) => {
|
||
this.appUsersManager.saveApiUsers(sendAsPeers.users);
|
||
this.saveApiChats(sendAsPeers.chats);
|
||
|
||
return sendAsPeers.peers;
|
||
}
|
||
});
|
||
}
|
||
|
||
public importChatInvite(hash: string) {
|
||
return this.apiManager.invokeApi('messages.importChatInvite', {hash})
|
||
.then((updates) => {
|
||
this.apiUpdatesManager.processUpdateMessage(updates);
|
||
const chat = (updates as Updates.updates).chats[0];
|
||
return chat.id;
|
||
});
|
||
}
|
||
|
||
public checkUsername(chatId: ChatId, username: string) {
|
||
return this.apiManager.invokeApi('channels.checkUsername', {
|
||
channel: this.getChannelInput(chatId),
|
||
username
|
||
});
|
||
}
|
||
|
||
public getSponsoredMessage(chatId: ChatId) {
|
||
// const s: MessagesSponsoredMessages.messagesSponsoredMessages = {
|
||
// '_': 'messages.sponsoredMessages',
|
||
// 'messages': [
|
||
// {
|
||
// '_': 'sponsoredMessage',
|
||
// 'pFlags': {},
|
||
// 'flags': 9,
|
||
// 'random_id': new Uint8Array([
|
||
// 80,
|
||
// 5,
|
||
// 249,
|
||
// 174,
|
||
// 44,
|
||
// 73,
|
||
// 173,
|
||
// 14,
|
||
// 246,
|
||
// 81,
|
||
// 187,
|
||
// 182,
|
||
// 223,
|
||
// 5,
|
||
// 4,
|
||
// 128
|
||
// ]),
|
||
// 'from_id': {
|
||
// '_': 'peerUser',
|
||
// 'user_id': 983000232
|
||
// },
|
||
// 'start_param': 'GreatMinds',
|
||
// 'message': 'This is a long sponsored message. In fact, it has the maximum length allowed on the platform – 160 characters 😬😬. It\'s promoting a bot with a start parameter.' + chatId
|
||
// }
|
||
// ],
|
||
// 'chats': [],
|
||
// 'users': [
|
||
// {
|
||
// '_': 'user',
|
||
// 'pFlags': {
|
||
// 'bot': true,
|
||
// 'verified': true,
|
||
// 'apply_min_photo': true
|
||
// },
|
||
// 'flags': 34226219,
|
||
// 'id': 983000232,
|
||
// 'access_hash': '-294959558742535650',
|
||
// 'first_name': 'Quiz Bot',
|
||
// 'username': 'QuizBot',
|
||
// 'photo': {
|
||
// '_': 'userProfilePhoto',
|
||
// 'pFlags': {},
|
||
// 'flags': 2,
|
||
// 'photo_id': '4221953848856651689',
|
||
// 'stripped_thumb': new Uint8Array([
|
||
// 1,
|
||
// 8,
|
||
// 8,
|
||
// 155,
|
||
// 247,
|
||
// 95,
|
||
// 103,
|
||
// 255,
|
||
// 0,
|
||
// 110,
|
||
// 138,
|
||
// 40,
|
||
// 174,
|
||
// 132,
|
||
// 142,
|
||
// 6,
|
||
// 238,
|
||
// 127
|
||
// ]),
|
||
// 'dc_id': 2
|
||
// },
|
||
// 'bot_info_version': 11,
|
||
// 'bot_inline_placeholder': 'Search a quiz...',
|
||
// 'sortName': 'quiz bot'
|
||
// }
|
||
// ]
|
||
// };
|
||
|
||
// const promise = Promise.resolve(s);
|
||
const promise = this.apiManager.invokeApiCacheable('channels.getSponsoredMessages', {
|
||
channel: this.getChannelInput(chatId)
|
||
}, {cacheSeconds: 300});
|
||
|
||
return promise.then((sponsoredMessages) => {
|
||
if(sponsoredMessages._ === 'messages.sponsoredMessages') {
|
||
this.appUsersManager.saveApiUsers(sponsoredMessages.users);
|
||
this.appChatsManager.saveApiChats(sponsoredMessages.chats);
|
||
|
||
const sponsoredMessage = sponsoredMessages.messages.shift();
|
||
sponsoredMessages.messages.push(sponsoredMessage);
|
||
}
|
||
|
||
return sponsoredMessages;
|
||
});
|
||
}
|
||
|
||
public viewSponsoredMessage(chatId: ChatId, randomId: SponsoredMessage['random_id']) {
|
||
return this.apiManager.invokeApiSingle('channels.viewSponsoredMessage', {
|
||
channel: this.getChannelInput(chatId),
|
||
random_id: randomId
|
||
});
|
||
}
|
||
|
||
public checkChatInvite(hash: string) {
|
||
return this.apiManager.invokeApi('messages.checkChatInvite', {
|
||
hash: hash
|
||
}).then((chatInvite) => {
|
||
if((chatInvite as ChatInvite.chatInvitePeek).chat) {
|
||
this.saveApiChat((chatInvite as ChatInvite.chatInvitePeek).chat, true);
|
||
}
|
||
|
||
return chatInvite;
|
||
});
|
||
}
|
||
|
||
public toggleUsername(chatId: ChatId, username: string, active: boolean) {
|
||
const promise = this.apiManager.invokeApi('channels.toggleUsername', {
|
||
channel: this.getChannelInput(chatId),
|
||
username,
|
||
active
|
||
});
|
||
|
||
return this.refreshChatAfterRequest(chatId, promise);
|
||
}
|
||
|
||
public reorderUsernames(chatId: ChatId, order: string[]) {
|
||
const promise = this.apiManager.invokeApi('channels.reorderUsernames', {
|
||
channel: this.getChannelInput(chatId),
|
||
order
|
||
});
|
||
|
||
return this.refreshChatAfterRequest(chatId, promise);
|
||
}
|
||
|
||
public deactivateAllUsernames(chatId: ChatId, doNotRefresh?: boolean) {
|
||
const promise = this.apiManager.invokeApi('channels.deactivateAllUsernames', {
|
||
channel: this.getChannelInput(chatId)
|
||
});
|
||
|
||
return this.refreshChatAfterRequest(chatId, promise, doNotRefresh);
|
||
}
|
||
|
||
public makeChannelPrivate(chatId: ChatId) {
|
||
const promises: Promise<boolean>[] = [
|
||
this.updateUsername(chatId, '', true),
|
||
this.deactivateAllUsernames(chatId, true)
|
||
];
|
||
|
||
const promise = Promise.all(promises).then(() => true);
|
||
return this.refreshChatAfterRequest(chatId, promise);
|
||
}
|
||
|
||
public refreshChatAfterRequest<T extends Promise<any>>(chatId: ChatId, promise: T, doNotRefresh?: boolean): T {
|
||
if(doNotRefresh) {
|
||
return promise;
|
||
}
|
||
|
||
return promise.then((value) => {
|
||
return this.getChannels([chatId]).then(() => value);
|
||
}) as T;
|
||
}
|
||
|
||
public getChannels(chatIds: ChatId[]) {
|
||
return this.apiManager.invokeApi('channels.getChannels', {
|
||
id: chatIds.map((chatId) => this.getChannelInput(chatId))
|
||
}).then((messagesChats) => {
|
||
this.saveApiChats(messagesChats.chats);
|
||
});
|
||
}
|
||
|
||
public toggleForum(chatId: ChatId, enabled: boolean) {
|
||
return this.migrateChat(chatId).then((channelId) => {
|
||
return this.apiManager.invokeApi('channels.toggleForum', {
|
||
channel: this.getChannelInput(channelId),
|
||
enabled
|
||
}).then(this.onChatUpdated.bind(this, channelId));
|
||
});
|
||
}
|
||
|
||
public editForumTopic(options: {
|
||
chatId: ChatId,
|
||
topicId: number,
|
||
title?: string,
|
||
iconEmojiId?: DocId,
|
||
closed?: boolean,
|
||
hidden?: boolean
|
||
}) {
|
||
const {chatId, topicId, title, iconEmojiId, closed, hidden} = options;
|
||
return this.apiManager.invokeApi('channels.editForumTopic', {
|
||
channel: this.getChannelInput(chatId),
|
||
topic_id: getServerMessageId(topicId),
|
||
title,
|
||
icon_emoji_id: iconEmojiId,
|
||
closed,
|
||
hidden
|
||
}).then(this.onChatUpdated.bind(this, chatId));
|
||
}
|
||
|
||
public async createForumTopic(options: {
|
||
chatId: ChatId,
|
||
title: string,
|
||
iconColor: number,
|
||
iconEmojiId: DocId
|
||
}) {
|
||
const {chatId, title, iconColor, iconEmojiId} = options;
|
||
|
||
const channelFull = await this.appProfileManager.getChannelFull(chatId);
|
||
const sendAsInputPeer = channelFull.default_send_as && this.appPeersManager.getInputPeerById(this.appPeersManager.getPeerId(channelFull.default_send_as));
|
||
|
||
return this.apiManager.invokeApi('channels.createForumTopic', {
|
||
channel: this.getChannelInput(chatId),
|
||
title,
|
||
icon_color: iconColor,
|
||
icon_emoji_id: iconEmojiId,
|
||
random_id: randomLong(),
|
||
send_as: sendAsInputPeer
|
||
}).then((updates) => {
|
||
this.onChatUpdated(chatId, updates);
|
||
|
||
const update = (updates as Updates.updates).updates.find((update) => update._ === 'updateNewChannelMessage') as Update.updateNewChannelMessage;
|
||
return generateMessageId(update.message.id);
|
||
});
|
||
}
|
||
|
||
public updatePinnedForumTopic(chatId: ChatId, topicId: number, pinned: boolean) {
|
||
return this.apiManager.invokeApi('channels.updatePinnedForumTopic', {
|
||
channel: this.getChannelInput(chatId),
|
||
topic_id: getServerMessageId(topicId),
|
||
pinned
|
||
}).then(this.onChatUpdated.bind(this, chatId));
|
||
}
|
||
}
|