From fbcf144f81863e020dd70428cc0e3318d9503012 Mon Sep 17 00:00:00 2001 From: ap-atul Date: Tue, 4 Apr 2023 20:39:23 +0530 Subject: [PATCH 1/5] updated comment api | query changes | tests refactored --- .../src/bots/discord/comments/handler.ts | 3 +- apps/discord-bot/src/core/comments/handler.ts | 39 ++++++++++------- apps/discord-bot/src/core/types.ts | 7 +++- apps/discord-bot/src/core/utils/data.ts | 8 +++- apps/discord-bot/tests/data.ts | 14 ++++++- .../tests/functional/comments.spec.ts | 29 ++++++++----- apps/discord-bot/tests/mock/fakes.ts | 42 ++++++++++++------- .../discord-bot/tests/unit/utils/data.spec.ts | 17 +++++++- packages/composedb/Query/query.ts | 19 ++------- 9 files changed, 115 insertions(+), 63 deletions(-) diff --git a/apps/discord-bot/src/bots/discord/comments/handler.ts b/apps/discord-bot/src/bots/discord/comments/handler.ts index 2c5a3111..ab270104 100644 --- a/apps/discord-bot/src/bots/discord/comments/handler.ts +++ b/apps/discord-bot/src/bots/discord/comments/handler.ts @@ -77,5 +77,6 @@ export const postComment = async (client: Client, payload: PostCommentToSocialPa throw new Error("unknown server or thread!"); } - return await thread.send(buildMessage({...payload, body: payload.text})); + const message = await thread.send(buildMessage({...payload, body: payload.text})); + return message.id; }; diff --git a/apps/discord-bot/src/core/comments/handler.ts b/apps/discord-bot/src/core/comments/handler.ts index 34f87ed7..b9820f69 100644 --- a/apps/discord-bot/src/core/comments/handler.ts +++ b/apps/discord-bot/src/core/comments/handler.ts @@ -6,23 +6,32 @@ import {Resp} from "../utils/response"; import {Client} from "discord.js"; import {commentHandler as discordCommentHandler} from "../../bots/discord"; import {logger} from "../utils/logger"; -import {communityHasSocial, getSocialCommunityId} from "../utils/data"; +import {communityHasSocial, getSocialCommunityId, getSocialThreadId} from "../utils/data"; export const postComment = async (clients: Clients, req: Request, res: Response) => { - const {commentId} = req.body; - logger.info('core', {body: req.body}); - const comment: Node = await clients.composeQuery().fetchCommentDetails(commentId); - const socials = _.get(comment, "node.thread.community.socialPlatforms.edges"); + try { + logger.info('core', {body: req.body}); + const {commentId} = req.body; + const comment: Node = await clients.composeQuery().fetchCommentDetails(commentId); + const socials = _.get(comment, "node.thread.community.socialPlatforms.edges"); - if (communityHasSocial(socials, constants.PLATFORM_DISCORD_NAME)) { - postCommentToDiscord(clients.discord, comment); - } else { - return Resp.notOk(res, "No discord for this community, bailing out!"); + if (communityHasSocial(socials, constants.PLATFORM_DISCORD_NAME)) { + const commentId = await postCommentToDiscord(clients.discord, comment); + const response = [{ + platformName: constants.PLATFORM_DISCORD_NAME, + commentId: commentId, + }]; + return Resp.okD(res, response, "Created comment on socials"); + } else { + return Resp.notOk(res, "No discord for this community, bailing out!"); + } + } catch (e) { + logger.error('core', {e, body: req.body}); + return Resp.error(res, "Server error occurred"); } - return Resp.ok(res, "Posted to socials!"); }; -export const postCommentToDiscord = (discordClient: Client, comment: Node) => { +export const postCommentToDiscord = async (discordClient: Client, comment: Node) => { const text = _.get(comment, "node.text"); const socials = _.get(comment, "node.thread.community.socialPlatforms.edges"); const threadStreamId = _.get(comment, "node.threadId"); @@ -31,9 +40,11 @@ export const postCommentToDiscord = (discordClient: Client, comment: Node logger.error('core', {payload, e})); + return await discordCommentHandler.postComment(discordClient, payload) } diff --git a/apps/discord-bot/src/core/types.ts b/apps/discord-bot/src/core/types.ts index a2eb3c1b..f25710d2 100644 --- a/apps/discord-bot/src/core/types.ts +++ b/apps/discord-bot/src/core/types.ts @@ -37,7 +37,7 @@ export interface Thread { title: string; body: string; userId: string; - threadId: string; + socialThreadIds: SocialThreadId[]; createdAt: string; community: Community; communityId: string; @@ -90,3 +90,8 @@ export interface PostThreadToSocialPayload { threadStreamId: string; serverId: string; } + +export interface SocialThreadId { + platformName: string; + threadId: string; +} diff --git a/apps/discord-bot/src/core/utils/data.ts b/apps/discord-bot/src/core/utils/data.ts index 215499ed..587671ac 100644 --- a/apps/discord-bot/src/core/utils/data.ts +++ b/apps/discord-bot/src/core/utils/data.ts @@ -1,4 +1,5 @@ -import {Node, SocialPlatform} from "../types"; +import _ from "lodash"; +import {Node, SocialPlatform, SocialThreadId} from "../types"; export const communityHasSocial = (socials: Node[], platform: string) => { const social = socials.filter((d) => d.node.platform === platform); @@ -9,3 +10,8 @@ export const getSocialCommunityId = (socials: Node[], platform: const social = socials.filter((d) => d.node.platform === platform); return social[0].node.platformId; } + +export const getSocialThreadId = (socials: SocialThreadId[], platformName: string) => { + const id = socials.find((s) => s.platformName === platformName); + return _.get(id,"threadId", ""); +} diff --git a/apps/discord-bot/tests/data.ts b/apps/discord-bot/tests/data.ts index 0c5e1fe1..0d232199 100644 --- a/apps/discord-bot/tests/data.ts +++ b/apps/discord-bot/tests/data.ts @@ -32,7 +32,12 @@ export const sampleComment = { "id": "kjzl6kcym7w8y772zht4omem25y3plfp929wsgumb158oi8uca2fnlhcdri2jqx", "title": "Is storing secrets in redux store secure?", "userId": "k2t6wzhkhabz2wixqd45q1wxpoy9fg7wd2dbfp2vzgq0wd2dq9sh5fkzywjxye", - "threadId": "na", + "socialThreadIds": [ + { + "platformName": "discord", + "threadId": "1092795497066020864" + } + ], "createdAt": "2023-03-15T09:22:45.468Z", "community": { "socialPlatforms": { @@ -86,7 +91,12 @@ export const sampleThread = { "title": "Is storing secrets in redux store secure?", "body": "From the docs, I understand that Redux store variables in memory so it should be readable to the browser, but is it secure enough to store sensitive information?", "userId": "k2t6wzhkhabz2wixqd45q1wxpoy9fg7wd2dbfp2vzgq0wd2dq9sh5fkzywjxye", - "threadId": "na", + "socialThreadIds": [ + { + "platformName": "discord", + "threadId": "1092795497066020864" + } + ], "createdAt": "2023-03-15T09:22:45.468Z", "communityId": "kjzl6kcym7w8y8dgfi093n3o6gby2gwq4fs3nltxjl8gutwvr2ol1sf9vpdmn09", "createdFrom": "devnode", diff --git a/apps/discord-bot/tests/functional/comments.spec.ts b/apps/discord-bot/tests/functional/comments.spec.ts index 38054656..dbbea360 100644 --- a/apps/discord-bot/tests/functional/comments.spec.ts +++ b/apps/discord-bot/tests/functional/comments.spec.ts @@ -1,22 +1,21 @@ import chai, {expect} from "../setup"; import {initServer} from "../../src/core"; -import {Express} from "express"; -import {fakeComposeClient, fakeComposeQueryClient, fakeDiscordClient} from "../mock/fakes"; -import {config} from "../../src/config"; +import {config, constants} from "../../src/config"; +import * as sinon from "sinon"; +import {beforeEach} from "node:test"; +import {fakeComposeClient, fakeComposeQueryClient, fakeDiscordClient, sendStub} from "../mock/fakes"; describe("comment api", () => { - let server: Express; const url = "/api/web-comment"; const header = {'x-api-key': config.server.apiKey}; - - before(() => { - server = initServer({ - discord: fakeDiscordClient, - compose: fakeComposeClient, - composeQuery: fakeComposeQueryClient, - }); + const server = initServer({ + discord: fakeDiscordClient, + compose: fakeComposeClient, + composeQuery: fakeComposeQueryClient, }); + beforeEach(() => sinon.restore()); + it("should authenticate the api call", async () => { const res = await chai.request(server).post(url); expect(res.status).to.eql(401); @@ -32,5 +31,13 @@ describe("comment api", () => { it("should response with 200 on sent message", async () => { const res = await chai.request(server).post(url).set(header).send({commentId: "123"}); expect(res.status).to.eql(200); + expect(sendStub).to.be.callCount(1); + expect(res.body).to.eql({ + msg: "Created comment on socials", + data: [{ + platformName: constants.PLATFORM_DISCORD_NAME, + commentId: 1 + }] + }) }); }); diff --git a/apps/discord-bot/tests/mock/fakes.ts b/apps/discord-bot/tests/mock/fakes.ts index f999a649..835a2689 100644 --- a/apps/discord-bot/tests/mock/fakes.ts +++ b/apps/discord-bot/tests/mock/fakes.ts @@ -3,24 +3,34 @@ import {ComposeClient} from "@composedb/client"; import {sampleComment, sampleThread} from "../data"; import * as sinon from 'sinon'; -export const fakeDiscordClient = { - guilds: { - cache: { - get: () => this, - }, - channels: { - cache: [], - create: sinon.stub().returns( - new Promise((res) => res({ - id: 1, - send: sinon.stub(), - })) - ), - } - } -} as unknown as Client; export const fakeComposeClient = {} as ComposeClient; + export const fakeComposeQueryClient = () => ({ fetchCommentDetails: async (id: string) => sampleComment, fetchThreadDetails: async (id: string) => sampleThread, }) as any; + +export const sendStub = sinon.stub().resolves({id: 1,}); +export const channelStub = { + cache: { + get: sinon.stub().returnsThis(), + send: sendStub, + }, +}; + +export const fakeDiscordClient = { + guilds: { + cache: { + get: sinon.stub().returnsThis(), + send: sendStub, + channels: channelStub, + }, + }, + channels: { + cache: { + get: sinon.stub().returnsThis(), + send: sendStub, + }, + }, + +} as unknown as Client; diff --git a/apps/discord-bot/tests/unit/utils/data.spec.ts b/apps/discord-bot/tests/unit/utils/data.spec.ts index f2c90238..9c376ecd 100644 --- a/apps/discord-bot/tests/unit/utils/data.spec.ts +++ b/apps/discord-bot/tests/unit/utils/data.spec.ts @@ -1,6 +1,6 @@ -import {SocialPlatform, Node} from "../../../src/core/types"; +import {SocialPlatform, Node, SocialThreadId} from "../../../src/core/types"; import {expect} from "../../setup"; -import {communityHasSocial, getSocialCommunityId} from "../../../src/core/utils/data"; +import {communityHasSocial, getSocialCommunityId, getSocialThreadId} from "../../../src/core/utils/data"; describe('utils.data', () => { const socialPlatforms: Node[] = [ @@ -18,6 +18,11 @@ describe('utils.data', () => { }, ]; + const socialThreadIds: SocialThreadId[] = [ + { threadId: "123", platformName: "discord" }, + { threadId: "456", platformName: "discourse" }, + ] + describe('communityHasSocial', () => { it('returns true when the community has the specified social platform', () => { const hasSocial = communityHasSocial(socialPlatforms, 'Discord'); @@ -40,4 +45,12 @@ describe('utils.data', () => { expect(() => getSocialCommunityId(socialPlatforms, 'Instagram')).throw(); }); }); + + describe('getSocialThreadId', () => { + it("returns thread id for matching platform name", () => { + expect(getSocialThreadId(socialThreadIds, "discord")).to.eq("123"); + expect(getSocialThreadId(socialThreadIds, "discourse")).to.eq("456"); + expect(getSocialThreadId(socialThreadIds, "twitter")).to.eq(""); + }); + }); }); diff --git a/packages/composedb/Query/query.ts b/packages/composedb/Query/query.ts index 953ff721..3e75ee10 100644 --- a/packages/composedb/Query/query.ts +++ b/packages/composedb/Query/query.ts @@ -431,7 +431,10 @@ export const composeQueryHandler = () => { id title userId - threadId + socialThreadIds { + platformName + threadId + } createdAt community { socialPlatforms(first: 10) { @@ -448,20 +451,6 @@ export const composeQueryHandler = () => { author { id } - user { - id - walletAddress - author { - id - } - userPlatforms { - platformId - platformName - platformAvatar - platformUsername - } - createdAt - } } author { id From 0625684a5df5b72b544786f61d925de6fae0e303 Mon Sep 17 00:00:00 2001 From: ap-atul Date: Tue, 4 Apr 2023 20:46:16 +0530 Subject: [PATCH 2/5] more test refactors --- apps/discord-bot/.nycrc.json | 8 ++++---- apps/discord-bot/tests/functional/threads.spec.ts | 5 +++++ apps/discord-bot/tests/mock/fakes.ts | 12 +++++------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/discord-bot/.nycrc.json b/apps/discord-bot/.nycrc.json index f636b146..3b4b3a4b 100644 --- a/apps/discord-bot/.nycrc.json +++ b/apps/discord-bot/.nycrc.json @@ -15,8 +15,8 @@ "src/**/types.ts" ], "loader": "ts-node/esm", - "branches": 65, - "lines": 65, - "functions": 65, - "statements": 65 + "branches": 70, + "lines": 70, + "functions": 70, + "statements": 70 } diff --git a/apps/discord-bot/tests/functional/threads.spec.ts b/apps/discord-bot/tests/functional/threads.spec.ts index 767e8be8..81a166fa 100644 --- a/apps/discord-bot/tests/functional/threads.spec.ts +++ b/apps/discord-bot/tests/functional/threads.spec.ts @@ -28,4 +28,9 @@ describe("thread api", () => { const another = await chai.request(server).post(url).set(header).send({threadId: 123}); expect(another.status).to.eql(400); }); + + it("should respond with 200 on thread creation", async () => { + const another = await chai.request(server).post(url).set(header).send({threadId: "123"}); + expect(another.status).to.eql(200); + }); }); diff --git a/apps/discord-bot/tests/mock/fakes.ts b/apps/discord-bot/tests/mock/fakes.ts index 835a2689..1553e76e 100644 --- a/apps/discord-bot/tests/mock/fakes.ts +++ b/apps/discord-bot/tests/mock/fakes.ts @@ -14,6 +14,11 @@ export const sendStub = sinon.stub().resolves({id: 1,}); export const channelStub = { cache: { get: sinon.stub().returnsThis(), + find: sinon.stub().returnsThis(), + threads: { + create: sinon.stub().returnsThis(), + send: sendStub, + }, send: sendStub, }, }; @@ -22,15 +27,8 @@ export const fakeDiscordClient = { guilds: { cache: { get: sinon.stub().returnsThis(), - send: sendStub, channels: channelStub, - }, - }, - channels: { - cache: { - get: sinon.stub().returnsThis(), send: sendStub, }, }, - } as unknown as Client; From 512bbaec8304d4cafe8ce35b8d0aa96cd5004135 Mon Sep 17 00:00:00 2001 From: ap-atul Date: Tue, 4 Apr 2023 20:58:36 +0530 Subject: [PATCH 3/5] added comment update in web --- apps/web/src/server/trpc/router/comment.ts | 24 +++++++++++++++-- apps/web/src/server/types.ts | 5 ++++ packages/composedb/Query/mutation.ts | 30 +++++++++++++++++++++- packages/composedb/Query/type.ts | 5 ++++ 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/apps/web/src/server/trpc/router/comment.ts b/apps/web/src/server/trpc/router/comment.ts index 45d7e5e6..45467e3c 100644 --- a/apps/web/src/server/trpc/router/comment.ts +++ b/apps/web/src/server/trpc/router/comment.ts @@ -6,6 +6,7 @@ import {config} from "../../../config"; import {left, right} from "../../../utils/fp"; import {omit, get} from "lodash"; import {DIDSession} from "did-session"; +import {SocialCommentId} from "../../types"; export const compose = new ComposeClient({ ceramic: config.ceramic.nodeUrl, @@ -38,7 +39,15 @@ export const commentRouter = router({ const response = await handler.createComment(payload as any); if(response.data) { const commentId = get(response.data, "createComment.document.id"); - handleWebToAggregator(commentId); + handleWebToAggregator(commentId) + .then((res) => res.json()) + .then((data) => { + if (has(data, "data[0]")) { + updateComment(handler, commentId, data.data[0]) + .then(console.log) + .catch(console.log); + } + }); } return (response.errors && response.errors.length > 0) ? left(response.errors) @@ -60,9 +69,20 @@ export const commentRouter = router({ }), }); +const updateComment = async (handler, streamId, social: SocialCommentId) => { + try { + const response = await handler.updateCommentWithSocialCommentId(streamId, social); + return response.errors && response.errors.length > 0 + ? left(response.errors) + : right(response.data); + } catch (e) { + return left(e); + } +} + const handleWebToAggregator = async (commentId: string) => { const endpoint = `${config.aggregator.endpoint}/web-comment`; - await fetch(endpoint, { + return await fetch(endpoint, { body: JSON.stringify({ commentId: commentId, }), diff --git a/apps/web/src/server/types.ts b/apps/web/src/server/types.ts index 4caa74c0..5edf2235 100644 --- a/apps/web/src/server/types.ts +++ b/apps/web/src/server/types.ts @@ -61,3 +61,8 @@ export interface SocialThreadId { platformName: string; threadId: string; } + +export interface SocialCommentId { + platformName: string; + commentId: string; +} diff --git a/packages/composedb/Query/mutation.ts b/packages/composedb/Query/mutation.ts index e770b25a..b08bdf9d 100644 --- a/packages/composedb/Query/mutation.ts +++ b/packages/composedb/Query/mutation.ts @@ -2,7 +2,9 @@ import { ComposeClient } from "@composedb/client"; import { CommentInput, CommunityDetails, - SocialPlatformInput, SocialThreadId, + SocialCommentId, + SocialPlatformInput, + SocialThreadId, ThreadInput, UserCommunityRelation, UserPlatformDetails, @@ -299,5 +301,31 @@ export const composeMutationHandler = async (compose: ComposeClient) => { }, }); }, + updateCommentWithSocialCommentId: async function ( + streamId: string, + socialCommentId: SocialCommentId, + ) { + const query = gql` + mutation UpdateComment($input: UpdateCommentInput!) { + updateComment(input: $input) { + document { + id + socialCommentIds { + commentId + platformName + } + } + } + } + `; + return await compose.executeQuery(query, { + input: { + id: streamId, + content: { + socialCommentIds: socialCommentId + }, + }, + }); + }, }; }; diff --git a/packages/composedb/Query/type.ts b/packages/composedb/Query/type.ts index 5c92fcc6..3dce13fd 100644 --- a/packages/composedb/Query/type.ts +++ b/packages/composedb/Query/type.ts @@ -121,6 +121,11 @@ export interface SocialThreadId { threadId: string; } +export interface SocialCommentId { + platformName: string; + commentId: string; +} + export interface UserFeedResponse { community: { threads: Edges; From b3f3b4ae892c645683b6f297edaef8d0fcea6fe4 Mon Sep 17 00:00:00 2001 From: ap-atul Date: Tue, 4 Apr 2023 21:04:16 +0530 Subject: [PATCH 4/5] minor updates --- .../tests/functional/comments.spec.ts | 1 - .../discord-bot/tests/functional/threads.spec.ts | 16 +++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/apps/discord-bot/tests/functional/comments.spec.ts b/apps/discord-bot/tests/functional/comments.spec.ts index dbbea360..69813a4f 100644 --- a/apps/discord-bot/tests/functional/comments.spec.ts +++ b/apps/discord-bot/tests/functional/comments.spec.ts @@ -2,7 +2,6 @@ import chai, {expect} from "../setup"; import {initServer} from "../../src/core"; import {config, constants} from "../../src/config"; import * as sinon from "sinon"; -import {beforeEach} from "node:test"; import {fakeComposeClient, fakeComposeQueryClient, fakeDiscordClient, sendStub} from "../mock/fakes"; describe("comment api", () => { diff --git a/apps/discord-bot/tests/functional/threads.spec.ts b/apps/discord-bot/tests/functional/threads.spec.ts index 81a166fa..9da50412 100644 --- a/apps/discord-bot/tests/functional/threads.spec.ts +++ b/apps/discord-bot/tests/functional/threads.spec.ts @@ -1,22 +1,20 @@ import chai, {expect} from "../setup"; import {initServer} from "../../src/core"; -import {Express} from "express"; +import * as sinon from "sinon"; import {fakeComposeClient, fakeComposeQueryClient, fakeDiscordClient} from "../mock/fakes"; import {config} from "../../src/config"; describe("thread api", () => { - let server: Express; const url = "/api/web-thread"; const header = {'x-api-key': config.server.apiKey}; - - before(() => { - server = initServer({ - discord: fakeDiscordClient, - compose: fakeComposeClient, - composeQuery: fakeComposeQueryClient, - }); + const server = initServer({ + discord: fakeDiscordClient, + compose: fakeComposeClient, + composeQuery: fakeComposeQueryClient, }); + beforeEach(() => sinon.restore()); + it("should authenticate the api call", async () => { const res = await chai.request(server).post(url); expect(res.status).to.eql(401); From a5683959144c65dd85698c3e7a07fc3d7287f6c2 Mon Sep 17 00:00:00 2001 From: ap-atul Date: Tue, 4 Apr 2023 21:08:48 +0530 Subject: [PATCH 5/5] fixed missing import --- apps/web/src/server/trpc/router/comment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/server/trpc/router/comment.ts b/apps/web/src/server/trpc/router/comment.ts index 45467e3c..69e65002 100644 --- a/apps/web/src/server/trpc/router/comment.ts +++ b/apps/web/src/server/trpc/router/comment.ts @@ -4,7 +4,7 @@ import {definition, composeMutationHandler, composeQueryHandler } from "@devnode import {ComposeClient} from "@composedb/client"; import {config} from "../../../config"; import {left, right} from "../../../utils/fp"; -import {omit, get} from "lodash"; +import {has, omit, get} from "lodash"; import {DIDSession} from "did-session"; import {SocialCommentId} from "../../types";