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

Add web comments/Threads to discord #3

Merged
merged 11 commits into from
Dec 27, 2022
2 changes: 2 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ DISCORD_CHANNEL_NAME=devnode
#Local
MYSQL_URL=mysql://root:testpassword@localhost/devnode
NEXTAUTH_URL=http://localhost:3000/
DISCORD_BOT_URL=http://localhost:4000/
DISCORD_SERVER_URL=

#Staging
DISCORD_TOKEN=
Expand Down
6 changes: 5 additions & 1 deletion apps/discord-bot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
106 changes: 106 additions & 0 deletions apps/discord-bot/src/handlers/onCommentCreateWeb.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
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";

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<Response> => {

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);

let composeResponse;

try{
composeResponse = 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'};
}

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'};
};
110 changes: 110 additions & 0 deletions apps/discord-bot/src/handlers/onThreadCreateWeb.ts
Original file line number Diff line number Diff line change
@@ -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<Response> => {

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'};
};
41 changes: 41 additions & 0 deletions apps/discord-bot/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -96,4 +106,35 @@ 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(200).send(response.value);
}
else{
res.status(400).send(response.value);
}

})

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(200).send(response.value);
}
else{
res.status(400).send(response.value);
}
})

app.listen(port, () => {
console.log(`server listening on port ${port}`)
})
export {};
4 changes: 4 additions & 0 deletions apps/discord-bot/src/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type Response = {
result: string,
value: string | object
}
1 change: 1 addition & 0 deletions apps/web/public/close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 3 additions & 6 deletions apps/web/src/components/Comment/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ const Comment: React.FC<CommentProps> = ({ 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 (
<div className="space-y-[23px]">
<div className="flex items-center gap-[11px]">
<div className="flex items-center"></div>
Expand All @@ -26,10 +26,7 @@ const Comment: React.FC<CommentProps> = ({ data }) => {
width="32"
height="32"
className="rounded-full"
src={
authorDiscord.data?.discordAvatar ??
"http://placekitten.com/200/200"
}
src={avatar}
alt=""
/>
<div>
Expand Down
46 changes: 46 additions & 0 deletions apps/web/src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import Image from "next/image";

const Modal = ({handleClick}) => {

return (
<>
<div className="fixed h-screen w-screen bg-neutral-900/50 flex justify-center items-center overflow-y-auto z-10 inset-0">
<div className="flex flex-col border-2 rounded-lg w-1/2 bg-white p-6 relative">
<div className="absolute right-0 mr-6" onClick={handleClick}>
<Image
width="22"
height="22"
className="rounded-full"
src="/close.svg"
alt=""
/>
</div>
<div className="mx-auto text-[48px] font-medium text-[#08010D] my-2">
Connect with Discord bot
</div>
<div className="mx-6 my-3">
<ol className="list-decimal break-words">
<li>Go to devnode server.</li>
<li>In &quot;devnode_signin&quot; channel type &quot;devnode&quot;.</li>
<li>Check your DM. You will be asked to reply with your did. It should look similar to this example: &quot;did:key:z6MkkyAkqY9bPr8gyQGuJTwQvzk8nsfywHCH4jyM1CgTq4KA&quot;. You can copy the DID by clicking on the created DID.</li>
<li>You will get a challenge link. Copy that link and paste it in your browser.</li>
<li>Once you get the success message, you are good to go. Head back to the application and start exploring.</li>
</ol>
</div>
<a href={String(process.env.DISCORD_SERVER_URL)} target="_blank" rel="noreferrer" className="flex justify- items-center w-1/3 mx-auto bg-[#5A68F1] text-white p-3 border-2 rounded-lg">
<div className="w-5 h-5 mr-2">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" fill="currentColor" viewBox="0 0 16 16">
<path d="M13.545 2.907a13.227 13.227 0 0 0-3.257-1.011.05.05 0 0 0-.052.025c-.141.25-.297.577-.406.833a12.19 12.19 0 0 0-3.658 0 8.258 8.258 0 0 0-.412-.833.051.051 0 0 0-.052-.025c-1.125.194-2.22.534-3.257 1.011a.041.041 0 0 0-.021.018C.356 6.024-.213 9.047.066 12.032c.001.014.01.028.021.037a13.276 13.276 0 0 0 3.995 2.02.05.05 0 0 0 .056-.019c.308-.42.582-.863.818-1.329a.05.05 0 0 0-.01-.059.051.051 0 0 0-.018-.011 8.875 8.875 0 0 1-1.248-.595.05.05 0 0 1-.02-.066.051.051 0 0 1 .015-.019c.084-.063.168-.129.248-.195a.05.05 0 0 1 .051-.007c2.619 1.196 5.454 1.196 8.041 0a.052.052 0 0 1 .053.007c.08.066.164.132.248.195a.051.051 0 0 1-.004.085 8.254 8.254 0 0 1-1.249.594.05.05 0 0 0-.03.03.052.052 0 0 0 .003.041c.24.465.515.909.817 1.329a.05.05 0 0 0 .056.019 13.235 13.235 0 0 0 4.001-2.02.049.049 0 0 0 .021-.037c.334-3.451-.559-6.449-2.366-9.106a.034.034 0 0 0-.02-.019Zm-8.198 7.307c-.789 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.45.73 1.438 1.613 0 .888-.637 1.612-1.438 1.612Zm5.316 0c-.788 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.451.73 1.438 1.613 0 .888-.631 1.612-1.438 1.612Z"/>
</svg>
</div>
<div className="w-full">
Go to Devnode Server
</div>
</a>
</div>
</div>
</>
);
};

export default Modal;
1 change: 1 addition & 0 deletions apps/web/src/components/Modal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Modal } from "./Modal";
Loading