Skip to content

Commit

Permalink
Use sequelize-typescript, process TS files with ts-loader or ts-node
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffreyATW committed May 19, 2023
1 parent 00497ef commit 77d3c73
Show file tree
Hide file tree
Showing 57 changed files with 985 additions and 715 deletions.
1 change: 1 addition & 0 deletions .mocharc.js
Expand Up @@ -3,4 +3,5 @@ module.exports = {
require: ["./test/setup"],
exit: true,
file: "./test/mocha-setup",
timeout: 4000,
};
2 changes: 2 additions & 0 deletions babel.config.js
Expand Up @@ -13,6 +13,8 @@ module.exports = {
plugins: [
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-transform-modules-commonjs",
// Decorators
["@babel/plugin-proposal-decorators", { version: "legacy" }],
],
presets: [
["@babel/preset-typescript", { allowDeclareFields: true }],
Expand Down
5 changes: 3 additions & 2 deletions global.d.ts
@@ -1,6 +1,6 @@
import { Action } from "redux";
import WebSocket from "ws";
import { Team, User as UserModel } from "./src/models";
import { Team, User as UserInterface } from "./src/interfaces";

declare global {
interface Window {
Expand All @@ -11,9 +11,10 @@ declare global {
broadcast: (teamId: number, data: Action) => void;
subdomain?: string;
team?: Team;
user?: UserModel;
user?: UserInterface;
wss?: Server;
}
export interface User extends UserInterface {}
}
}

Expand Down
13 changes: 10 additions & 3 deletions package.json
Expand Up @@ -67,13 +67,15 @@
"react-scroll": "^1.8.9",
"react-transition-group": "^4.4.5",
"redux": "^4.2.1",
"reflect-metadata": "^0.1.13",
"reselect": "^2.3.0",
"reserved-usernames": "^1.0.3",
"robust-websocket": "^0.2.1",
"rotating-file-stream": "^3.1.0",
"sendgrid": "^5.2.3",
"sequelize": "^6.29.0",
"sequelize-cli": "^6.6.0",
"sequelize-typescript": "^2.1.5",
"serialize-javascript": "^6.0.1",
"source-map-support": "^0.5.9",
"sqlite3": "^5.1.5",
Expand All @@ -86,6 +88,7 @@
"@babel/eslint-parser": "^7.19.1",
"@babel/node": "^7.20.7",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-decorators": "^7.21.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-modules-commonjs": "^7.20.11",
"@babel/plugin-transform-react-constant-elements": "^7.20.2",
Expand Down Expand Up @@ -115,13 +118,15 @@
"@types/method-override": "^0.0.32",
"@types/mocha": "^10.0.1",
"@types/morgan": "^1.9.4",
"@types/node": "^20.2.1",
"@types/node-fetch": "^2.6.2",
"@types/passport": "^1.0.11",
"@types/passport-google-oauth20": "^2.0.11",
"@types/passport-local": "^1.0.35",
"@types/proxyquire": "^1.3.28",
"@types/react-dom": "^18.2.4",
"@types/uuid": "^9.0.0",
"@types/validator": "^13.7.17",
"@types/webpack-env": "^1.18.0",
"@typescript-eslint/eslint-plugin": "^5.59.1",
"@typescript-eslint/parser": "^5.59.1",
Expand All @@ -130,6 +135,7 @@
"babel-loader": "^9.1.0",
"babel-plugin-istanbul": "^6.1.1",
"babel-plugin-transform-react-remove-prop-types": "^0.4.18",
"babel-plugin-transform-typescript-metadata": "^0.3.2",
"browser-sync": "2.29.1",
"chai": "4.3.7",
"chai-jsdom": "^0.2.3",
Expand Down Expand Up @@ -187,6 +193,7 @@
"supertest": "^6.3.3",
"svg-url-loader": "^8.0.0",
"ts-loader": "^9.4.2",
"ts-node": "^10.9.1",
"typescript": "^4.9.5",
"url-loader": "^4.1.1",
"webpack": "^5.76.0",
Expand Down Expand Up @@ -222,8 +229,8 @@
"fix-js": "npm run lint-js -- --fix",
"fix-css": "npm run lint-css -- --fix",
"fix": "npm run fix-js && npm run fix-css",
"test-file": "mocha",
"test-file-ci": "mocha --reporter mocha-junit-reporter",
"test-file": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha",
"test-file-ci": "npm run test-file --reporter mocha-junit-reporter",
"test": "npm run test-file \"./src/**/*.test.{js,ts}\"",
"test-ci": "npm run test-file-ci \"./src/**/*.test.{js,ts}\"",
"test-watch": "npm run test --watch --notify",
Expand Down Expand Up @@ -257,4 +264,4 @@
"prepare": "husky install"
},
"packageManager": "yarn@3.5.1"
}
}
4 changes: 2 additions & 2 deletions src/actions/restaurants.ts
@@ -1,8 +1,8 @@
import { ThunkAction } from "@reduxjs/toolkit";
import { getDecision } from "../selectors/decisions";
import { getNewlyAdded } from "../selectors/listUi";
import { getCurrentUser } from "../selectors/user";
import { processResponse, credentials, jsonHeaders } from "../core/ApiClient";
import { ThunkAction } from "@reduxjs/toolkit";
import { Action, Restaurant, State, Tag, Vote } from "../interfaces";

export function sortRestaurants(): ThunkAction<void, State, unknown, Action> {
Expand All @@ -12,7 +12,7 @@ export function sortRestaurants(): ThunkAction<void, State, unknown, Action> {
type: "SORT_RESTAURANTS",
decision: getDecision(state),
newlyAdded: getNewlyAdded(state),
user: getCurrentUser(state),
user: getCurrentUser(state)!,
});
};
}
Expand Down
2 changes: 1 addition & 1 deletion src/actions/tags.ts
Expand Up @@ -85,6 +85,6 @@ export function removeTag(
method: "delete",
})
.then((response) => processResponse(response, dispatch))
.then(() => dispatch(tagDeleted(id, getState().user.id)));
.then(() => dispatch(tagDeleted(id, getState().user!.id)));
};
}
4 changes: 2 additions & 2 deletions src/actions/users.ts
Expand Up @@ -92,7 +92,7 @@ export function removeUser(
return (dispatch, getState) => {
const state = getState();
let isSelf = false;
if (getCurrentUser(state).id === id) {
if (getCurrentUser(state)!.id === id) {
isSelf = true;
}
dispatch(deleteUser(id, team, isSelf));
Expand Down Expand Up @@ -183,7 +183,7 @@ export function changeUserRole(
const state = getState();
const team = state.team;
let isSelf = false;
if (getCurrentUser(state).id === id) {
if (getCurrentUser(state)!.id === id) {
isSelf = true;
}
dispatch(patchUser(id, type, team, isSelf));
Expand Down
2 changes: 1 addition & 1 deletion src/api/helpers/checkTeamRole.ts
Expand Up @@ -2,7 +2,7 @@ import { RequestHandler } from "express";
import { RoleType } from "src/interfaces";
import hasRole from "../../helpers/hasRole";

export default (role: RoleType): RequestHandler =>
export default (role?: RoleType): RequestHandler =>
(req, res, next) => {
if (hasRole(req.user, req.team, role)) {
next();
Expand Down
46 changes: 26 additions & 20 deletions src/api/main/teams.js → src/api/main/teams.ts
@@ -1,7 +1,7 @@
import { Router } from "express";
import { RequestHandler, Response, Router } from "express";
import cors from "cors";
import { bsHost } from "../../config";
import { Team, Role, User } from "../../models";
import { Team, Role, User } from "../../db";
import reservedTeamSlugs from "../../constants/reservedTeamSlugs";
import { TEAM_LIMIT, TEAM_SLUG_REGEX } from "../../constants";
import generateUrl from "../../helpers/generateUrl";
Expand All @@ -11,23 +11,27 @@ import checkTeamRole from "../helpers/checkTeamRole";
import corsOptionsDelegate from "../helpers/corsOptionsDelegate";
import loggedIn from "../helpers/loggedIn";

const getTeam = async (req, res, next) => {
const getTeam: RequestHandler = async (req, res, next) => {
const id = parseInt(req.params.id, 10);
const team = await Team.findOne({ where: { id } });
req.team = team; // eslint-disable-line no-param-reassign
next();
if (team) {
req.team = team; // eslint-disable-line no-param-reassign
next();
} else {
next(new Error("Team doesn't exist"));
}
};

const error409 = (res, message) =>
const error409 = (res: Response, message: string) =>
res.status(409).json({ error: true, data: { message } });

export default () => {
const router = new Router();
const router = Router();

return router
.get("/", loggedIn, async (req, res, next) => {
try {
const teams = await Team.findAllForUser(req.user);
const teams = await Team.findAllForUser(req.user!);

res.status(200).json({ error: false, data: teams });
} catch (err) {
Expand All @@ -38,8 +42,8 @@ export default () => {
const { address, lat, lng, name, slug } = req.body;
const message409 = "Could not create new team. It might already exist.";

if (!req.user.superuser) {
const roles = await req.user.getRoles();
if (!req.user!.superuser) {
const roles = await req.user!.$get("roles");
if (roles.length >= TEAM_LIMIT) {
return res.status(403).json({
error: true,
Expand Down Expand Up @@ -71,7 +75,7 @@ export default () => {
slug,
roles: [
{
userId: req.user.id,
userId: req.user!.id,
type: "owner",
},
],
Expand All @@ -81,7 +85,7 @@ export default () => {

const json = obj.toJSON();
return res.status(201).send({ error: false, data: json });
} catch (err) {
} catch (err: any) {
if (err.name === "SequelizeUniqueConstraintError") {
return error409(res, message409);
}
Expand All @@ -97,7 +101,7 @@ export default () => {
checkTeamRole("owner"),
async (req, res, next) => {
try {
await req.team.destroy();
await req.team!.destroy();
return res.status(204).send();
} catch (err) {
return next(err);
Expand Down Expand Up @@ -146,7 +150,9 @@ export default () => {
);
}

const filteredPayload = {};
const filteredPayload: {
[key in (typeof allowedFields)[number]["type"]]: string;
} = {};

allowedFields.forEach((f) => {
const value = req.body[f.name];
Expand All @@ -159,7 +165,7 @@ export default () => {

if (fieldCount) {
try {
const oldSlug = req.team.get("slug");
const oldSlug = req.team!.get("slug");

if (
oldSlug !== filteredPayload.slug &&
Expand All @@ -168,13 +174,13 @@ export default () => {
return error409(res, message409);
}

await req.team.update(filteredPayload);
await req.team!.update(filteredPayload);

if (filteredPayload.slug && oldSlug !== filteredPayload.slug) {
req.flash("success", "Team URL has been updated.");
return req.session.save(async () => {
const teamRoles = await Role.findAll({
where: { teamId: req.team.get("id") },
where: { teamId: req.team!.get("id") },
});
const userIds = teamRoles.map((r) => r.get("userId"));
const recipients = await User.findAll({
Expand All @@ -185,10 +191,10 @@ export default () => {
transporter
.sendMail({
recipients,
subject: `${req.team.get("name")}'s team URL has changed`,
subject: `${req.team!.get("name")}'s team URL has changed`,
text: `Hi there!
${req.user.get("name")} has changed the URL of the ${req.team.get(
${req.user!.get("name")} has changed the URL of the ${req.team!.get(
"name"
)} team on Lunch.
Expand All @@ -206,7 +212,7 @@ Happy Lunching!`,
});
}
return res.status(200).json({ error: false, data: req.team });
} catch (err) {
} catch (err: any) {
if (err.name === "SequelizeUniqueConstraintError") {
return error409(res, message409);
}
Expand Down
16 changes: 9 additions & 7 deletions src/api/main/user.js → src/api/main/user.ts
@@ -1,11 +1,11 @@
import { Router } from "express";
import getPasswordError from "../../helpers/getPasswordError";
import getUserPasswordUpdates from "../../helpers/getUserPasswordUpdates";
import { User } from "../../models";
import { User } from "../../db";
import loggedIn from "../helpers/loggedIn";

export default () => {
const router = new Router();
const router = Router();

return router.patch("/", loggedIn, async (req, res, next) => {
let fieldCount = 0;
Expand All @@ -25,7 +25,9 @@ export default () => {
},
];

const filteredPayload = {};
const filteredPayload: {
[key in (typeof allowedFields)[number]["type"]]: string | boolean;
} = {};

allowedFields.forEach((f) => {
const value = req.body[f.name];
Expand Down Expand Up @@ -53,17 +55,17 @@ export default () => {
delete filteredPayload.password;
}
if (filteredPayload.name) {
if (req.user.get("name") !== filteredPayload.name) {
if (req.user!.get("name") !== filteredPayload.name) {
filteredPayload.namedChanged = true;
}
}
await req.user.update(filteredPayload);
await req.user!.update(filteredPayload);

// get user again because now req.user contains password fields
const user = await User.getSessionUser(req.user.get("id"));
const user = await User.getSessionUser(req.user!.id);

return res.status(200).json({ error: false, data: user });
} catch (err) {
} catch (err: any) {
if (err.name === "SequelizeUniqueConstraintError") {
return res.status(422).json({
error: true,
Expand Down

0 comments on commit 77d3c73

Please sign in to comment.