Skip to content

Commit

Permalink
Merge pull request #15 from PRATHAM1ST/master
Browse files Browse the repository at this point in the history
Added Single member route and eslint
  • Loading branch information
PRATHAM1ST authored Sep 24, 2023
2 parents 51dc349 + a8fc161 commit 5e9fd59
Show file tree
Hide file tree
Showing 13 changed files with 1,573 additions and 218 deletions.
25 changes: 25 additions & 0 deletions __tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,28 @@ describe("GET /members", () => {
expect(member).toHaveProperty("github_link");
});
});

describe("GET /member/PRATHAM1ST", () => {
it("should return a 200 response", async () => {
const res = await request(app).get("/member/PRATHAM1ST");
expect(res.status).toBe(200);
});

it("should return an object", async () => {
const res = await request(app).get("/member/PRATHAM1ST");
expect(typeof res.body.data).toBe("object");
});

it("should return an object with the correct properties", async () => {
const res = await request(app).get("/member/PRATHAM1ST");
const member = res.body.data;
expect(member).toHaveProperty("name");
expect(member).toHaveProperty("username");
expect(member).toHaveProperty("profile_pic_url");
expect(member).toHaveProperty("followers");
expect(member).toHaveProperty("following");
expect(member).toHaveProperty("repositories");
expect(member).toHaveProperty("bio");
expect(member).toHaveProperty("github_link");
});
});
17 changes: 13 additions & 4 deletions app.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
require('dotenv').config()
import "dotenv/config";

import express, { Express, Request, Response } from "express";
import membersRoute from "./routes/members";
import cors from "cors";
import morgan from "morgan";
import ResponseHandler from "./components/response";
import ResponseHandler from "./components/responseHandler";

import membersRoute from "./routes/members";
import memberRoute from "./routes/member";

const corsOptions = {
origin: "*",
Expand All @@ -17,9 +20,15 @@ app.use(cors());
app.use(morgan("dev"));

app.get("/", (req: Request, res: Response) => {
return ResponseHandler.success(req, res, "Hello World", "Success");
return ResponseHandler.success({
req,
res,
data: "Hello World",
message: "Success",
});
});

app.use("/member", memberRoute);
app.use("/members", membersRoute);

export default app;
17 changes: 17 additions & 0 deletions components/errorHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { NextFunction, Request, Response } from "express";
import ResponseHandler from "./responseHandler";

const errorHandler = (
fn: (req: Request, res: Response, next?: NextFunction) => Promise<Response>
) =>
function (req: Request, res: Response, next: NextFunction) {
Promise.resolve(fn(req, res, next)).catch((err: Error) => {
return ResponseHandler.error({
req,
res,
message: err.message,
});
});
};

export default errorHandler;
20 changes: 0 additions & 20 deletions components/response.ts

This file was deleted.

25 changes: 25 additions & 0 deletions components/responseHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Request, Response } from "express";

class ResponseHandler {
static success(options: {
req: Request;
res: Response;
data: string | object | object[] | null;
message: string;
}) {
return options.res.status(200).json({
status: true,
data: options.data,
message: options.message,
});
}

static error(options: { req: Request; res: Response; message: string }) {
return options.res.status(500).json({
status: false,
message: options.message,
});
}
}

export default ResponseHandler;
123 changes: 123 additions & 0 deletions controllers/member.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { Request, Response } from "express";
import membersListLatest from "../data/members-list.json";
import ResponseHandler from "../components/responseHandler";
import axios, { AxiosResponse } from "axios";
import { parseHTML } from "linkedom";

interface Member {
login: string;
username?: string;
name: null | string;
tfa_enabled: boolean;
is_public: boolean;
role: string | null;
last_active: string | null;
saml_name_id: null | string;
profile_pic_url?: null | string;
followers?: null | string;
following?: null | string;
repositories?: null | string;
bio?: null | string;
github_link?: string;
}

const getUserProfile = async (login: string) => {
const response: AxiosResponse = await axios.get(
`https://github.com/${login}`
);

if (response.status !== 200) {
throw new Error("User not found");
}

return await response.data;
};

const getUserInfo = async (html: string) => {
const { document } = parseHTML(html);
const photoSrc: HTMLAnchorElement | null = document.querySelector(
".js-profile-editable-replace > .clearfix.d-flex.d-md-block.flex-items-center.mb-4.mb-md-0 > .position-relative.d-inline-block.col-2.col-md-12.mr-3.mr-md-0.flex-shrink-0 > a"
);
const followersAndFollowing: NodeListOf<HTMLSpanElement> | null =
document.querySelectorAll(
".js-profile-editable-area.d-flex.flex-column.d-md-block > div.flex-order-1.flex-md-order-none.mt-2.mt-md-0 > div > a > span"
);

const repositories: HTMLSpanElement | null = document.querySelector(
".Layout-main > div > nav > a > .Counter"
);

const bio: HTMLDivElement | null =
document.querySelector("div[data-bio-text]");

if (!followersAndFollowing)
console.log("Followers and Following not found");

if (!photoSrc) console.log("Photo not found");

if (!repositories) console.log("Repositories not found");

return {
profile_pic_url: photoSrc?.href,
followers: followersAndFollowing[0]
? followersAndFollowing[0].innerText
: "0",
following: followersAndFollowing[1]
? followersAndFollowing[1].innerText
: "0",
repositories: repositories?.title,
bio: bio?.innerText ?? "",
};
};

export const updateSingleMember = async (member: Member) => {
const html = await getUserProfile(member.login);
const { profile_pic_url, followers, following, repositories, bio } = await getUserInfo(html);
member.username = member.login;
member.github_link = `https://github.com/${member.login}`;
member.profile_pic_url = profile_pic_url;
member.followers = followers ?? "0";
member.following = following ?? "0";
member.repositories = repositories ?? "0";
member.bio = bio ?? "";

return member;
};

export async function PATCH(req: Request, res: Response) {
const getGithubUserName = req.params.username;

const member = membersListLatest.find((member) => member.login === getGithubUserName);
if (!member) throw new Error("Member not found");

const updatedMember = await updateSingleMember(member);
if (!updatedMember) throw new Error("Member not found");

console.log("updatedMember", updatedMember);

return ResponseHandler.success({
req,
res,
data: updatedMember,
message: "Member found",
});
}

export async function GET(req: Request, res: Response) {
const getGithubUserName = req.params.username;
const membersListArray: Member[] = membersListLatest;
const member = membersListArray.find(
(member) => member.login === getGithubUserName
);

if (!member) throw new Error("Member not found");

return ResponseHandler.success({
req,
res,
data: member,
message: "Member found",
});
}

export default { GET, PATCH };
124 changes: 17 additions & 107 deletions controllers/members.ts
Original file line number Diff line number Diff line change
@@ -1,119 +1,29 @@
import { Request, Response } from "express";
import axios, { AxiosResponse } from "axios";
import { parseHTML } from "linkedom";
import membersList from "../data/members-list-old.json";
import membersListLatest from "../data/members-list.json";
import ResponseHandler from "../components/response";

interface Member {
login: string;
username?: string;
name: null | string;
tfa_enabled: boolean;
is_public: boolean;
role: string | null;
last_active: string | null;
saml_name_id: null | string;
profile_pic_url?: null | string;
followers?: null | string;
following?: null | string;
repositories?: null | string;
bio?: null | string;
github_link?: string;
}

const getUserProfile = async (login: string) => {
const response: AxiosResponse = await axios.get(
`https://github.com/${login}`
);

if (response.status !== 200) {
throw new Error("User not found");
}

return await response.data;
};

const getUserInfo = async (html: string) => {
const { document } = parseHTML(html);
const photoSrc: HTMLAnchorElement | null = document.querySelector(
".js-profile-editable-replace > .clearfix.d-flex.d-md-block.flex-items-center.mb-4.mb-md-0 > .position-relative.d-inline-block.col-2.col-md-12.mr-3.mr-md-0.flex-shrink-0 > a"
);
const followersAndFollowing: NodeListOf<HTMLSpanElement> | null =
document.querySelectorAll(
".js-profile-editable-area.d-flex.flex-column.d-md-block > div.flex-order-1.flex-md-order-none.mt-2.mt-md-0 > div > a > span"
);

const repositories: HTMLSpanElement | null = document.querySelector(
".Layout-main > div > nav > a > .Counter"
);

const bio: HTMLDivElement | null =
document.querySelector("div[data-bio-text]");

if (!followersAndFollowing)
console.log("Followers and Following not found");

if (!photoSrc) console.log("Photo not found");

if (!repositories) console.log("Repositories not found");

return {
profile_pic_url: photoSrc?.href,
followers: followersAndFollowing[0]
? followersAndFollowing[0].innerText
: "0",
following: followersAndFollowing[1]
? followersAndFollowing[1].innerText
: "0",
repositories: repositories?.title,
bio: bio?.innerText ?? "",
};
};

const updateSingleMember = async (member: Member) => {
const html = await getUserProfile(member.login);
const { profile_pic_url, followers, following, repositories, bio } =
await getUserInfo(html);
member.username = member.login;
member.github_link = `https://github.com/${member.login}`;
member.profile_pic_url = profile_pic_url;
member.followers = followers ?? "0";
member.following = following ?? "0";
member.repositories = repositories ?? "0";
member.bio = bio ?? "";
};
import ResponseHandler from "../components/responseHandler";
import { updateSingleMember } from "./member";

export async function PATCH(req: Request, res: Response) {
try {
const membersListArray: Member[] = membersList;

await Promise.all(
membersListArray.map(async (member) => updateSingleMember(member))
);
const updateMembersListArray = await Promise.all(
membersList.map((member) => updateSingleMember(member))
);

return ResponseHandler.success(
req,
res,
membersListArray,
"Members list updated"
);
} catch (err: any) {
return ResponseHandler.error(req, res, err);
}
return ResponseHandler.success({
req,
res,
data: updateMembersListArray,
message: "Members list updated",
});
}

export async function GET(req: Request, res: Response) {
try {
return ResponseHandler.success(
req,
res,
membersListLatest,
"Members list"
);
} catch (err: any) {
return ResponseHandler.error(req, res, err);
}
return ResponseHandler.success({
req,
res,
data: membersListLatest,
message: "Members list",
});
}

export default { GET, PATCH };
Loading

0 comments on commit 5e9fd59

Please sign in to comment.