move some message interactions logic to another file

This commit is contained in:
Audric Ackermann 2021-04-23 11:08:38 +10:00
parent 3b30d13719
commit 193fb2a101
No known key found for this signature in database
GPG key ID: 999F434D76324AD4
15 changed files with 140 additions and 77 deletions

View file

@ -384,6 +384,8 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
return;
}
// guess if this is an open
// Server URL valid?
if (serverUrl.length === 0 || !OpenGroup.validate(serverUrl)) {
ToastUtils.pushToastError('connectToServer', window.i18n('invalidOpenGroupUrl'));

View file

@ -1,4 +1,5 @@
import { OpenGroupRequestCommonType } from '../opengroup/opengroupV2/ApiUtil';
import { isOpenGroupV2 } from '../opengroup/utils/OpenGroupUtils';
import { channels } from './channels';
export type OpenGroupV2Room = {
@ -35,7 +36,10 @@ export async function getAllV2OpenGroupRooms(): Promise<Map<string, OpenGroupV2R
export async function getV2OpenGroupRoom(
conversationId: string
): Promise<OpenGroupV2Room | undefined> {
const opengroupv2Rooms = await channels.getV2OpenGroupRoom(conversationId);
if (!isOpenGroupV2(conversationId)) {
throw new Error(`getV2OpenGroupRoom: this is not a valid v2 id: ${conversationId}`);
}
const opengroupv2Rooms = channels.getV2OpenGroupRoom(conversationId);
if (!opengroupv2Rooms) {
return undefined;

3
ts/interactions/index.ts Normal file
View file

@ -0,0 +1,3 @@
import * as MessageInteraction from './message';
export { MessageInteraction };

View file

@ -0,0 +1,62 @@
import _ from 'lodash';
import { getV2OpenGroupRoom } from '../data/opengroups';
import { ConversationModel } from '../models/conversation';
import { ApiV2 } from '../opengroup/opengroupV2';
import { isOpenGroupV2 } from '../opengroup/utils/OpenGroupUtils';
import { PubKey } from '../session/types';
import { ToastUtils } from '../session/utils';
export function banUser(userToBan: string, conversation?: ConversationModel) {
let pubKeyToBan: PubKey;
try {
pubKeyToBan = PubKey.cast(userToBan);
} catch (e) {
window.log.warn(e);
ToastUtils.pushUserBanFailure();
return;
}
window.confirmationDialog({
title: window.i18n('banUser'),
message: window.i18n('banUserConfirm'),
resolve: async () => {
if (!conversation) {
window.log.info('cannot ban user, the corresponding conversation was not found.');
return;
}
let success = false;
if (isOpenGroupV2(conversation.id)) {
const roomInfos = await getV2OpenGroupRoom(conversation.id);
if (!roomInfos) {
window.log.warn('banUser room not found');
} else {
await ApiV2.banUser(pubKeyToBan, _.pick(roomInfos, 'serverUrl', 'roomId'));
}
} else {
const channelAPI = await conversation.getPublicSendData();
if (!channelAPI) {
window.log.info('cannot ban user, the corresponding channelAPI was not found.');
return;
}
success = await channelAPI.banUser(userToBan);
}
if (success) {
ToastUtils.pushUserBanSuccess();
} else {
ToastUtils.pushUserBanFailure();
}
},
});
}
export function copyBodyToClipboard(body?: string) {
window.clipboard.writeText(body);
ToastUtils.pushCopiedToClipBoard();
}
export function copyPubKey(sender: string) {
// this.getSource return out pubkey if this is an outgoing message, or the sender pubkey
window.clipboard.writeText();
ToastUtils.pushCopiedToClipBoard();
}

View file

@ -37,11 +37,14 @@ import {
import { GroupInvitationMessage } from '../session/messages/outgoing/visibleMessage/GroupInvitationMessage';
import { ReadReceiptMessage } from '../session/messages/outgoing/controlMessage/receipt/ReadReceiptMessage';
import { OpenGroup } from '../opengroup/opengroupV1/OpenGroup';
import { openGroupPrefixRegex } from '../opengroup/utils/OpenGroupUtils';
import {
openGroupPrefixRegex,
openGroupV1ConversationIdRegex,
openGroupV2ConversationIdRegex,
} from '../opengroup/utils/OpenGroupUtils';
export enum ConversationType {
GROUP = 'group',
OPEN_GROUP = 'opengroup',
PRIVATE = 'private',
}
@ -188,11 +191,11 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
public isMe() {
return UserUtils.isUsFromCache(this.id);
}
public isPublic() {
return !!(this.id && this.id.match(openGroupPrefixRegex));
public isPublic(): boolean {
return Boolean(this.id && this.id.match(openGroupPrefixRegex));
}
public isOpenGroupV2() {
return this.get('type') === ConversationType.OPEN_GROUP;
public isOpenGroupV2(): boolean {
return Boolean(this.id && this.id.match(openGroupV2ConversationIdRegex));
}
public isClosedGroup() {
return this.get('type') === ConversationType.GROUP && !this.isPublic();
@ -374,7 +377,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
const groupAdmins = this.getGroupAdmins();
const members = this.isGroup() && !this.isPublic() ? this.get('members') : undefined;
// isSelected is overriden by redux
return {
isSelected: false,
@ -1309,6 +1311,10 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
}
public async deletePublicMessages(messages: Array<MessageModel>) {
if (this.isOpenGroupV2()) {
console.warn('FIXME deletePublicMessages');
throw new Error('deletePublicMessages todo');
}
const channelAPI = await this.getPublicSendData();
if (!channelAPI) {

View file

@ -25,6 +25,8 @@ import { VisibleMessage } from '../session/messages/outgoing/visibleMessage/Visi
import { buildSyncMessage } from '../session/utils/syncUtils';
import { isOpenGroupV2 } from '../opengroup/utils/OpenGroupUtils';
import { banUser } from '../opengroup/opengroupV2/OpenGroupAPIV2';
import { getV2OpenGroupRoom } from '../data/opengroups';
import { MessageInteraction } from '../interactions';
export class MessageModel extends Backbone.Model<MessageAttributes> {
public propsForTimerNotification: any;
public propsForGroupNotification: any;
@ -456,8 +458,6 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
const expirationTimestamp =
expirationLength && expireTimerStart ? expireTimerStart + expirationLength : null;
// TODO: investigate why conversation is undefined
// for the public group chat
const conversation = this.getConversation();
const convoId = conversation ? conversation.id : undefined;
@ -697,50 +697,16 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
}
public copyPubKey() {
if (this.isIncoming()) {
window.clipboard.writeText(this.get('source'));
} else {
window.clipboard.writeText(UserUtils.getOurPubKeyStrFromCache());
}
ToastUtils.pushCopiedToClipBoard();
// this.getSource return out pubkey if this is an outgoing message, or the sender pubkey
MessageInteraction.copyPubKey(this.getSource());
}
public banUser() {
window.confirmationDialog({
title: window.i18n('banUser'),
message: window.i18n('banUserConfirm'),
resolve: async () => {
const source = this.get('source');
const conversation = this.getConversation();
if (!conversation) {
window.log.info('cannot ban user, the corresponding conversation was not found.');
return;
}
let success = false;
if (isOpenGroupV2(conversation.id)) {
await banUser();
} else {
const channelAPI = await conversation.getPublicSendData();
if (!channelAPI) {
window.log.info('cannot ban user, the corresponding channelAPI was not found.');
return;
}
success = await channelAPI.banUser(source);
}
if (success) {
ToastUtils.pushUserBanSuccess();
} else {
ToastUtils.pushUserBanFailure();
}
},
});
MessageInteraction.banUser(this.get('source'), this.getConversation());
}
public copyText() {
window.clipboard.writeText(this.get('body'));
ToastUtils.pushCopiedToClipBoard();
MessageInteraction.copyBodyToClipboard(this.get('body'));
}
/**

View file

@ -2,6 +2,7 @@ import _ from 'lodash';
import { getV2OpenGroupRoomByRoomId, saveV2OpenGroupRoom } from '../../data/opengroups';
import { ConversationController } from '../../session/conversations';
import { sendViaOnion } from '../../session/onions/onionSend';
import { PubKey } from '../../session/types';
import { allowOnlyOneAtATime } from '../../session/utils/Promise';
import {
fromArrayBufferToBase64,
@ -273,7 +274,10 @@ export async function getAuthToken({
return null;
}
export const deleteAuthToken = async ({ serverUrl, roomId }: OpenGroupRequestCommonType) => {
export const deleteAuthToken = async ({
serverUrl,
roomId,
}: OpenGroupRequestCommonType): Promise<boolean> => {
const request: OpenGroupV2Request = {
method: 'DELETE',
room: roomId,
@ -281,10 +285,17 @@ export const deleteAuthToken = async ({ serverUrl, roomId }: OpenGroupRequestCom
isAuthRequired: false,
endpoint: 'auth_token',
};
const result = await sendOpenGroupV2Request(request);
const statusCode = parseStatusCodeFromOnionRequest(result);
if (statusCode !== 200) {
window.log.warn(`Could not deleteAuthToken, status code: ${statusCode}`);
try {
const result = await sendOpenGroupV2Request(request);
const statusCode = parseStatusCodeFromOnionRequest(result);
if (statusCode !== 200) {
window.log.warn(`Could not deleteAuthToken, status code: ${statusCode}`);
return false;
}
return true;
} catch (e) {
window.log.error('deleteAuthToken failed:', e);
return false;
}
};
@ -402,10 +413,10 @@ export const isUserModerator = (
};
export const banUser = async (
publicKey: string,
userToBan: PubKey,
roomInfos: OpenGroupRequestCommonType
): Promise<void> => {
const queryParams = { public_key: publicKey };
const queryParams = { public_key: userToBan.key };
const request: OpenGroupV2Request = {
method: 'POST',
room: roomInfos.roomId,
@ -414,11 +425,12 @@ export const banUser = async (
queryParams,
endpoint: 'block_list',
};
await sendOpenGroupV2Request(request);
const banResult = await sendOpenGroupV2Request(request);
console.warn('banResult', banResult);
};
export const unbanUser = async (
publicKey: string,
userToBan: PubKey,
roomInfos: OpenGroupRequestCommonType
): Promise<void> => {
const request: OpenGroupV2Request = {
@ -426,7 +438,7 @@ export const unbanUser = async (
room: roomInfos.roomId,
server: roomInfos.serverUrl,
isAuthRequired: true,
endpoint: `block_list/${publicKey}`,
endpoint: `block_list/${userToBan.key}`,
};
await sendOpenGroupV2Request(request);
};

View file

@ -62,16 +62,19 @@ async function attemptConnectionV2(
}
const conversation = await ConversationController.getInstance().getOrCreateAndWait(
conversationId,
ConversationType.OPEN_GROUP
ConversationType.GROUP
);
room.imageID = roomInfos.imageId || undefined;
room.roomName = roomInfos.name || undefined;
await saveV2OpenGroupRoom(room);
console.warn('openGroupRoom info', roomInfos);
// mark active so it's not in the contacts list but in the conversation list
conversation.set({
active_at: Date.now(),
name: room.roomName,
avatarPath: room.roomName,
});
await conversation.commit();

View file

@ -0,0 +1,3 @@
import * as ApiV2 from './OpenGroupAPIV2';
export { ApiV2 };

View file

@ -28,7 +28,7 @@ export const openGroupPrefix = 'publicChat:';
/**
* Just a regex to match a public chat (i.e. a string starting with publicChat:)
*/
export const openGroupPrefixRegex = new RegExp(`/^${openGroupPrefix}/`);
export const openGroupPrefixRegex = new RegExp(`^${openGroupPrefix}`);
/**
* An open group v1 conversation id can only have the char '1' as roomId

View file

@ -14,6 +14,9 @@ import { BlockedNumberController } from '../../util';
import { getSnodesFor } from '../snode_api/snodePool';
import { PubKey } from '../types';
import { actions as conversationActions } from '../../state/ducks/conversations';
import { getV2OpenGroupRoom, removeV2OpenGroupRoom } from '../../data/opengroups';
import { deleteAuthToken } from '../../opengroup/opengroupV2/OpenGroupAPIV2';
import _ from 'lodash';
export class ConversationController {
private static instance: ConversationController | null;
@ -68,12 +71,8 @@ export class ConversationController {
throw new TypeError("'id' must be a string");
}
if (
type !== ConversationType.PRIVATE &&
type !== ConversationType.GROUP &&
type !== ConversationType.OPEN_GROUP
) {
throw new TypeError(`'type' must be 'private' or 'group' or 'opengroup; got: '${type}'`);
if (type !== ConversationType.PRIVATE && type !== ConversationType.GROUP) {
throw new TypeError(`'type' must be 'private' or 'group' got: '${type}'`);
}
if (!this._initialFetchComplete) {
@ -178,10 +177,6 @@ export class ConversationController {
}
public async deleteContact(id: string) {
if (typeof id !== 'string') {
throw new TypeError("'id' must be a string");
}
if (!this._initialFetchComplete) {
throw new Error('ConversationController.get() needs complete initial fetch');
}
@ -202,9 +197,17 @@ export class ConversationController {
channelAPI.serverAPI.partChannel((channelAPI as any).channelId);
}
} else if (conversation.isOpenGroupV2()) {
window.log.warn('leave open group v2 todo');
window.log.info('leaving open group v2', conversation.id);
const roomInfos = await getV2OpenGroupRoom(conversation.id);
if (roomInfos) {
// leave the group on the remote server
await deleteAuthToken(_.pick(roomInfos, 'serverUrl', 'roomId'));
// remove the roomInfos locally for this open group room
await removeV2OpenGroupRoom(conversation.id);
}
}
// those are the stuff to do for all contact types
await conversation.destroyMessages();
await removeConversation(id);

View file

@ -165,7 +165,7 @@ export const sendViaOnion = async (
// port: url.port,
};
console.warn('sendViaOnion payloadObj ==> ', payloadObj);
window.log.debug('sendViaOnion payloadObj ==> ', payloadObj);
result = await sendOnionRequestLsrpcDest(
0,

View file

@ -113,7 +113,6 @@ const getSslAgentForSeedNode = (seedNodeHost: string, isSsl = false) => {
// read the cert each time. We only run this request once for each seed node nevertheless.
const appPath = remote.app.getAppPath();
const crt = fs.readFileSync(path.join(appPath, `/certificates/${filePrefix}.crt`), 'utf-8');
// debugger;
const sslOptions = {
// as the seed nodes are using a self signed certificate, we have to provide it here.
ca: crt,

View file

@ -227,17 +227,17 @@ describe('Message Utils', () => {
let convos: Array<ConversationModel>;
const mockValidOpenGroup = new MockConversation({
type: ConversationType.OPEN_GROUP,
type: ConversationType.GROUP,
id: `${openGroupPrefix}1@chat-dev.lokinet.org`,
});
const mockValidOpenGroup2 = new MockConversation({
type: ConversationType.OPEN_GROUP,
type: ConversationType.GROUP,
id: `${openGroupPrefix}1@chat-dev2.lokinet.org`,
});
const mockValidClosedGroup = new MockConversation({
type: ConversationType.OPEN_GROUP,
type: ConversationType.GROUP,
});
const mockValidPrivate = {

View file

@ -70,7 +70,7 @@ export class MockConversation {
id: this.id,
name: '',
profileName: undefined,
type: params.type === ConversationType.OPEN_GROUP ? 'group' : params.type,
type: params.type === ConversationType.GROUP ? 'group' : params.type,
members,
left: false,
expireTimer: 0,