Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
247 changes: 247 additions & 0 deletions src/channel_batch_updater.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
import type { StreamChat } from './client';
import type {
APIResponse,
BatchChannelDataUpdate,
NewMemberPayload,
UpdateChannelsBatchFilters,
UpdateChannelsBatchResponse,
} from './types';

/**
* ChannelBatchUpdater - A class that provides convenience methods for batch channel operations
*/
export class ChannelBatchUpdater {
client: StreamChat;

constructor(client: StreamChat) {
this.client = client;
}

// Member operations

/**
* addMembers - Add members to channels matching the filter
*
* @param {UpdateChannelsBatchFilters} filter Filter to select channels
* @param {string[] | NewMemberPayload[]} members Members to add
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async addMembers(
filter: UpdateChannelsBatchFilters,
members: string[] | NewMemberPayload[],
): Promise<APIResponse & UpdateChannelsBatchResponse> {
return await this.client.updateChannelsBatch({
operation: 'addMembers',
filter,
members,
});
}

/**
* removeMembers - Remove members from channels matching the filter
*
* @param {UpdateChannelsBatchFilters} filter Filter to select channels
* @param {string[]} members Member IDs to remove
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async removeMembers(
filter: UpdateChannelsBatchFilters,
members: string[],
): Promise<APIResponse & UpdateChannelsBatchResponse> {
return await this.client.updateChannelsBatch({
operation: 'removeMembers',
filter,
members,
});
}

/**
* inviteMembers - Invite members to channels matching the filter
*
* @param {UpdateChannelsBatchFilters} filter Filter to select channels
* @param {string[] | NewMemberPayload[]} members Members to invite
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async inviteMembers(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a question. What happens under the hood, when we call inviteMembers? How does it differ from addMembers?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have this two options, or just add the member "without permission" or invite the member, this second one needs the member agree with that, the user can disagree and will not be added as a member

filter: UpdateChannelsBatchFilters,
members: string[] | NewMemberPayload[],
): Promise<APIResponse & UpdateChannelsBatchResponse> {
return await this.client.updateChannelsBatch({
operation: 'invites',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if possible, but to be consistent with removeMembers, the operation should be called 'inviteMembers'?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@javierdfm can answer this more properly, but I think the idea is it should be something clear with the abstraction layer for example:

channel.inviteMembers() -> client.updateChannelsBatch()

the operation will be the "user level" layer and the string indicating the operation will be more internal

filter,
members,
});
}

/**
* addModerators - Add moderators to channels matching the filter
*
* @param {UpdateChannelsBatchFilters} filter Filter to select channels
* @param {string[]} members Member IDs to promote to moderator
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async addModerators(
filter: UpdateChannelsBatchFilters,
members: string[],
): Promise<APIResponse & UpdateChannelsBatchResponse> {
return await this.client.updateChannelsBatch({
operation: 'addModerators',
filter,
members,
});
}

/**
* demoteModerators - Remove moderator role from members in channels matching the filter
*
* @param {UpdateChannelsBatchFilters} filter Filter to select channels
* @param {string[]} members Member IDs to demote
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async demoteModerators(
filter: UpdateChannelsBatchFilters,
members: string[],
): Promise<APIResponse & UpdateChannelsBatchResponse> {
return await this.client.updateChannelsBatch({
operation: 'demoteModerators',
filter,
members,
});
}

/**
* assignRoles - Assign roles to members in channels matching the filter
*
* @param {UpdateChannelsBatchFilters} filter Filter to select channels
* @param {NewMemberPayload[]} members Members with role assignments
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async assignRoles(
filter: UpdateChannelsBatchFilters,
members: NewMemberPayload[],
): Promise<APIResponse & UpdateChannelsBatchResponse> {
return await this.client.updateChannelsBatch({
operation: 'assignRoles',
filter,
members,
});
}

// Visibility operations

/**
* hide - Hide channels matching the filter
*
* @param {UpdateChannelsBatchFilters} filter Filter to select channels
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async hide(
filter: UpdateChannelsBatchFilters,
): Promise<APIResponse & UpdateChannelsBatchResponse> {
return await this.client.updateChannelsBatch({
operation: 'hide',
filter,
});
}

/**
* show - Show channels matching the filter
*
* @param {UpdateChannelsBatchFilters} filter Filter to select channels
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async show(
filter: UpdateChannelsBatchFilters,
): Promise<APIResponse & UpdateChannelsBatchResponse> {
return await this.client.updateChannelsBatch({
operation: 'show',
filter,
});
}

/**
* archive - Archive channels matching the filter
*
* @param {UpdateChannelsBatchFilters} filter Filter to select channels
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async archive(
filter: UpdateChannelsBatchFilters,
): Promise<APIResponse & UpdateChannelsBatchResponse> {
return await this.client.updateChannelsBatch({
operation: 'archive',
filter,
});
}

/**
* unarchive - Unarchive channels matching the filter
*
* @param {UpdateChannelsBatchFilters} filter Filter to select channels
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async unarchive(
filter: UpdateChannelsBatchFilters,
): Promise<APIResponse & UpdateChannelsBatchResponse> {
return await this.client.updateChannelsBatch({
operation: 'unarchive',
filter,
});
}

// Data operations

/**
* updateData - Update data on channels matching the filter
*
* @param {UpdateChannelsBatchFilters} filter Filter to select channels
* @param {BatchChannelDataUpdate} data Data to update
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async updateData(
filter: UpdateChannelsBatchFilters,
data: BatchChannelDataUpdate,
): Promise<APIResponse & UpdateChannelsBatchResponse> {
return await this.client.updateChannelsBatch({
operation: 'updateData',
filter,
data,
});
}

/**
* addFilterTags - Add filter tags to channels matching the filter
*
* @param {UpdateChannelsBatchFilters} filter Filter to select channels
* @param {string[]} tags Tags to add
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async addFilterTags(
filter: UpdateChannelsBatchFilters,
tags: string[],
): Promise<APIResponse & UpdateChannelsBatchResponse> {
return await this.client.updateChannelsBatch({
operation: 'addFilterTags',
filter,
filter_tags_update: tags,
});
}

/**
* removeFilterTags - Remove filter tags from channels matching the filter
*
* @param {UpdateChannelsBatchFilters} filter Filter to select channels
* @param {string[]} tags Tags to remove
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async removeFilterTags(
filter: UpdateChannelsBatchFilters,
tags: string[],
): Promise<APIResponse & UpdateChannelsBatchResponse> {
return await this.client.updateChannelsBatch({
operation: 'removeFilterTags',
filter,
filter_tags_update: tags,
});
}
}
25 changes: 25 additions & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { CheckSignature, DevToken, JWTUserToken } from './signing';
import { TokenManager } from './token_manager';
import { WSConnectionFallback } from './connection_fallback';
import { Campaign } from './campaign';
import { ChannelBatchUpdater } from './channel_batch_updater';
import { Segment } from './segment';
import { isErrorResponse, isWSFailure } from './errors';
import {
Expand Down Expand Up @@ -209,6 +210,8 @@ import type {
TokenOrProvider,
TranslateResponse,
UnBanUserOptions,
UpdateChannelsBatchOptions,
UpdateChannelsBatchResponse,
UpdateChannelTypeRequest,
UpdateChannelTypeResponse,
UpdateCommandOptions,
Expand Down Expand Up @@ -3746,6 +3749,15 @@ export class StreamChat {
return new Campaign(this, idOrData, data);
}

/**
* channelBatchUpdater - Returns a ChannelBatchUpdater instance for batch channel operations
*
* @return {ChannelBatchUpdater} A ChannelBatchUpdater instance
*/
channelBatchUpdater() {
return new ChannelBatchUpdater(this);
}

segment(type: SegmentType, idOrData: string | SegmentData, data?: SegmentData) {
if (typeof idOrData === 'string') {
return new Segment(this, type, idOrData, data);
Expand Down Expand Up @@ -4792,4 +4804,17 @@ export class StreamChat {
syncDeliveredCandidates(collections: Channel[]) {
this.messageDeliveryReporter.syncDeliveredCandidates(collections);
}

/**
* Update Channels Batch
*
* @param {UpdateChannelsBatchOptions} payload for updating channels in batch
* @return {Promise<APIResponse & UpdateChannelsBatchResponse>} The server response
*/
async updateChannelsBatch(payload: UpdateChannelsBatchOptions) {
return await this.put<APIResponse & UpdateChannelsBatchResponse>(
this.baseURL + `/channels/batch`,
payload,
);
}
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './base64';
export * from './campaign';
export * from './channel_batch_updater';
export * from './client';
export * from './client_state';
export * from './channel';
Expand Down
49 changes: 49 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4495,3 +4495,52 @@ export type EventHook = {
created_at?: string;
updated_at?: string;
};

export type BatchUpdateOperation =
| 'addMembers'
| 'removeMembers'
| 'invites'
| 'assignRoles'
| 'addModerators'
| 'demoteModerators'
| 'hide'
| 'show'
| 'archive'
| 'unarchive'
| 'updateData'
| 'addFilterTags'
| 'removeFilterTags';

export type BatchChannelDataUpdate = {
frozen?: boolean;
disabled?: boolean;
custom?: Record<string, unknown>;
team?: string;
config_overrides?: Record<string, unknown>;
auto_translation_enabled?: boolean;
auto_translation_language?: string;
};

export type UpdateChannelsBatchOptions = {
operation: BatchUpdateOperation;
filter: UpdateChannelsBatchFilters;
members?: string[] | Array<NewMemberPayload>;
data?: BatchChannelDataUpdate;
filter_tags_update?: string[];
};

export type UpdateChannelsBatchFilters = QueryFilters<{
cids?:
| RequireOnlyOne<Pick<QueryFilter<string>, '$in' | '$eq'>>
| PrimitiveFilter<string[]>;
types?:
| RequireOnlyOne<Pick<QueryFilter<string>, '$in' | '$eq'>>
| PrimitiveFilter<string[]>;
filter_tags?:
| RequireOnlyOne<Pick<QueryFilter<string>, '$in' | '$eq'>>
| PrimitiveFilter<Record<string, string>>;
}>;

export type UpdateChannelsBatchResponse = {
result: Record<string, string>;
} & Partial<TaskResponse>;