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

Implement use of .svelte-kit with hot-reloading #540

Merged
merged 1 commit into from
Mar 28, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ module.exports = {
},
],
},
settings: {
'svelte3/typescript': () => require('typescript')
},
env: {
es6: true,
node: true,
Expand Down
7 changes: 4 additions & 3 deletions app.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import express, { Request, Response, NextFunction } from 'express';
import express from 'express';
import type { Request, Response, NextFunction } from 'express';
import mongoose from 'mongoose';
import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser';
Expand All @@ -13,7 +14,7 @@ import raven from 'raven';
import router from './app/routes';
import User from './app/models/user';
import env from './env';
import { HTTPError } from './app/errors';
import type { HTTPError } from './app/errors';
import path from 'path';
import { fileURLToPath } from 'url';

Expand Down Expand Up @@ -47,7 +48,7 @@ if (['development', 'protractor'].includes(env.NODE_ENV)) {
const webpackMiddleware = await import('webpack-dev-middleware');
// eslint-disable-next-line
// @ts-ignore
const config = await import('./webpack.config.js');
const config = await import('./webpack.config.ts');

app.use(
webpackMiddleware.default(webpack.default(config.default), {
Expand Down
28 changes: 14 additions & 14 deletions app/algorithms/normal.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import isEmpty from 'lodash/isEmpty';
import { Status, Vote, Alternative, ElectionResult, Count } from './types';
import { PopulatedVote, AlternativeType } from '../../app/types/types';
import type { AlternativeType, PopulatedVote } from '../types/types';
import type { Vote, Alternative, ElectionResult, Count } from './types';
import { Status } from './types';

/**
* @param votes - All votes for the election
Expand Down Expand Up @@ -65,26 +66,25 @@ const calculateWinnerUsingNormal = (
const thr = winningThreshold(votes, useStrict);

// Winner key
const maxKey: string = Object.keys(count).reduce((a, b) =>
const maxKey = Object.keys(count).reduce((a, b) =>
count[a] > count[b] ? a : b
);

// Check if we can call the vote Resolved based on
const status = count[maxKey] >= thr ? Status.resolved : Status.unresolved;

// Create winner alternative from maxKey
const winner =
count[maxKey] >= thr
? {
...alternatives.find((a) => a.description === maxKey),
count: count[maxKey],
}
: undefined;
let status: Status = Status.unresolved;
let winner: Alternative = undefined;
if (count[maxKey] >= thr) {
winner = {
...alternatives.find((a) => a.description === maxKey),
count: count[maxKey],
};
status = Status.resolved;
}

return {
result: {
status,
winners: winner ? [winner] : undefined,
winners: winner ? [winner] : [],
},
thr,
seats,
Expand Down
5 changes: 3 additions & 2 deletions app/algorithms/stv.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import cloneDeep from 'lodash/cloneDeep';
import { Status, Vote, Alternative, ElectionResult, Count } from './types';
import { PopulatedVote, AlternativeType } from '../../app/types/types';
import { Status } from './types';
import type { Vote, Alternative, ElectionResult, Count } from './types';
import type { PopulatedVote, AlternativeType } from '../../app/types/types';

enum Action {
iteration = 'ITERATION',
Expand Down
3 changes: 2 additions & 1 deletion app/algorithms/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { STVEvent } from './stv';
import type { STVEvent } from './stv';

export type Count = { [key: string]: number };

export type Alternative = {
_id: string;
description: string;
election: string;
count?: number;
};

export type Vote = {
Expand Down
5 changes: 2 additions & 3 deletions app/controllers/alternative.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ import type { RequestHandler } from 'express';
import mongoose from 'mongoose';
import Alternative from '../models/alternative';
import errors from '../errors';
import type { ReqWithElection } from './election';

export const list: RequestHandler = async (req: ReqWithElection, res) => {
export const list: RequestHandler = async (req, res) => {
const election = await req.election.populate('alternatives');
return res.json(election.alternatives);
};

export const create: RequestHandler = async (req: ReqWithElection, res) => {
export const create: RequestHandler = async (req, res) => {
try {
const election = req.election;
await election.populate('alternatives');
Expand Down
93 changes: 40 additions & 53 deletions app/controllers/election.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import type {
RequestParamHandler,
Request,
Response,
RequestHandler,
} from 'express';
import mongoose, { Types, HydratedDocument } from 'mongoose';
import type { RequestParamHandler, RequestHandler } from 'express';
import mongoose, { type HydratedDocument, Types } from 'mongoose';
import Election from '../models/election';
import User from '../models/user';
import Alternative from '../models/alternative';
Expand All @@ -13,18 +8,10 @@ import app from '../../app';
import type { Server } from 'socket.io';
import type {
ElectionType,
IElectionMethods,
AlternativeType,
IElectionMethods,
} from '../types/types';

export interface ReqWithElection extends Request {
election: HydratedDocument<ElectionType, IElectionMethods>;
}

export interface TypedRequestBody<T> extends Request {
body: T;
}

type CreateElection = Pick<
ElectionType,
'title' | 'description' | 'seats' | 'type' | 'useStrict' | 'physical'
Expand All @@ -35,12 +22,7 @@ type CreateElection = Pick<
}[];
};

export const load: RequestParamHandler = (
req: ReqWithElection,
res,
next,
electionId: string
) =>
export const load: RequestParamHandler = (req, res, next, electionId) =>
Election.findById(electionId)
.then((election) => {
if (!election) throw new errors.NotFoundError('election');
Expand All @@ -54,10 +36,7 @@ export const load: RequestParamHandler = (
throw err;
});

export const retrieveActive = (
req: ReqWithElection,
res: Response
): Promise<Response> =>
export const retrieveActive: RequestHandler = (req, res) =>
Election.findOne({
active: true,
hasVotedUsers: { $ne: new Types.ObjectId(req.user._id) },
Expand Down Expand Up @@ -97,10 +76,11 @@ export const retrieveActive = (
return res.status(200).json(election);
});

export const create = async (
req: TypedRequestBody<CreateElection>,
res: Response
): Promise<Response<ElectionType>> => {
export const create: RequestHandler<
unknown,
ElectionType,
CreateElection
> = async (req, res) => {
try {
const election = await Election.create({
title: req.body.title,
Expand Down Expand Up @@ -132,59 +112,64 @@ export const create = async (
}
};

export const list = (
req: Request,
res: Response
): Promise<Response<ElectionType[]>> =>
export const list: RequestHandler<unknown, ElectionType[]> = (req, res) =>
Election.find()
.populate('alternatives')
.exec()
.then((elections) => res.status(200).json(elections));

export const retrieve = async (
req: ReqWithElection,
res: Response
): Promise<Response<ElectionType>> => {
export const retrieve: RequestHandler<unknown, ElectionType> = async (
req,
res
) => {
if (!req.election) throw new errors.NotFoundError('election');

await req.election.populate('alternatives');

return res.status(200).json(req.election);
};

const setElectionStatus = (
req: ReqWithElection,
res: Response,
election: HydratedDocument<ElectionType, IElectionMethods>,
active: boolean
) => {
req.election.active = active;
return req.election.save();
election.active = active;
return election.save();
};

export const activate = async (
req: ReqWithElection,
res: Response
): Promise<Response> => {
export const activate: RequestHandler = async (req, res) => {
if (!req.election) throw new errors.NotFoundError('election');

const otherActiveElection = await Election.findOne({ active: true });
if (otherActiveElection) {
throw new errors.AlreadyActiveElectionError();
}
return setElectionStatus(req, res, true).then((election) => {
return setElectionStatus(req.election, true).then((election) => {
const io: Server = app.get('io');
io.emit('election');
return res.status(200).json(election);
});
};

export const deactivate: RequestHandler = (req: ReqWithElection, res) =>
setElectionStatus(req, res, false).then((election) => {
export const deactivate: RequestHandler = (req, res) => {
if (!req.election) throw new errors.NotFoundError('election');

return setElectionStatus(req.election, false).then((election) => {
const io: Server = app.get('io');
io.emit('election');
res.status(200).json(election);
});
};

export const elect: RequestHandler = (req: ReqWithElection, res) =>
req.election.elect().then((result) => res.json(result));
export const elect: RequestHandler = (req, res) => {
if (!req.election) throw new errors.NotFoundError('election');

return req.election.elect().then((result) => res.json(result));
};

export const deleteElection: RequestHandler = (req, res) => {
if (!req.election) throw new errors.NotFoundError('election');

export const deleteElection: RequestHandler = (req: ReqWithElection, res) => {
if (req.election.active) {
throw new errors.ActiveElectionError('Cannot delete an active election.');
}
Expand All @@ -197,7 +182,9 @@ export const deleteElection: RequestHandler = (req: ReqWithElection, res) => {
);
};

export const count: RequestHandler = (req: ReqWithElection, res) => {
export const count: RequestHandler = (req, res) => {
if (!req.election) throw new errors.NotFoundError('election');

res.json({
users: req.election.hasVotedUsers.length,
});
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { badRequestError, duplicateError } from '../errors/error-checks';
import crypto from 'crypto';
import { mailHandler, MailAction } from '../digital/mail';
import short from 'short-uuid';
import { RequestHandler } from 'express';
import { UserType } from '../types/types';
import type { RequestHandler } from 'express';
import type { UserType } from '../types/types';

export const count: RequestHandler = async (req, res) => {
const query: mongoose.FilterQuery<UserType> = {
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/vote.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { RequestHandler } from 'express';
import Client from 'ioredis';
import Redlock, { ExecutionError } from 'redlock';
import Redlock from 'redlock';

import Election from '../models/election';
import Vote from '../models/vote';
Expand Down
2 changes: 1 addition & 1 deletion app/digital/mail.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import nodemailer, { Transporter } from 'nodemailer';
import nodemailer, { type Transporter } from 'nodemailer';
import fs from 'fs';
import path from 'path';
import handlebars from 'handlebars';
Expand Down
2 changes: 1 addition & 1 deletion app/errors/error-checks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HTTPError } from './index';
import type { HTTPError } from './index';

export const duplicateError = (err: HTTPError): boolean =>
err.code === 11000 || err.code === 11001;
Expand Down
6 changes: 3 additions & 3 deletions app/errors/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Response } from 'express';
import { IAlternative, IElection } from '../types/types';
import mongoose from 'mongoose';
import type { Response } from 'express';
import type { IAlternative, IElection } from '../types/types';
import type mongoose from 'mongoose';

export class HTTPError extends Error {
status: number;
Expand Down
2 changes: 1 addition & 1 deletion app/models/alternative.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import mongoose, { Schema } from 'mongoose';
import { AlternativeType, AlternativeModel } from '../types/types';
import type { AlternativeType, AlternativeModel } from '../types/types';

const alternativeSchema = new Schema<AlternativeType, AlternativeModel>({
description: {
Expand Down
8 changes: 4 additions & 4 deletions app/models/election.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import errors from '../errors';
import mongoose, {
Schema,
Types,
HydratedDocument,
HydratedDocumentFromSchema,
type HydratedDocument,
type HydratedDocumentFromSchema,
} from 'mongoose';
import Vote from './vote';
import calculateWinnerUsingNormal from '../algorithms/normal';
import calculateWinnerUsingSTV from '../algorithms/stv';
import crypto from 'crypto';
import {
ElectionSystems,
import { ElectionSystems } from '../types/types';
import type {
AlternativeType,
IElectionMethods,
ElectionModel,
Expand Down
2 changes: 1 addition & 1 deletion app/models/register.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import mongoose, { Schema } from 'mongoose';
import { RegisterType } from '../types/types';
import type { RegisterType } from '../types/types';

const registerSchema = new Schema<RegisterType>({
identifier: {
Expand Down
4 changes: 2 additions & 2 deletions app/models/user.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import _ from 'lodash';
import bcrypt from 'bcryptjs';
import mongoose, { Schema, HydratedDocumentFromSchema } from 'mongoose';
import mongoose, { Schema, type HydratedDocumentFromSchema } from 'mongoose';
import errors from '../errors';
import { UserType, UserModel, IUserMethods } from '../types/types';
import type { UserType, UserModel, IUserMethods } from '../types/types';

export const userSchema = new Schema<UserType, UserModel, IUserMethods>({
username: {
Expand Down
2 changes: 1 addition & 1 deletion app/models/vote.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import mongoose, { Schema } from 'mongoose';
import { VoteType } from '../types/types';
import type { VoteType } from '../types/types';

const voteSchema = new Schema<VoteType>({
hash: {
Expand Down
2 changes: 1 addition & 1 deletion app/routes/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Request, Response, NextFunction } from 'express';
import type { Request, Response, NextFunction } from 'express';
import routerFactory from 'express-promise-router';
const router = routerFactory();
import electionRoutes from './election';
Expand Down