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 api refactoring and updates #27

Merged
merged 4 commits into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions apps/discord-bot/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
node_modules
# Keep environment variables out of version control
.env

# log files
*.log
1 change: 1 addition & 0 deletions apps/discord-bot/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {DIDSession} from "did-session";
export const config = {
server: {
port: process.env.AGGREGATOR_PORT || 4000,
apiKey: process.env.AGGREGATOR_API_KEY || "sample-api-key",
},
compose: {
nodeUrl: process.env.CERAMIC_NODE || "",
Expand Down
3 changes: 1 addition & 2 deletions apps/discord-bot/src/core/comments/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import {config, constants} from "../../config";
import {Resp} from "../utils/response";
import {Client} from "discord.js";
import {commentHandler as discordCommentHandler} from "../../bots/discord";
import {composeQueryHandler} from "@devnode/composedb";
import {logger} from "../utils/logger";
import {communityHasSocial, getSocialCommunityId} from "../utils/data";

export const postComment = async (clients: Clients, req: Request, res: Response) => {
const {commentId} = req.body;
const comment: Node<Comment> = await composeQueryHandler().fetchCommentDetails(commentId);
const comment: Node<Comment> = await clients.composeQuery().fetchCommentDetails(commentId);
const socials = _.get(comment, "node.thread.community.socialPlatforms.edges");

if (communityHasSocial(socials, constants.PLATFORM_DISCORD_NAME)) {
Expand Down
12 changes: 12 additions & 0 deletions apps/discord-bot/src/core/middleware/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {NextFunction, Request, Response} from "express";
import {Resp} from "../utils/response";

export const apiKeyAuth = (apiKey: string) => {
return (req: Request, res: Response, next: NextFunction) => {
const apiKeyHeader = req.headers['x-api-key'];
if (apiKeyHeader !== apiKey) {
return Resp.unAuth(res, "unauthorized");
}
next();
};
}
3 changes: 2 additions & 1 deletion apps/discord-bot/src/core/middleware/validator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import joi from "joi";
import {NextFunction, Request, Response} from "express";
import {Resp} from "../utils/response";

export const commentSchema = joi.object({
commentId: joi.string().required(),
Expand All @@ -15,7 +16,7 @@ export const validator = (schema: joi.Schema) => {
req.body = await schema.validateAsync(req.body);
return next();
} catch (e) {
return res.status(400).json(e);
return Resp.notOk(res, "invalid payload");
}
}
}
2 changes: 2 additions & 0 deletions apps/discord-bot/src/core/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {Client, GatewayIntentBits, Partials} from "discord.js";
import {commentSchema, threadSchema, validator} from "./middleware/validator";
import {Clients} from "./types";
import {logger} from "./utils/logger";
import {apiKeyAuth} from "./middleware/auth";

process.on("uncaughtException", (error, origin) => {
console.log(error);
Expand All @@ -23,6 +24,7 @@ export const initServer = (clients: Clients): Express => {
server.use(cors());
server.use(express.urlencoded({extended: true}));
server.use(express.json());
server.use(apiKeyAuth(config.server.apiKey));

const router = express.Router();
router.get("/ping", (_, res) => res.send("pong"));
Expand Down
23 changes: 14 additions & 9 deletions apps/discord-bot/src/core/threads/handler.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
import {Request, Response} from "express";
import {composeQueryHandler} from "@devnode/composedb";
import {Clients, Node, Thread} from "../types";
import _ from "lodash";
import {communityHasSocial, getSocialCommunityId} from "../utils/data";
import {config, constants} from "../../config";
import {Resp} from "../utils/response";
import {threadHandler as discordThreadHandler} from "../../bots/discord";
import {logger} from "../utils/logger";

export const postThread = async (clients: Clients, req: Request, res: Response) => {
const {threadId} = req.body;
const thread: Node<Thread> = await composeQueryHandler().fetchThreadDetails(threadId);
const socials = _.get(thread, "node.community.socialPlatforms.edges");
try {
const {threadId} = req.body;
const thread: Node<Thread> = await clients.composeQuery().fetchThreadDetails(threadId);
const socials = _.get(thread, "node.community.socialPlatforms.edges");

if (communityHasSocial(socials, constants.PLATFORM_DISCORD_NAME)) {
const threadId = await postThreadToDiscord(clients, thread);
return Resp.okD(res, {threadId}, "Created thread on socials");
} else {
return Resp.notOk(res, "No discord for this community, bailing out!");
if (communityHasSocial(socials, constants.PLATFORM_DISCORD_NAME)) {
const threadId = await postThreadToDiscord(clients, thread);
return Resp.okD(res, {threadId}, "Created thread 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");
}
};

Expand Down
2 changes: 2 additions & 0 deletions apps/discord-bot/src/core/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {ComposeClient} from "@composedb/client";
import {Client as DiscordClient} from "discord.js";
import {composeQueryHandler} from "@devnode/composedb";

export type Clients = {
compose: ComposeClient,
composeQuery: typeof composeQueryHandler,
discord: DiscordClient,
};

Expand Down
3 changes: 2 additions & 1 deletion apps/discord-bot/src/core/utils/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {Response} from "express";
export const Resp = {
ok: (res: Response, msg: string) => res.status(200).json({msg}).end(),
okD: (res: Response, data: object, msg: string) => res.status(200).json({msg, data}).end(),
notOk: (res: Response, msg: string) => res.status(401).json({msg}).end(),
notOk: (res: Response, msg: string) => res.status(400).json({msg}).end(),
unAuth: (res: Response, msg: string) => res.status(401).json({msg}).end(),
error: (res: Response, msg: string) => res.status(500).json({msg}).end(),
}
3 changes: 2 additions & 1 deletion apps/discord-bot/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {initDiscord, initServer} from "./core";
import {config} from "./config";
import {ComposeClient} from "@composedb/client";
import {definition} from "@devnode/composedb";
import {composeQueryHandler, definition} from "@devnode/composedb";
import {attachListeners} from "./bots/discord";
import {Clients} from "./core/types";

Expand All @@ -15,6 +15,7 @@ const start = async () => {
const clients: Clients = {
discord: discordClient,
compose: composeClient,
composeQuery: composeQueryHandler,
};

const server = initServer(clients);
Expand Down
141 changes: 141 additions & 0 deletions apps/discord-bot/tests/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
export const sampleComment = {
"node": {
"id": "kjzl6kcym7w8y6384dl2gsx51b6vvn780h61qcwtil7klp5s5y3u3zo0uekc0oo",
"text": "I am aware of the fact that storing anything sensitive on the client side is a no-do. ",
"userId": "k2t6wzhkhabz2wixqd45q1wxpoy9fg7wd2dbfp2vzgq0wd2dq9sh5fkzywjxye",
"threadId": "kjzl6kcym7w8y772zht4omem25y3plfp929wsgumb158oi8uca2fnlhcdri2jqx",
"createdAt": "2023-03-16T09:59:02.979Z",
"createdFrom": "devnode",
"user": {
"id": "k2t6wzhkhabz2wixqd45q1wxpoy9fg7wd2dbfp2vzgq0wd2dq9sh5fkzywjxye",
"walletAddress": "0x7c98C2DEc5038f00A2cbe8b7A64089f9c0b51991",
"author": {
"id": "did:pkh:eip155:1:0x7c98C2DEc5038f00A2cbe8b7A64089f9c0b51991"
},
"userPlatforms": [
{
"platformId": "devnode",
"platformName": "devnode",
"platformAvatar": "https://avatars.githubusercontent.com/u/35269424",
"platformUsername": "atul"
},
{
"platformId": "922429029544525866",
"platformName": "discord",
"platformAvatar": "https://cdn.discordapp.com/avatars/922429029544525866/5d55754141899036e54df7df8ae8e7c5.jpg",
"platformUsername": "atul#0555"
}
],
"createdAt": "2023-03-16T06:56:22.443Z"
},
"thread": {
"id": "kjzl6kcym7w8y772zht4omem25y3plfp929wsgumb158oi8uca2fnlhcdri2jqx",
"title": "Is storing secrets in redux store secure?",
"userId": "k2t6wzhkhabz2wixqd45q1wxpoy9fg7wd2dbfp2vzgq0wd2dq9sh5fkzywjxye",
"threadId": "na",
"createdAt": "2023-03-15T09:22:45.468Z",
"community": {
"socialPlatforms": {
"edges": [
{
"node": {
"platformId": "785055113126871091",
"platform": "discord"
}
}
]
}
},
"communityId": "kjzl6kcym7w8y8dgfi093n3o6gby2gwq4fs3nltxjl8gutwvr2ol1sf9vpdmn09",
"createdFrom": "devnode",
"author": {
"id": "did:key:"
},
"user": {
"id": "k2t6wzhkhabz2wixqd45q1wxpoy9fg7wd2dbfp2vzgq0wd2dq9sh5fkzywjxye",
"walletAddress": "0x7c98C2DEc5038f00A2cbe8b7A64089f9c0b51991",
"author": {
"id": "did:pkh:eip155:1:0x7c98C2DEc5038f00A2cbe8b7A64089f9c0b51991"
},
"userPlatforms": [
{
"platformId": "devnode",
"platformName": "devnode",
"platformAvatar": "https://avatars.githubusercontent.com/u/35269424",
"platformUsername": "atul"
},
{
"platformId": "922429029544525866",
"platformName": "discord",
"platformAvatar": "https://cdn.discordapp.com/avatars/922429029544525866/5d55754141899036e54df7df8ae8e7c5.jpg",
"platformUsername": "atul#0555"
}
],
"createdAt": "2023-03-16T06:56:22.443Z"
}
},
"author": {
"id": "did:pkh:eip155:1:0x7c98C2DEc5038f00A2cbe8b7A64089f9c0b51991"
}
}
};

export const sampleThread = {
"node": {
"id": "kjzl6kcym7w8y772zht4omem25y3plfp929wsgumb158oi8uca2fnlhcdri2jqx",
"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",
"createdAt": "2023-03-15T09:22:45.468Z",
"communityId": "kjzl6kcym7w8y8dgfi093n3o6gby2gwq4fs3nltxjl8gutwvr2ol1sf9vpdmn09",
"createdFrom": "devnode",
"author": {
"id": "did:key:z"
},
"user": {
"id": "k2t6wzhkhabz2wixqd45q1wxpoy9fg7wd2dbfp2vzgq0wd2dq9sh5fkzywjxye",
"walletAddress": "0x7c98C2DEc5038f00A2cbe8b7A64089f9c0b51991",
"author": {
"id": "did:pkh:eip155:1:0x7c98C2DEc5038f00A2cbe8b7A64089f9c0b51991"
},
"userPlatforms": [
{
"platformId": "devnode",
"platformName": "devnode",
"platformAvatar": "https://avatars.githubusercontent.com/u/35269424",
"platformUsername": "atul"
},
{
"platformId": "922429029544525866",
"platformName": "discord",
"platformAvatar": "https://cdn.discordapp.com/avatars/922429029544525866/5d55754141899036e54df7df8ae8e7c5.jpg",
"platformUsername": "atul#0555"
}
],
"createdAt": "2023-03-16T06:56:22.443Z"
},
"community": {
"id": "kjzl6kcym7w8y8dgfi093n3o6gby2gwq4fs3nltxjl8gutwvr2ol1sf9vpdmn09",
"createdAt": "2023-03-15T11:55:36.358Z",
"communityName": "rushiserver",
"socialPlatforms": {
"edges": [
{
"node": {
"platformId": "785055113126871091",
"platform": "discord"
}
}
]
},
"author": {
"id": "did:pkh:eip155:1:0x8b2a6a22ec055225C4c4b5815e7d9F566b8be68F"
}
},
"comments": {
"edges": [sampleComment]
}
}
};

26 changes: 23 additions & 3 deletions apps/discord-bot/tests/functional/comments.spec.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
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";

describe("comment api", () => {
let server: Express;
const url = "/api/web-comment";
before(() => server = initServer({} as any));
const header = {'x-api-key': config.server.apiKey};

it("should validate the schema for request", async () => {
before(() => {
server = initServer({
discord: fakeDiscordClient,
compose: fakeComposeClient,
composeQuery: fakeComposeQueryClient,
});
});

it("should authenticate the api call", async () => {
const res = await chai.request(server).post(url);
expect(res.status).to.eql(401);
});

it("should validate the schema for request", async () => {
const res = await chai.request(server).post(url).set(header);
expect(res.status).to.eql(400);
const another = await chai.request(server).post(url).send({commentId: 123});
const another = await chai.request(server).post(url).set(header).send({commentId: 123});
expect(another.status).to.eql(400);
});

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);
});
});
11 changes: 10 additions & 1 deletion apps/discord-bot/tests/functional/ping.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import {Express} from "express";
import {initServer} from "../../src/core";
import chai, {expect} from "../setup";
import {config} from "../../src/config";

describe("ping api", () => {
let server: Express;
const header = {'x-api-key': config.server.apiKey};

before(() => server = initServer({} as any));
it("should respond with pong on call", async () => {

it("should authenticate the call", async () => {
const res = await chai.request(server).get("/api/ping");
expect(res).to.have.status(401);
});

it("should respond with pong on call", async () => {
const res = await chai.request(server).get("/api/ping").set(header);
expect(res).to.have.status(200);
expect(res.text).to.eql("pong");
});
Expand Down
21 changes: 18 additions & 3 deletions apps/discord-bot/tests/functional/threads.spec.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
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";

describe("thread api", () => {
let server: Express;
const url = "/api/web-thread";
before(() => server = initServer({} as any));
const header = {'x-api-key': config.server.apiKey};

it("should validate the schema for request", async () => {
before(() => {
server = initServer({
discord: fakeDiscordClient,
compose: fakeComposeClient,
composeQuery: fakeComposeQueryClient,
});
});

it("should authenticate the api call", async () => {
const res = await chai.request(server).post(url);
expect(res.status).to.eql(401);
});

it("should validate the schema for request", async () => {
const res = await chai.request(server).post(url).set(header);
expect(res.status).to.eql(400);
const another = await chai.request(server).post(url).send({threadId: 123});
const another = await chai.request(server).post(url).set(header).send({threadId: 123});
expect(another.status).to.eql(400);
});
});
Loading