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

Create GitHub Workflow for Linting #24

Merged
merged 6 commits into from
Oct 16, 2021
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
39 changes: 39 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Lint Code Base

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

jobs:
run-lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"

- name: Cache node_modules
uses: actions/cache@v2
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-

- name: Install dependencies
run: yarn --cwd ./frontend/ && yarn --cwd ./backend

- name: Lint frontend
working-directory: ./frontend
run: yarn lint

- name: Lint backend
working-directory: ./backend
run: yarn lint
119 changes: 59 additions & 60 deletions backend/graphql/index.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,59 @@
import { makeExecutableSchema, gql } from "apollo-server-express";
import { applyMiddleware } from "graphql-middleware";
import { merge } from "lodash";

import {
isAuthorizedByEmail,
isAuthorizedByRole,
isAuthorizedByUserId,
} from "../middlewares/auth";
import authResolvers from "./resolvers/authResolvers";
import authType from "./types/authType";
import entityResolvers from "./resolvers/entityResolvers";
import entityType from "./types/entityType";
import userResolvers from "./resolvers/userResolvers";
import userType from "./types/userType";

const query = gql`
type Query {
_empty: String
}
`;

const mutation = gql`
type Mutation {
_empty: String
}
`;

const executableSchema = makeExecutableSchema({
typeDefs: [query, mutation, authType, entityType, userType],
resolvers: merge(authResolvers, entityResolvers, userResolvers),
});

const authorizedByAllRoles = () =>
isAuthorizedByRole(new Set(["User", "Admin"]));
const authorizedByAdmin = () => isAuthorizedByRole(new Set(["Admin"]));

const graphQLMiddlewares = {
Query: {
entity: authorizedByAllRoles(),
entities: authorizedByAllRoles(),
userById: authorizedByAdmin(),
userByEmail: authorizedByAdmin(),
users: authorizedByAdmin(),
},
Mutation: {
createEntity: authorizedByAllRoles(),
updateEntity: authorizedByAllRoles(),
deleteEntity: authorizedByAllRoles(),
createUser: authorizedByAdmin(),
updateUser: authorizedByAdmin(),
deleteUserById: authorizedByAdmin(),
deleteUserByEmail: authorizedByAdmin(),
logout: isAuthorizedByUserId("userId"),
resetPassword: isAuthorizedByEmail("email"),
},
};

export default applyMiddleware(executableSchema, graphQLMiddlewares);

import { makeExecutableSchema, gql } from "apollo-server-express";
import { applyMiddleware } from "graphql-middleware";
import { merge } from "lodash";

import {
isAuthorizedByEmail,
isAuthorizedByRole,
isAuthorizedByUserId,
} from "../middlewares/auth";
import authResolvers from "./resolvers/authResolvers";
import authType from "./types/authType";
import entityResolvers from "./resolvers/entityResolvers";
import entityType from "./types/entityType";
import userResolvers from "./resolvers/userResolvers";
import userType from "./types/userType";

const query = gql`
type Query {
_empty: String
}
`;

const mutation = gql`
type Mutation {
_empty: String
}
`;

const executableSchema = makeExecutableSchema({
typeDefs: [query, mutation, authType, entityType, userType],
resolvers: merge(authResolvers, entityResolvers, userResolvers),
});

const authorizedByAllRoles = () =>
isAuthorizedByRole(new Set(["User", "Admin"]));
const authorizedByAdmin = () => isAuthorizedByRole(new Set(["Admin"]));

const graphQLMiddlewares = {
Query: {
entity: authorizedByAllRoles(),
entities: authorizedByAllRoles(),
userById: authorizedByAdmin(),
userByEmail: authorizedByAdmin(),
users: authorizedByAdmin(),
},
Mutation: {
createEntity: authorizedByAllRoles(),
updateEntity: authorizedByAllRoles(),
deleteEntity: authorizedByAllRoles(),
createUser: authorizedByAdmin(),
updateUser: authorizedByAdmin(),
deleteUserById: authorizedByAdmin(),
deleteUserByEmail: authorizedByAdmin(),
logout: isAuthorizedByUserId("userId"),
resetPassword: isAuthorizedByEmail("email"),
},
};

export default applyMiddleware(executableSchema, graphQLMiddlewares);
30 changes: 18 additions & 12 deletions backend/graphql/resolvers/authResolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import UserService from "../../services/implementations/userService";
import IAuthService from "../../services/interfaces/authService";
import IEmailService from "../../services/interfaces/emailService";
import IUserService from "../../services/interfaces/userService";
import { RegisterUserDTO } from "../../types";
import { AuthDTO, RegisterUserDTO } from "../../types";

const userService: IUserService = new UserService();
const emailService: IEmailService = new EmailService(nodemailerConfig);
Expand All @@ -22,30 +22,30 @@ const cookieOptions: CookieOptions = {
const authResolvers = {
Mutation: {
login: async (
_parent: any,
_parent: undefined,
{ email, password }: { email: string; password: string },
{ res }: { res: Response },
) => {
): Promise<Omit<AuthDTO, "refreshToken">> => {
const authDTO = await authService.generateToken(email, password);
const { refreshToken, ...rest } = authDTO;
res.cookie("refreshToken", refreshToken, cookieOptions);
return rest;
},
loginWithGoogle: async (
_parent: any,
_parent: undefined,
{ idToken }: { idToken: string },
{ res }: { res: Response },
) => {
): Promise<Omit<AuthDTO, "refreshToken">> => {
const authDTO = await authService.generateTokenOAuth(idToken);
const { refreshToken, ...rest } = authDTO;
res.cookie("refreshToken", refreshToken, cookieOptions);
return rest;
},
register: async (
_parent: any,
_parent: undefined,
{ user }: { user: RegisterUserDTO },
{ res }: { res: Response },
) => {
): Promise<Omit<AuthDTO, "refreshToken">> => {
await userService.createUser({ ...user, role: "User" });
const authDTO = await authService.generateToken(
user.email,
Expand All @@ -57,18 +57,24 @@ const authResolvers = {
return rest;
},
refresh: async (
_parent: any,
_args: any,
_parent: undefined,
_args: Record<string, undefined>,
{ req, res }: { req: Request; res: Response },
) => {
): Promise<string> => {
const token = await authService.renewToken(req.cookies.refreshToken);
res.cookie("refreshToken", token.refreshToken, cookieOptions);
return token.accessToken;
},
logout: async (_parent: any, { userId }: { userId: string }) => {
logout: async (
_parent: undefined,
{ userId }: { userId: string },
): Promise<void> => {
await authService.revokeTokens(userId);
},
resetPassword: async (_parent: any, { email }: { email: string }) => {
resetPassword: async (
_parent: undefined,
{ email }: { email: string },
): Promise<boolean> => {
await authService.resetPassword(email);
return true;
},
Expand Down
28 changes: 19 additions & 9 deletions backend/graphql/resolvers/entityResolvers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import fs from "fs";
/* eslint-disable-next-line import/no-extraneous-dependencies */
import { ReadStream } from "fs-capacitor";
import { FileUpload } from "graphql-upload";
import multer from "multer";
Expand Down Expand Up @@ -33,26 +34,32 @@ const writeFile = (readStream: ReadStream, filePath: string): Promise<void> => {

const entityResolvers = {
Query: {
entity: async (_req: any, { id }: { id: string }) => {
entity: async (
_req: undefined,
{ id }: { id: string },
): Promise<EntityResponseDTO> => {
return entityService.getEntity(id);
},
entities: async () => {
entities: async (): Promise<EntityResponseDTO[]> => {
return entityService.getEntities();
},
entitiesCSV: async () => {
entitiesCSV: async (): Promise<string> => {
const entities = await entityService.getEntities();
const csv = await generateCSV<EntityResponseDTO>({ data: entities });
return csv;
},
file: async (_req: any, { fileUUID }: { fileUUID: string }) => {
file: async (
_req: undefined,
{ fileUUID }: { fileUUID: string },
): Promise<string> => {
return fileStorageService.getFile(fileUUID);
},
},
Mutation: {
createEntity: async (
_req: any,
_req: undefined,
{ entity, file }: { entity: EntityRequestDTO; file: Promise<FileUpload> },
) => {
): Promise<EntityResponseDTO> => {
let filePath = "";
let fileContentType = "";
if (file) {
Expand Down Expand Up @@ -80,13 +87,13 @@ const entityResolvers = {
return newEntity;
},
updateEntity: async (
_req: any,
_req: undefined,
{
id,
entity,
file,
}: { id: string; entity: EntityRequestDTO; file: Promise<FileUpload> },
) => {
): Promise<EntityResponseDTO | null> => {
let filePath = "";
let fileContentType = "";
if (file) {
Expand All @@ -113,7 +120,10 @@ const entityResolvers = {
}
return updatedEntity;
},
deleteEntity: async (_req: any, { id }: { id: string }) => {
deleteEntity: async (
_req: undefined,
{ id }: { id: string },
): Promise<void> => {
return entityService.deleteEntity(id);
},
},
Expand Down
33 changes: 24 additions & 9 deletions backend/graphql/resolvers/userResolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,52 @@ const authService: IAuthService = new AuthService(userService, emailService);

const userResolvers = {
Query: {
userById: async (_parent: any, { id }: { id: string }) => {
userById: async (
_parent: undefined,
{ id }: { id: string },
): Promise<UserDTO> => {
return userService.getUserById(id);
},
userByEmail: async (_parent: any, { email }: { email: string }) => {
userByEmail: async (
_parent: undefined,
{ email }: { email: string },
): Promise<UserDTO> => {
return userService.getUserByEmail(email);
},
users: async () => {
users: async (): Promise<UserDTO[]> => {
return userService.getUsers();
},
usersCSV: async () => {
usersCSV: async (): Promise<string> => {
const users = await userService.getUsers();
const csv = await generateCSV<UserDTO>({ data: users });
return csv;
},
},
Mutation: {
createUser: async (_parent: any, { user }: { user: CreateUserDTO }) => {
createUser: async (
_parent: undefined,
{ user }: { user: CreateUserDTO },
): Promise<UserDTO> => {
const newUser = await userService.createUser(user);
await authService.sendEmailVerificationLink(newUser.email);
return newUser;
},
updateUser: async (
_parent: any,
_parent: undefined,
{ id, user }: { id: string; user: UpdateUserDTO },
) => {
): Promise<UserDTO> => {
return userService.updateUserById(id, user);
},
deleteUserById: async (_parent: any, { id }: { id: string }) => {
deleteUserById: async (
_parent: undefined,
{ id }: { id: string },
): Promise<void> => {
return userService.deleteUserById(id);
},
deleteUserByEmail: async (_parent: any, { email }: { email: string }) => {
deleteUserByEmail: async (
_parent: undefined,
{ email }: { email: string },
): Promise<void> => {
return userService.deleteUserByEmail(email);
},
},
Expand Down
Loading