Skip to content

Commit 48da325

Browse files
committed
feat: add update-subscription writer
1 parent fb49cc2 commit 48da325

File tree

3 files changed

+137
-0
lines changed

3 files changed

+137
-0
lines changed

src/writer/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import * as subscribe from './subscribe';
1212
import * as unfollow from './unfollow';
1313
import * as unsubscribe from './unsubscribe';
1414
import * as updateProposal from './update-proposal';
15+
import * as updateSubscription from './update-subscription';
1516
import * as vote from './vote';
1617

1718
export default {
@@ -26,6 +27,7 @@ export default {
2627
unfollow,
2728
subscribe,
2829
unsubscribe,
30+
'update-subscription': updateSubscription,
2931
'delete-subscription': deleteSubscription,
3032
alias,
3133
profile,

src/writer/update-subscription.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { envelopDB } from '../helpers/mysql';
2+
import { jsonParse } from '../helpers/utils';
3+
4+
type Message = { msg: string; address: string };
5+
type Payload = {
6+
type: string;
7+
value: string;
8+
metadata: { subscriptions: string[] };
9+
};
10+
11+
const VALID_SUBSCRIPTIONS = ['summary', 'newProposal', 'closedProposal'];
12+
13+
function extractPayload(message: Message): Payload {
14+
const payload = jsonParse(message.msg).payload;
15+
16+
return {
17+
...payload,
18+
metadata: jsonParse(payload.metadata)
19+
};
20+
}
21+
22+
export async function verify(message: Message): Promise<any> {
23+
const result = await envelopDB.queryAsync(`SELECT * FROM subscribers WHERE address = ? LIMIT 1`, [
24+
message.address
25+
]);
26+
27+
if (!result[0]) {
28+
return Promise.reject('user not subscribed');
29+
}
30+
31+
if (!result[0].verified) {
32+
return Promise.reject('email not verified');
33+
}
34+
35+
const {
36+
metadata: { subscriptions }
37+
} = extractPayload(message);
38+
if ((subscriptions || []).some(s => !VALID_SUBSCRIPTIONS.includes(s))) {
39+
return Promise.reject('invalid subscription value');
40+
}
41+
42+
return result[0];
43+
}
44+
45+
export async function action(message: Message): Promise<void> {
46+
const {
47+
metadata: { subscriptions }
48+
} = extractPayload(message);
49+
50+
await envelopDB.queryAsync(
51+
`UPDATE subscribers SET subscriptions = ? WHERE address = ? AND verified > 0 LIMIT 1`,
52+
[JSON.stringify(subscriptions), message.address]
53+
);
54+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import db, { envelopDB, sequencerDB } from '../../../src/helpers/mysql';
2+
import { action, verify } from '../../../src/writer/update-subscription';
3+
4+
describe('writer/update-subscription', () => {
5+
const TEST_PREFIX = 'test-update-subscription';
6+
7+
afterAll(async () => {
8+
await envelopDB.queryAsync('DELETE FROM subscribers');
9+
await envelopDB.endAsync();
10+
await db.endAsync();
11+
await sequencerDB.endAsync();
12+
});
13+
14+
describe('verify()', () => {
15+
const msg = JSON.stringify({ payload: { subscriptions: ['closedProposal'] } });
16+
const msgWithInvalidSubscriptions = JSON.stringify({
17+
payload: { subscriptions: ['test'] }
18+
});
19+
20+
beforeAll(async () => {
21+
await Promise.all([
22+
envelopDB.queryAsync(
23+
'INSERT INTO subscribers SET address = ?, email = ?, subscriptions = ?, created = ?, verified = ?',
24+
[`${TEST_PREFIX}-0x0`, '[email protected]', '[]', 0, 0]
25+
),
26+
envelopDB.queryAsync(
27+
'INSERT INTO subscribers SET address = ?, email = ?, subscriptions = ?, created = ?, verified = ?',
28+
[`${TEST_PREFIX}-0x1`, '[email protected]', '[]', 0, 1]
29+
)
30+
]);
31+
});
32+
33+
it('rejects when the address is not subscribed', () => {
34+
return expect(verify({ address: '0x0', msg })).rejects.toEqual(`user not subscribed`);
35+
});
36+
37+
it('rejects when the address is not verified', () => {
38+
return expect(verify({ address: `${TEST_PREFIX}-0x0`, msg })).rejects.toEqual(
39+
`email not verified`
40+
);
41+
});
42+
43+
it('rejects when subscription values are not valid', () => {
44+
return expect(
45+
verify({ address: `${TEST_PREFIX}-0x1`, msg: msgWithInvalidSubscriptions })
46+
).rejects.toEqual(`invalid subscription value`);
47+
});
48+
49+
it('resolves when all args are valid', () => {
50+
return expect(verify({ address: `${TEST_PREFIX}-0x1`, msg })).resolves.toHaveProperty(
51+
'address'
52+
);
53+
});
54+
});
55+
56+
describe('action()', () => {
57+
const address = `${TEST_PREFIX}-0x3`;
58+
const subscriptions = ['newProposal', 'closedProposal'];
59+
60+
beforeAll(async () => {
61+
await envelopDB.queryAsync(
62+
'INSERT INTO subscribers SET address = ?, email = ?, subscriptions = ?, created = ?, verified = ?',
63+
[address, '[email protected]', '["summary"]', 0, 1]
64+
);
65+
});
66+
67+
it('updates the subscription', async () => {
68+
await action({
69+
address: address,
70+
msg: JSON.stringify({ payload: { subscriptions } })
71+
});
72+
73+
const result = await envelopDB.queryAsync(
74+
`SELECT subscriptions FROM subscribers WHERE address = ? LIMIT 1`,
75+
[address]
76+
);
77+
78+
expect(JSON.parse(result[0].subscriptions)).toEqual(subscriptions);
79+
});
80+
});
81+
});

0 commit comments

Comments
 (0)