Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

discard reserved fields from channel.Update() channelData #439

Merged
merged 7 commits into from
Sep 24, 2020
Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
/node_modules
/ts-test
/test
*.md
*.md
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ typings/
.tern-port

/.vscode
/.idea

ts-test/data.js
ts-test/data.ts

1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
/node_modules
/.vscode
/types
/ts-test/data.ts
23 changes: 22 additions & 1 deletion src/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -479,9 +479,30 @@ export class Channel<
* @return {Promise<UpdateChannelAPIResponse<AttachmentType, ChannelType, CommandType, MessageType, ReactionType, UserType>>} The server response
*/
async update(
channelData: ChannelData<ChannelType>,
channelData:
| Partial<ChannelData<ChannelType>>
| Partial<ChannelResponse<ChannelType, CommandType, UserType>>
| Partial<
Immutable.Immutable<ChannelResponse<ChannelType, CommandType, UserType>>
> = {},
updateMessage?: Message<AttachmentType, MessageType, UserType>,
) {
// Strip out reserved names that will result in API errors.
const reserved = [
'config',
'cid',
'created_by',
'id',
'member_count',
'type',
'created_at',
'updated_at',
'last_message_at',
];
reserved.forEach(key => {
delete channelData[key];
});

const data = await this.getClient().post<
UpdateChannelAPIResponse<
AttachmentType,
Expand Down
45 changes: 36 additions & 9 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1375,14 +1375,39 @@ export class StreamChat<
* ie. client.channel("messaging", {members: ["tommaso", "thierry"]})
*
* @param {string} channelType The channel type
* @param {string} channelID The channel ID, you can leave this out if you want to create a conversation channel
* @param {string | ChannelData<ChannelType> | null} [channelIDOrCustom] The channel ID, you can leave this out if you want to create a conversation channel
* @param {object} [custom] Custom data to attach to the channel
*
* @return {channel} The channel object, initialize it using channel.watch()
*/
channel(
channelType: string,
channelID: string,
channelID?: string | null,
custom?: ChannelData<ChannelType>,
): Channel<
AttachmentType,
ChannelType,
CommandType,
EventType,
MessageType,
ReactionType,
UserType
>;
channel(
channelType: string,
custom?: ChannelData<ChannelType>,
): Channel<
AttachmentType,
ChannelType,
CommandType,
EventType,
MessageType,
ReactionType,
UserType
>;
channel(
channelType: string,
channelIDOrCustom?: string | ChannelData<ChannelType> | null,
custom: ChannelData<ChannelType> = {} as ChannelData<ChannelType>,
) {
if (!this.userID && !this._isUsingServerAuth()) {
Expand All @@ -1396,7 +1421,7 @@ export class StreamChat<
// support channel("messaging", null, {options})
// support channel("messaging", undefined, {options})
// support channel("messaging", "", {options})
if (channelID == null || channelID === '') {
if (channelIDOrCustom == null || channelIDOrCustom === '') {
return new Channel<
AttachmentType,
ChannelType,
Expand All @@ -1408,7 +1433,7 @@ export class StreamChat<
>(this, channelType, undefined, custom);
}
// support channel("messaging", {options})
if (typeof channelID === 'object' && arguments.length === 2) {
if (typeof channelIDOrCustom === 'object') {
return new Channel<
AttachmentType,
ChannelType,
Expand All @@ -1417,15 +1442,17 @@ export class StreamChat<
MessageType,
ReactionType,
UserType
>(this, channelType, undefined, channelID);
>(this, channelType, undefined, channelIDOrCustom);
}

if (typeof channelID === 'string' && ~channelID.indexOf(':')) {
throw Error(`Invalid channel id ${channelID}, can't contain the : character`);
if (typeof channelIDOrCustom === 'string' && ~channelIDOrCustom.indexOf(':')) {
throw Error(
`Invalid channel id ${channelIDOrCustom}, can't contain the : character`,
);
}

// only allow 1 channel object per cid
const cid = `${channelType}:${channelID}`;
const cid = `${channelType}:${channelIDOrCustom}`;
if (cid in this.activeChannels) {
const channel = this.activeChannels[cid];
if (Object.keys(custom).length > 0) {
Expand All @@ -1442,7 +1469,7 @@ export class StreamChat<
MessageType,
ReactionType,
UserType
>(this, channelType, channelID, custom);
>(this, channelType, channelIDOrCustom, custom);
this.activeChannels[channel.cid] = channel;

return channel;
Expand Down
64 changes: 47 additions & 17 deletions test/channels.js
Original file line number Diff line number Diff line change
Expand Up @@ -875,26 +875,26 @@ describe('Query Channels and sort by unread', function() {
expect(result[3].cid).to.be.equal(channels[3].cid);

/*result = await tommasoClient.queryChannels(
{ members: { $in: [tommaso] } },
{ unread_count: 1, last_message_at: -1 },
);
{ members: { $in: [tommaso] } },
{ unread_count: 1, last_message_at: -1 },
);

expect(result.length).to.be.equal(4);
expect(result[0].cid).to.be.equal(channels[3].cid);
expect(result[1].cid).to.be.equal(channels[2].cid);
expect(result[2].cid).to.be.equal(channels[1].cid);
expect(result[3].cid).to.be.equal(channels[0].cid);
expect(result.length).to.be.equal(4);
expect(result[0].cid).to.be.equal(channels[3].cid);
expect(result[1].cid).to.be.equal(channels[2].cid);
expect(result[2].cid).to.be.equal(channels[1].cid);
expect(result[3].cid).to.be.equal(channels[0].cid);

result = await tommasoClient.queryChannels(
{ members: { $in: [tommaso] } },
{ unread_count: 1, last_message_at: 1 },
);
result = await tommasoClient.queryChannels(
{ members: { $in: [tommaso] } },
{ unread_count: 1, last_message_at: 1 },
);

expect(result.length).to.be.equal(4);
expect(result[0].cid).to.be.equal(channels[2].cid);
expect(result[1].cid).to.be.equal(channels[3].cid);
expect(result[2].cid).to.be.equal(channels[0].cid);
expect(result[3].cid).to.be.equal(channels[1].cid);*/
expect(result.length).to.be.equal(4);
expect(result[0].cid).to.be.equal(channels[2].cid);
expect(result[1].cid).to.be.equal(channels[3].cid);
expect(result[2].cid).to.be.equal(channels[0].cid);
expect(result[3].cid).to.be.equal(channels[1].cid);*/
});

it('limit results should work fine', async function() {
Expand Down Expand Up @@ -1972,3 +1972,33 @@ describe('pagination with invalid offset', function() {
expect(result.messages.length).to.be.equal(0);
});
});

describe('update channel with reserved fields', function() {
const user = uuidv4();
const channelType = uuidv4();
const channelId = uuidv4();
let channel;
let client;
before(async function() {
client = await getServerTestClient();

await client.createChannelType({
name: channelType,
commands: ['giphy'],
});

channel = client.channel(channelType, channelId, {
members: [user],
created_by_id: user,
});
await channel.watch();
});

it('should not fail when re-using channel.data', async function() {
await channel.update(channel.data);
});

it('should not fail when re-using channel._data', async function() {
await channel.update(channel._data);
});
});
8 changes: 7 additions & 1 deletion ts-test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,13 @@ const executables = [
f: rg.updateChannel,
imports: ['Channel', 'Unpacked'],
type:
"Unpacked<ReturnType<Channel<{ description?: string }, { description?: string }, string & {}, {}, {}, {}, {}>['update']>>",
"Unpacked<ReturnType<Channel<{}, { description: string }, string & {}, {}, {}, {}, {}>['update']>>",
},
{
f: rg.updateChannelFromOriginal,
imports: ['Channel', 'Unpacked'],
type:
"Unpacked<ReturnType<Channel<{}, { description: string; smallTitle: string }, string & {}, {}, {}, {}, {}>['update']>>",
},
{
f: rg.updateChannelType,
Expand Down
15 changes: 15 additions & 0 deletions ts-test/response-generators/channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,20 @@ async function updateChannel() {
});
}

async function updateChannelFromOriginal() {
const channel = await utils.createTestChannelForUser(uuidv4(), johnID);
await channel.watch();
await channel.update({
...channel.data,
frozen: true,
description: 'Updating original data',
});
return await channel.update({
...channel.data,
smallTitle: 'Updating original data too/two',
});
}

async function updateChannelType() {
const authClient = await utils.getTestClient(true);
return await authClient.updateChannelType('messaging', { uploads: true });
Expand Down Expand Up @@ -252,6 +266,7 @@ module.exports = {
truncateChannel,
unmute,
updateChannel,
updateChannelFromOriginal,
updateChannelType,
watch,
};
20 changes: 20 additions & 0 deletions ts-test/unit-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,26 @@ client.queryChannels({
},
});

const testChannelUpdate = channel.update({
...channel._data,
name: 'helloWorld',
color: 'yellow',
});

const testChannelUpdate2 = channel.update({
...channel.data,
name: 'helloWorld2',
color: 'yellow',
});

// Good
const testChannel1 = client.channel('hello', { color: 'red' });
const testChannel2 = client.channel('hello2', 'myId', { color: 'green' });
const testChannel3 = client.channel('hello3');
const testChannel4 = client.channel('hello4', undefined, { color: 'red ' });
// Bad
// const testChannel5 = client.channel('hello3', { color: 'newColor' }, { color: 'green' });

// TODO: Fix this
// channel.queryMembers({
// $or: [
Expand Down