Skip to content
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
1 change: 1 addition & 0 deletions .mocharc.js
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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": "[email protected]"
}
}
4 changes: 2 additions & 2 deletions src/actions/restaurants.ts
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Loading