From 35daddf6813e9fcba867622816db7af8cad6d979 Mon Sep 17 00:00:00 2001 From: rushikesh dhanwant Date: Thu, 15 Dec 2022 14:59:44 +0530 Subject: [PATCH 01/11] setup express server | created api to add web comment/threads to discord --- apps/discord-bot/package.json | 6 +++- apps/discord-bot/src/index.ts | 37 ++++++++++++++++++++++ apps/discord-bot/src/type.ts | 4 +++ yarn.lock | 59 ++++++++++++++++++++++++++++++++++- 4 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 apps/discord-bot/src/type.ts diff --git a/apps/discord-bot/package.json b/apps/discord-bot/package.json index ec7c2546..b2870283 100644 --- a/apps/discord-bot/package.json +++ b/apps/discord-bot/package.json @@ -24,11 +24,15 @@ "@devnode/composedb": "*", "@devnode/database": "*", "@stablelib/random": "^1.0.2", + "@types/cors": "^2.8.13", + "@types/express": "^4.17.14", "@types/node": "^18.11.0", + "cors": "^2.8.5", "cross-fetch": "^3.1.5", "did-session": "^1.0.0", "discord.js": "^14.6.0", - "dotenv": "^16.0.3" + "dotenv": "^16.0.3", + "express": "^4.18.2" }, "devDependencies": { "@composedb/types": "^0.3.0", diff --git a/apps/discord-bot/src/index.ts b/apps/discord-bot/src/index.ts index 31278ff6..22743432 100644 --- a/apps/discord-bot/src/index.ts +++ b/apps/discord-bot/src/index.ts @@ -14,10 +14,20 @@ import { onInvoke } from "./handlers/onInvoke"; import { onMessageCreate } from "./handlers/onMessageCreate"; import { onStart } from "./handlers/onStart"; import { onThreadCreate } from "./handlers/onThreadCreate"; +import { onCommentCreateWeb } from "./handlers/onCommentCreateWeb"; +import { onThredCreateWeb } from "./handlers/onThreadCreateWeb"; import fetch from "cross-fetch"; import { prisma } from "@devnode/database"; +import express, { response } from 'express'; +import cors from 'cors'; + +const app = express(); +app.use(cors()); +app.use(express.json()); +const port = 4000 + const INVOCATION_STRING = "devnode"; const INVOCATION_CHANNEL = "devnode_signin"; @@ -96,4 +106,31 @@ client.on("threadCreate", async (thread) => { onThreadCreate(thread); }); + +// apis + +app.post('/webcomment', async (req, res) => { + const { threadId, comment, discordUserName } = req.body; + console.log({thredId:threadId, comment:comment}) + const response = await onCommentCreateWeb(client, threadId, comment, discordUserName); + if(response.result){ + res.status(400).send(response); + } + res.status(200).send(response); + +}) + +app.post('/webThread', async (req, res) => { + const { threadTitle, community, discordUserName} = req.body; + console.log({threadTitle:threadTitle}) + const response = await onThredCreateWeb(client, threadTitle, community, discordUserName); + if(response.result){ + res.status(400).send(response.value); + } + res.status(200).send(response.value); +}) + +app.listen(port, () => { + console.log(`server listening on port ${port}`) +}) export {}; diff --git a/apps/discord-bot/src/type.ts b/apps/discord-bot/src/type.ts new file mode 100644 index 00000000..e79cc4fc --- /dev/null +++ b/apps/discord-bot/src/type.ts @@ -0,0 +1,4 @@ +export type Response = { + result: string, + value: string | object +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index d7e342e2..3f044b71 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2619,6 +2619,14 @@ dependencies: "@types/node" "*" +"@types/body-parser@*": + version "1.19.2" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" + integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + "@types/bs58check@^2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@types/bs58check/-/bs58check-2.1.0.tgz#7d25a8b88fe7a9e315d2647335ee3c43c8fdb0c0" @@ -2636,13 +2644,20 @@ "@types/node" "*" "@types/responselike" "^1.0.0" -"@types/connect@^3.4.33": +"@types/connect@*", "@types/connect@^3.4.33": version "3.4.35" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== dependencies: "@types/node" "*" +"@types/cors@^2.8.13": + version "2.8.13" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94" + integrity sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA== + dependencies: + "@types/node" "*" + "@types/cross-spawn@6.0.2": version "6.0.2" resolved "https://registry.yarnpkg.com/@types/cross-spawn/-/cross-spawn-6.0.2.tgz#168309de311cd30a2b8ae720de6475c2fbf33ac7" @@ -2657,6 +2672,25 @@ dependencies: "@types/ms" "*" +"@types/express-serve-static-core@^4.17.18": + version "4.17.31" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz#a1139efeab4e7323834bb0226e62ac019f474b2f" + integrity sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@^4.17.14": + version "4.17.14" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.14.tgz#143ea0557249bc1b3b54f15db4c81c3d4eb3569c" + integrity sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.18" + "@types/qs" "*" + "@types/serve-static" "*" + "@types/http-cache-semantics@*": version "4.0.1" resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812" @@ -2684,6 +2718,11 @@ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== +"@types/mime@*": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" + integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== + "@types/minimatch@^3.0.4": version "3.0.5" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" @@ -2731,6 +2770,16 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + "@types/react-dom@^18.0.5": version "18.0.9" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.9.tgz#ffee5e4bfc2a2f8774b15496474f8e7fe8d0b504" @@ -2781,6 +2830,14 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== +"@types/serve-static@*": + version "1.15.0" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.0.tgz#c7930ff61afb334e121a9da780aac0d9b8f34155" + integrity sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg== + dependencies: + "@types/mime" "*" + "@types/node" "*" + "@types/ws@^7.4.4": version "7.4.7" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" From dced498cdb0def31db1239dcfe7d48bb2ff01141 Mon Sep 17 00:00:00 2001 From: rushikesh dhanwant Date: Thu, 15 Dec 2022 15:05:23 +0530 Subject: [PATCH 02/11] handler to for sending Web comments to discord --- .../src/handlers/onCommentCreateWeb.ts | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 apps/discord-bot/src/handlers/onCommentCreateWeb.ts diff --git a/apps/discord-bot/src/handlers/onCommentCreateWeb.ts b/apps/discord-bot/src/handlers/onCommentCreateWeb.ts new file mode 100644 index 00000000..73fdbc7a --- /dev/null +++ b/apps/discord-bot/src/handlers/onCommentCreateWeb.ts @@ -0,0 +1,84 @@ +import { config } from "dotenv"; +config(); +import { ChannelType, Client, TextChannel, ThreadChannel } from "discord.js"; +import { prisma } from "@devnode/database"; +import { DIDSession } from "did-session"; +import { Response } from "../type" +import { ComposeClient } from "@composedb/client"; +import { definition } from "@devnode/composedb"; +import { + DISCORD_DO_NOT_CREATE_THREADS_IF_NOT_SIGNED, + DISCORD_LOST_SESSION, +} from "../consts/replyMessages"; + +export const compose = new ComposeClient({ + ceramic: String(process.env.CERAMIC_NODE), + definition, +}); + +export const onCommentCreateWeb = async (client:Client, threadId:string, comment:string, discordUserName:string):Promise => { + + const existhreaingThread = await prisma.thread.findUnique({ + where: { + streamId: threadId, + }, + }).catch((e)=>{ + console.log(e); + }); + + const user = await prisma.user + .findUniqueOrThrow({ + where: { + discordUsername: discordUserName, + }, + select: { + didSession: true, + }, + }) + + if (user == null || !user.didSession) { + return {result: 'false', value:'user not signed in from discord or did session has expired'}; + } + + if(existhreaingThread){ + + const thread = client.channels.cache.get(existhreaingThread?.discordId) as ThreadChannel; + const message = await thread.send(`From WEB \n ${discordUserName} : ${comment}`); + + const session = await DIDSession.fromSession(user.didSession); + compose.setDID(session.did); + + try{ + await compose + .executeQuery<{ + createComment: { document: { id: string } }; + }>( + `mutation CreateComment($input: CreateCommentInput!) { + createComment(input: $input) { + document { + id + threadID + text + createdAt + } + } + }`, + { + input: { + content: { + threadID: threadId, + text: comment, + createdAt: new Date().toISOString(), + }, + }, + } + ) + } + catch{ + message.delete(); + return {result: 'false', value:'compose failed'}; + } + } + + return {result: 'true', value:'comment added'}; +}; From c7a1b528f926e0144c98dd1177f997183057d197 Mon Sep 17 00:00:00 2001 From: rushikesh dhanwant Date: Thu, 15 Dec 2022 15:06:13 +0530 Subject: [PATCH 03/11] handler to for sending Web Thread to discord --- .../src/handlers/onThreadCreateWeb.ts | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 apps/discord-bot/src/handlers/onThreadCreateWeb.ts diff --git a/apps/discord-bot/src/handlers/onThreadCreateWeb.ts b/apps/discord-bot/src/handlers/onThreadCreateWeb.ts new file mode 100644 index 00000000..06004874 --- /dev/null +++ b/apps/discord-bot/src/handlers/onThreadCreateWeb.ts @@ -0,0 +1,110 @@ +import { config } from "dotenv"; +config(); +import { ChannelType, Client, TextChannel, ThreadChannel } from "discord.js"; +import { prisma } from "@devnode/database"; +import { DIDSession } from "did-session"; +import { ComposeClient } from "@composedb/client"; +import { definition } from "@devnode/composedb"; +import { Response } from "../type" +export const compose = new ComposeClient({ + ceramic: String(process.env.CERAMIC_NODE), + definition, +}); + +export const onThredCreateWeb = async (client:Client, threadTitle:string, community:string, discordUserName:string):Promise => { + + let devnodeChannel = client.channels.cache + .filter( + (channel) => + channel.type == ChannelType.GuildText && + channel.name == process.env.DISCORD_CHANNEL_NAME + ) + .first() as TextChannel; + + + const user = await prisma.user + .findUniqueOrThrow({ + where: { + discordUsername: discordUserName + }, + select: { + didSession: true, + }, + }) + + if (user == null || !user.didSession) { + return {result: 'false', value:'user not signed in from discord or did session has expired'}; + } + + let thread:ThreadChannel; + + try{ + thread = await devnodeChannel.threads.create({ + name: threadTitle , + reason: 'Created in Web', + }); + } + catch{ + return {result: 'false', value:'could not create thread'}; + } + + const session = await DIDSession.fromSession(user.didSession); + compose.setDID(session.did); + + let composeResponse; + try{ + composeResponse = await compose + .executeQuery<{ + createThread: { document: { id: string } }; + }>( + `mutation CreateThread($input: CreateThreadInput!) { + createThread(input: $input) { + document { + id + community + title + createdAt + } + } + }`, + { + input: { + content: { + community: thread.guild.id, + title: String(thread.name), + createdAt: thread.createdAt?.toISOString(), + }, + }, + } + ) + } + catch{ + await thread.delete(); + return {result:'false', value:'composedb failed'}; + } + + if (!composeResponse || !composeResponse.data) { + await thread.delete(); + return {result:'false', value:'composedb failed'}; + } + + await prisma.thread.upsert({ + where: { discordId: thread.id }, + update: { + createdAt: thread.createdAt!, + discordAuthor: discordUserName, + discordCommunity: thread.guild.id, + title: String(thread.name), + }, + create: { + discordId: thread.id, + streamId: composeResponse.data.createThread.document.id, + createdAt: thread.createdAt!, + discordAuthor: discordUserName, + discordCommunity: thread.guild.id, + title: String(thread.name), + }, + }); + + return {result:'true', value:'thread added'}; +}; From f1f93ddfaa705e1c49b8dc2ea68ae5c8af72417a Mon Sep 17 00:00:00 2001 From: rushikesh dhanwant Date: Thu, 15 Dec 2022 15:27:48 +0530 Subject: [PATCH 04/11] integrated api to add web threads to discord --- .env.template | 1 + apps/web/src/components/Thread/NewThread.tsx | 58 +++++++------------- 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/.env.template b/.env.template index 8d74936a..c82d6992 100644 --- a/.env.template +++ b/.env.template @@ -4,6 +4,7 @@ DISCORD_CHANNEL_NAME=devnode #Local MYSQL_URL=mysql://root:testpassword@localhost/devnode NEXTAUTH_URL=http://localhost:3000/ +DISCORD_BOT_URL=http://localhost:4000/ #Staging DISCORD_TOKEN= diff --git a/apps/web/src/components/Thread/NewThread.tsx b/apps/web/src/components/Thread/NewThread.tsx index 9c840483..ba8125f1 100644 --- a/apps/web/src/components/Thread/NewThread.tsx +++ b/apps/web/src/components/Thread/NewThread.tsx @@ -1,15 +1,9 @@ -import { ComposeClient } from "@composedb/client"; -import { definition } from "@devnode/composedb"; import { DIDSession } from "did-session"; import { useEffect, useState } from "react"; import { useAccount } from "wagmi"; import useLocalStorage from "../../hooks/useLocalStorage"; import { trpc } from "../../utils/trpc"; -export const compose = new ComposeClient({ - ceramic: String(process.env.NEXT_PUBLIC_CERAMIC_NODE), - definition, -}); const NewThread = (props: { refresh: () => void }) => { const { isConnected } = useAccount(); @@ -20,7 +14,7 @@ const NewThread = (props: { refresh: () => void }) => { const allCommunities = trpc.public.getAllCommunities.useQuery(); const [thread, setThread] = useState(""); - + useEffect(() => { const getData = async () => { if (!didSession || !isConnected) return; @@ -30,38 +24,26 @@ const NewThread = (props: { refresh: () => void }) => { getData(); }, [didSession, isConnected]); + const authorDiscord = trpc.public.getDiscordUser.useQuery({ + didSession: didSession + }); + + const discordUserName = authorDiscord.data?.discordUsername ?? "Anonymous"; + const onThreadSumbit = async () => { - const session = await DIDSession.fromSession(didSession); - compose.setDID(session.did); - await compose - .executeQuery<{ - createThread: { document: { id: string } }; - }>( - `mutation CreateThread($input: CreateThreadInput!) { - createThread(input: $input) { - document { - id - title - community - createdAt - } - } - }`, - { - input: { - content: { - title: String(thread), - community: community, - createdAt: new Date().toISOString(), - }, - }, - } - ) - .then((r) => { - props.refresh(); - console.log(r); - }) - .catch((e) => console.log(e)); + + await fetch(`${String(process.env.DISCORD_BOT_URL)}webThread`, + { + body:JSON.stringify({ + community:String(community), + threadTitle: String(thread), + discordUserName: String(discordUserName) + }), + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + }) }; return isConnected && didSession ? ( From 421b4cc59c38c7658f7c04f1ed2abbc3ea703a05 Mon Sep 17 00:00:00 2001 From: rushikesh dhanwant Date: Thu, 15 Dec 2022 15:28:21 +0530 Subject: [PATCH 05/11] integrated api to add web comments to discord --- apps/discord-bot/src/index.ts | 8 ++- .../components/ThreadCard/CommentInput.tsx | 55 +++++++------------ apps/web/src/server/trpc/router/public.ts | 12 ++++ 3 files changed, 38 insertions(+), 37 deletions(-) diff --git a/apps/discord-bot/src/index.ts b/apps/discord-bot/src/index.ts index 22743432..133fbdb9 100644 --- a/apps/discord-bot/src/index.ts +++ b/apps/discord-bot/src/index.ts @@ -116,7 +116,9 @@ app.post('/webcomment', async (req, res) => { if(response.result){ res.status(400).send(response); } - res.status(200).send(response); + else{ + res.status(200).send(response.value); + } }) @@ -127,7 +129,9 @@ app.post('/webThread', async (req, res) => { if(response.result){ res.status(400).send(response.value); } - res.status(200).send(response.value); + else{ + res.status(200).send(response.value); + } }) app.listen(port, () => { diff --git a/apps/web/src/components/ThreadCard/CommentInput.tsx b/apps/web/src/components/ThreadCard/CommentInput.tsx index b12e9f3f..ab306105 100644 --- a/apps/web/src/components/ThreadCard/CommentInput.tsx +++ b/apps/web/src/components/ThreadCard/CommentInput.tsx @@ -1,14 +1,8 @@ import { useEffect, useState } from "react"; import { useAccount } from "wagmi"; import useLocalStorage from "../../hooks/useLocalStorage"; -import { definition } from "@devnode/composedb"; -import { ComposeClient } from "@composedb/client"; import { DIDSession } from "did-session"; - -export const compose = new ComposeClient({ - ceramic: String(process.env.NEXT_PUBLIC_CERAMIC_NODE), - definition, -}); +import { trpc } from "../../utils/trpc"; const CommentInput = (props: { threadId: string }) => { const { isConnected } = useAccount(); @@ -25,35 +19,26 @@ const CommentInput = (props: { threadId: string }) => { getData(); }, [didSession]); + const authorDiscord = trpc.public.getDiscordUser.useQuery({ + didSession: didSession + }); + + const discordUserName = authorDiscord.data?.discordUsername ?? "Anonymous"; + const onCommentSubmit = async () => { - const session = await DIDSession.fromSession(didSession); - compose.setDID(session.did); - await compose - .executeQuery<{ - createComment: { document: { id: string } }; - }>( - `mutation CreateComment($input: CreateCommentInput!) { - createComment(input: $input) { - document { - id - threadID - text - createdAt - } - } - }`, - { - input: { - content: { - threadID: props.threadId, - text: String(comment), - createdAt: new Date().toISOString(), - }, - }, - } - ) - .then((r) => console.log(r)) - .catch((e) => console.log(e)); + // api to add comment to discord + await fetch(`${String(process.env.DISCORD_BOT_URL)}webcomment`, + { + body:JSON.stringify({ + threadId:props.threadId, + comment: String(comment), + discordUserName: String(discordUserName) + }), + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + }) }; return isConnected && didSession ? ( diff --git a/apps/web/src/server/trpc/router/public.ts b/apps/web/src/server/trpc/router/public.ts index b2cc8285..a1605e50 100644 --- a/apps/web/src/server/trpc/router/public.ts +++ b/apps/web/src/server/trpc/router/public.ts @@ -90,4 +90,16 @@ export const publicRouter = router({ return user; }), + + getDiscordUser: publicProcedure + .input(z.object({ didSession: z.string() })) + .query(async ({ input }) => { + let discordUsername = await prisma.user.findFirstOrThrow({ + where: { + didSession: input.didSession, + }, + }); + + return discordUsername; + }), }); From 568ebaac36e74d6f75139b1618cef10ded4c59da Mon Sep 17 00:00:00 2001 From: rushikesh dhanwant Date: Thu, 15 Dec 2022 17:11:20 +0530 Subject: [PATCH 06/11] typo --- apps/discord-bot/src/index.ts | 2 +- apps/web/src/components/Thread/NewThread.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/discord-bot/src/index.ts b/apps/discord-bot/src/index.ts index 133fbdb9..18a781e7 100644 --- a/apps/discord-bot/src/index.ts +++ b/apps/discord-bot/src/index.ts @@ -122,7 +122,7 @@ app.post('/webcomment', async (req, res) => { }) -app.post('/webThread', async (req, res) => { +app.post('/webthread', async (req, res) => { const { threadTitle, community, discordUserName} = req.body; console.log({threadTitle:threadTitle}) const response = await onThredCreateWeb(client, threadTitle, community, discordUserName); diff --git a/apps/web/src/components/Thread/NewThread.tsx b/apps/web/src/components/Thread/NewThread.tsx index ba8125f1..d49ba5e1 100644 --- a/apps/web/src/components/Thread/NewThread.tsx +++ b/apps/web/src/components/Thread/NewThread.tsx @@ -32,7 +32,7 @@ const NewThread = (props: { refresh: () => void }) => { const onThreadSumbit = async () => { - await fetch(`${String(process.env.DISCORD_BOT_URL)}webThread`, + await fetch(`${String(process.env.DISCORD_BOT_URL)}webthread`, { body:JSON.stringify({ community:String(community), From 1d85b594748910692427d83db49eac57f9d2a4c5 Mon Sep 17 00:00:00 2001 From: rushikesh dhanwant Date: Thu, 22 Dec 2022 03:21:42 +0530 Subject: [PATCH 07/11] response status fix --- apps/discord-bot/src/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/discord-bot/src/index.ts b/apps/discord-bot/src/index.ts index 18a781e7..24afc0b4 100644 --- a/apps/discord-bot/src/index.ts +++ b/apps/discord-bot/src/index.ts @@ -114,10 +114,10 @@ app.post('/webcomment', async (req, res) => { console.log({thredId:threadId, comment:comment}) const response = await onCommentCreateWeb(client, threadId, comment, discordUserName); if(response.result){ - res.status(400).send(response); + res.status(200).send(response.value); } else{ - res.status(200).send(response.value); + res.status(400).send(response.value); } }) @@ -127,10 +127,10 @@ app.post('/webthread', async (req, res) => { console.log({threadTitle:threadTitle}) const response = await onThredCreateWeb(client, threadTitle, community, discordUserName); if(response.result){ - res.status(400).send(response.value); + res.status(200).send(response.value); } else{ - res.status(200).send(response.value); + res.status(400).send(response.value); } }) From f113cba3bf20cd08fd3db5811b11e82780a219be Mon Sep 17 00:00:00 2001 From: rushikesh dhanwant Date: Thu, 22 Dec 2022 12:41:24 +0530 Subject: [PATCH 08/11] created modal to ask users to connect with discord --- apps/web/public/close.svg | 1 + apps/web/src/components/Modal/Modal.tsx | 46 ++++++++++++++ apps/web/src/components/Modal/index.tsx | 1 + apps/web/src/components/NavBar/NavBar.tsx | 63 ++++++++++++++++--- apps/web/src/components/Thread/NewThread.tsx | 3 +- .../components/ThreadCard/CommentInput.tsx | 3 +- 6 files changed, 105 insertions(+), 12 deletions(-) create mode 100644 apps/web/public/close.svg create mode 100644 apps/web/src/components/Modal/Modal.tsx create mode 100644 apps/web/src/components/Modal/index.tsx diff --git a/apps/web/public/close.svg b/apps/web/public/close.svg new file mode 100644 index 00000000..2f27b86f --- /dev/null +++ b/apps/web/public/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/web/src/components/Modal/Modal.tsx b/apps/web/src/components/Modal/Modal.tsx new file mode 100644 index 00000000..dbcec1a5 --- /dev/null +++ b/apps/web/src/components/Modal/Modal.tsx @@ -0,0 +1,46 @@ +import Image from "next/image"; + +const Modal = ({handleClick}) => { + + return ( + <> +
+
+
+ +
+
+ Connect with Discord bot +
+
+
    +
  1. Go to devnode server.
  2. +
  3. In "devnode_signin" channel type "devnode".
  4. +
  5. Check your DM. You will be asked to reply with your did. It should look similar to this example: "did:key:z6MkkyAkqY9bPr8gyQGuJTwQvzk8nsfywHCH4jyM1CgTq4KA". You can copy the DID by clicking on the created DID.
  6. +
  7. You will get a challenge link. Copy that link and paste it in your browser.
  8. +
  9. Once you get the success message, you are good to go. Head back to the application and start exploring.
  10. +
+
+ +
+ + + +
+
+ Go to Devnode Server +
+
+
+
+ + ); +}; + +export default Modal; diff --git a/apps/web/src/components/Modal/index.tsx b/apps/web/src/components/Modal/index.tsx new file mode 100644 index 00000000..b7c4885f --- /dev/null +++ b/apps/web/src/components/Modal/index.tsx @@ -0,0 +1 @@ +export { default as Modal } from "./Modal"; \ No newline at end of file diff --git a/apps/web/src/components/NavBar/NavBar.tsx b/apps/web/src/components/NavBar/NavBar.tsx index ba3015ea..18e35249 100644 --- a/apps/web/src/components/NavBar/NavBar.tsx +++ b/apps/web/src/components/NavBar/NavBar.tsx @@ -3,12 +3,14 @@ import { SearchIcon } from "@heroicons/react/solid"; import { MenuIcon, XIcon } from "@heroicons/react/outline"; import { useConnect, useAccount, useDisconnect } from "wagmi"; import Image from "next/image"; -import { Fragment } from "react"; +import { Fragment, useState } from "react"; import { EthereumWebAuth, getAccountId } from "@didtools/pkh-ethereum"; import { DIDSession } from "did-session"; import useLocalStorage from "../../hooks/useLocalStorage"; import { Resolver } from "did-resolver"; import { getResolver } from "pkh-did-resolver"; +import { trpc } from "../../utils/trpc"; +import { Modal } from "../Modal" const pkhResolver = getResolver(); const resolver = new Resolver(pkhResolver); @@ -27,6 +29,13 @@ const NavBar = () => { const [did, setDid] = useLocalStorage("did", ""); const [didSession, setDidSession] = useLocalStorage("didSession", ""); + const [isOpen, setOpen] = useState(false); + + const authorDiscord = trpc.public.getDiscordUser.useQuery({ + didSession: didSession + }); + const discordUserName = authorDiscord.data?.discordUsername; + const connectWallet = async () => { await Promise.all( connectors.map(async (connector) => { @@ -61,6 +70,10 @@ const NavBar = () => { setDid(session.did.id); }; + const handleClick = () =>{ + setOpen((state) => !state); + } + return ( <> {/* When the mobile menu is open, add `overflow-hidden` to the `body` element to prevent double scrollbars */} @@ -111,22 +124,16 @@ const NavBar = () => {
{/* Mobile menu button */} - + {/* Open menu {open ? ( + */}
-
- - Ask a question - +
{isConnected ? ( )} + + {discordUserName ? ( + + { + await navigator.clipboard.writeText(did); + }} + className="flex h-[50px] items-center justify-center rounded-[10px] border-[1px] border-[#DAD8E2] bg-white px-2 text-[#97929B] hover:border-[#08010D] hover:text-[#08010D] focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2" + > + {discordUserName} + + + +
+

Discord user name copied to clipboard!

+
+
+
+
+ ) : ( + + )} + {isOpen && }
diff --git a/apps/web/src/components/Thread/NewThread.tsx b/apps/web/src/components/Thread/NewThread.tsx index d49ba5e1..963d25f5 100644 --- a/apps/web/src/components/Thread/NewThread.tsx +++ b/apps/web/src/components/Thread/NewThread.tsx @@ -28,6 +28,7 @@ const NewThread = (props: { refresh: () => void }) => { didSession: didSession }); + const isDiscordUser = authorDiscord.data?.discordUsername; const discordUserName = authorDiscord.data?.discordUsername ?? "Anonymous"; const onThreadSumbit = async () => { @@ -46,7 +47,7 @@ const NewThread = (props: { refresh: () => void }) => { }) }; - return isConnected && didSession ? ( + return isConnected && didSession && isDiscordUser ? (
{ diff --git a/apps/web/src/components/ThreadCard/CommentInput.tsx b/apps/web/src/components/ThreadCard/CommentInput.tsx index ab306105..86b98673 100644 --- a/apps/web/src/components/ThreadCard/CommentInput.tsx +++ b/apps/web/src/components/ThreadCard/CommentInput.tsx @@ -23,6 +23,7 @@ const CommentInput = (props: { threadId: string }) => { didSession: didSession }); + const isDiscordUser = authorDiscord.data?.discordUsername; const discordUserName = authorDiscord.data?.discordUsername ?? "Anonymous"; const onCommentSubmit = async () => { @@ -41,7 +42,7 @@ const CommentInput = (props: { threadId: string }) => { }) }; - return isConnected && didSession ? ( + return isConnected && didSession && isDiscordUser ? (
{ From d662295896f4bd07dde3ed05c5a14cd88c63c7f7 Mon Sep 17 00:00:00 2001 From: rushikesh dhanwant Date: Fri, 23 Dec 2022 14:42:56 +0530 Subject: [PATCH 09/11] added comments from web to centralised db so that we can get the comments streamid --- .../src/handlers/onCommentCreateWeb.ts | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/apps/discord-bot/src/handlers/onCommentCreateWeb.ts b/apps/discord-bot/src/handlers/onCommentCreateWeb.ts index 73fdbc7a..fe8f0a9a 100644 --- a/apps/discord-bot/src/handlers/onCommentCreateWeb.ts +++ b/apps/discord-bot/src/handlers/onCommentCreateWeb.ts @@ -6,10 +6,6 @@ import { DIDSession } from "did-session"; import { Response } from "../type" import { ComposeClient } from "@composedb/client"; import { definition } from "@devnode/composedb"; -import { - DISCORD_DO_NOT_CREATE_THREADS_IF_NOT_SIGNED, - DISCORD_LOST_SESSION, -} from "../consts/replyMessages"; export const compose = new ComposeClient({ ceramic: String(process.env.CERAMIC_NODE), @@ -48,8 +44,10 @@ export const onCommentCreateWeb = async (client:Client, threadId:string, comment const session = await DIDSession.fromSession(user.didSession); compose.setDID(session.did); + let composeResponse; + try{ - await compose + composeResponse = await compose .executeQuery<{ createComment: { document: { id: string } }; }>( @@ -78,6 +76,30 @@ export const onCommentCreateWeb = async (client:Client, threadId:string, comment message.delete(); return {result: 'false', value:'compose failed'}; } + + if (!composeResponse || !composeResponse.data) { + await message.delete(); + return {result:'false', value:'composedb failed'}; + } + + await prisma.comment.upsert({ + where: { discordId: message.id }, + update: { + createdAt: message.createdAt, + discordAuthor: discordUserName, + text: comment, + }, + create: { + discordId: message.id, + streamId: composeResponse.data.createComment.document.id, + createdAt: message.createdAt, + discordAuthor: discordUserName, + text: comment, + Thread: { + connect: { id: existhreaingThread.id }, + }, + }, + }); } return {result: 'true', value:'comment added'}; From 89dd8e1db7176993ade544a8dbdf3dafdfd5b6c5 Mon Sep 17 00:00:00 2001 From: rushikesh dhanwant Date: Fri, 23 Dec 2022 14:47:22 +0530 Subject: [PATCH 10/11] resolved broken image and anonymous user name --- apps/web/src/components/Comment/index.tsx | 9 +++------ apps/web/src/components/Thread/index.tsx | 7 +++---- apps/web/src/components/ThreadCard/index.tsx | 7 +++---- apps/web/src/server/trpc/router/public.ts | 4 ++-- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/apps/web/src/components/Comment/index.tsx b/apps/web/src/components/Comment/index.tsx index 89c2024f..a5bd5a19 100644 --- a/apps/web/src/components/Comment/index.tsx +++ b/apps/web/src/components/Comment/index.tsx @@ -16,8 +16,8 @@ const Comment: React.FC = ({ data }) => { const authorDiscord = trpc.public.getAuthorDiscordForComment.useQuery({ commentStreamId: data.id, }); - - return ( + const avatar = authorDiscord.data?.discordAvatar !== "" ? authorDiscord.data?.discordAvatar : "http://placekitten.com/200/200"; + return (
@@ -26,10 +26,7 @@ const Comment: React.FC = ({ data }) => { width="32" height="32" className="rounded-full" - src={ - authorDiscord.data?.discordAvatar ?? - "http://placekitten.com/200/200" - } + src={avatar} alt="" />
diff --git a/apps/web/src/components/Thread/index.tsx b/apps/web/src/components/Thread/index.tsx index b502fb40..610ebd26 100644 --- a/apps/web/src/components/Thread/index.tsx +++ b/apps/web/src/components/Thread/index.tsx @@ -17,6 +17,8 @@ const Thread: React.FC = ({ data }) => { threadStreamId: data.id, }); + const avatar = authorDiscord.data?.discordAvatar !== "" ? authorDiscord.data?.discordAvatar : "http://placekitten.com/200/200"; + return (
@@ -26,10 +28,7 @@ const Thread: React.FC = ({ data }) => { width="32" height="32" className="rounded-full" - src={ - authorDiscord.data?.discordAvatar ?? - "http://placekitten.com/200/200" - } + src={avatar} alt="" />
diff --git a/apps/web/src/components/ThreadCard/index.tsx b/apps/web/src/components/ThreadCard/index.tsx index c9f1a1c3..003dd077 100644 --- a/apps/web/src/components/ThreadCard/index.tsx +++ b/apps/web/src/components/ThreadCard/index.tsx @@ -17,6 +17,8 @@ const ThreadCard = ({ thread }) => { .filter((comment) => comment.node.threadID == id) .map((comment) => comment.node); + const avatar = authorDiscord.data?.discordAvatar !== "" ? authorDiscord.data?.discordAvatar : "http://placekitten.com/200/200"; + return (
@@ -26,10 +28,7 @@ const ThreadCard = ({ thread }) => { width={32} height={32} className="rounded-full" - src={ - authorDiscord.data?.discordAvatar ?? - "http://placekitten.com/200/200" - } + src={avatar} alt="" />
diff --git a/apps/web/src/server/trpc/router/public.ts b/apps/web/src/server/trpc/router/public.ts index a1605e50..d550b53b 100644 --- a/apps/web/src/server/trpc/router/public.ts +++ b/apps/web/src/server/trpc/router/public.ts @@ -76,7 +76,7 @@ export const publicRouter = router({ getAuthorDiscordForComment: publicProcedure .input(z.object({ commentStreamId: z.string() })) .query(async ({ input }) => { - let thread = await prisma.comment.findFirstOrThrow({ + let comment = await prisma.comment.findFirstOrThrow({ where: { streamId: input.commentStreamId, }, @@ -84,7 +84,7 @@ export const publicRouter = router({ let user = await prisma.user.findFirstOrThrow({ where: { - discordUsername: thread.discordAuthor, + discordUsername: comment.discordAuthor, }, }); From 13eee6a25c76240e43e4ad6d3b49692b300b23a3 Mon Sep 17 00:00:00 2001 From: rushikesh dhanwant Date: Fri, 23 Dec 2022 14:53:44 +0530 Subject: [PATCH 11/11] modal update --- .env.template | 1 + apps/web/src/components/Modal/Modal.tsx | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.env.template b/.env.template index c82d6992..71434098 100644 --- a/.env.template +++ b/.env.template @@ -5,6 +5,7 @@ DISCORD_CHANNEL_NAME=devnode MYSQL_URL=mysql://root:testpassword@localhost/devnode NEXTAUTH_URL=http://localhost:3000/ DISCORD_BOT_URL=http://localhost:4000/ +DISCORD_SERVER_URL= #Staging DISCORD_TOKEN= diff --git a/apps/web/src/components/Modal/Modal.tsx b/apps/web/src/components/Modal/Modal.tsx index dbcec1a5..3b5f1cba 100644 --- a/apps/web/src/components/Modal/Modal.tsx +++ b/apps/web/src/components/Modal/Modal.tsx @@ -21,13 +21,13 @@ const Modal = ({handleClick}) => {
  1. Go to devnode server.
  2. -
  3. In "devnode_signin" channel type "devnode".
  4. -
  5. Check your DM. You will be asked to reply with your did. It should look similar to this example: "did:key:z6MkkyAkqY9bPr8gyQGuJTwQvzk8nsfywHCH4jyM1CgTq4KA". You can copy the DID by clicking on the created DID.
  6. +
  7. In "devnode_signin" channel type "devnode".
  8. +
  9. Check your DM. You will be asked to reply with your did. It should look similar to this example: "did:key:z6MkkyAkqY9bPr8gyQGuJTwQvzk8nsfywHCH4jyM1CgTq4KA". You can copy the DID by clicking on the created DID.
  10. You will get a challenge link. Copy that link and paste it in your browser.
  11. Once you get the success message, you are good to go. Head back to the application and start exploring.
- +