Skip to content

Commit

Permalink
Merge pull request #338 from mikefranze/kyesly-integration
Browse files Browse the repository at this point in the history
Kyesly integration
  • Loading branch information
mikefranze authored Nov 4, 2023
2 parents b8346a8 + a4e4377 commit afb9ba3
Show file tree
Hide file tree
Showing 16 changed files with 948 additions and 609 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ COPY --chown=node:node --from=build /usr/src/app/domain_model domain_model
COPY --chown=node:node --from=build /usr/src/app/frontend/build /usr/src/app/frontend/build
COPY --chown=node:node --from=build /usr/src/app/backend/build /usr/src/app/backend/build
COPY --chown=node:node --from=build /usr/src/app/backend/node_modules /usr/src/app/backend/node_modules
CMD ["dumb-init", "node", "backend/build/backend/src/index.js"]

ENTRYPOINT ["dumb-init", "--"]
CMD ["npm", "run", "start"]
EXPOSE 5000
299 changes: 240 additions & 59 deletions backend/package-lock.json

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"test": "jest --forceExit --detectOpenHandles",
"start": "npm run-script build && node ./build/backend/src/index.js",
"dev": "nodemon ./src/index.ts",
"build": "tsc --project ./"
"build": "tsc --project ./",
"migrate:latest": "node ./build/backend/src/migrate-to-latest.js"
},
"keywords": [],
"author": "",
Expand All @@ -18,9 +19,10 @@
"@types/cookie-parser": "^1.4.2",
"@types/cors": "^2.8.12",
"@types/express": "^4.17.13",
"@types/jest": "^27.4.1",
"@types/luxon": "^3.3.0",
"@types/node": "^16.11.26",
"@types/jest": "^27.4.1",
"@types/pg": "^8.10.2",
"aws-sdk": "^2.1277.0",
"axios": "^0.24.0",
"cookie-parser": "^1.4.6",
Expand All @@ -31,6 +33,7 @@
"express-async-handler": "^1.2.0",
"fraction.js": "^4.2.0",
"jsonwebtoken": "^9.0.0",
"kysely": "^0.25.0",
"luxon": "^3.3.0",
"multer": "^1.4.5-lts.1",
"node-fetch": "^3.2.3",
Expand Down
58 changes: 58 additions & 0 deletions backend/src/Migrations/2023_07_03_Initial.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Kysely } from 'kysely'

export async function up(db: Kysely<any>): Promise<void> {
await db.schema
.createTable('electionDB')
.addColumn('election_id', 'varchar', (col) => col.primaryKey())
.addColumn('title', 'varchar')
.addColumn('description', 'text')
.addColumn('frontend_url', 'varchar')
.addColumn('start_time', 'varchar')
.addColumn('end_time', 'varchar')
.addColumn('support_email', 'varchar')
.addColumn('owner_id', 'varchar')
.addColumn('audit_ids', 'json')
.addColumn('admin_ids', 'json')
.addColumn('credential_ids', 'json')
.addColumn('state', 'varchar')
.addColumn('races', 'json', (col) => col.notNull())
.addColumn('settings', 'json')
.addColumn('auth_key', 'varchar')
.execute()

await db.schema
.createTable('electionRollDB')
.addColumn('voter_id', 'varchar', (col) => col.primaryKey().notNull())
.addColumn('election_id', 'varchar', (col) => col.notNull())
.addColumn('email', 'varchar')
.addColumn('submitted', 'boolean', (col) => col.notNull())
.addColumn('ballot_id', 'varchar')
.addColumn('ip_address', 'varchar')
.addColumn('address', 'varchar')
.addColumn('state', 'varchar', (col) => col.notNull())
.addColumn('history', 'json')
.addColumn('registration', 'json')
.addColumn('precinct', 'varchar')
.addColumn('email_data', 'json')
.execute()

await db.schema
.createTable('ballotDB')
.addColumn('ballot_id', 'varchar', (col) => col.primaryKey().notNull())
.addColumn('election_id', 'varchar')
.addColumn('user_id', 'varchar')
.addColumn('status', 'varchar')
.addColumn('date_submitted', 'varchar')
.addColumn('ip_address', 'varchar')
.addColumn('votes', 'json', (col) => col.notNull())
.addColumn('history', 'json')
.addColumn('precinct', 'varchar')
.execute()
}

export async function down(db: Kysely<any>): Promise<void> {
await db.schema.dropTable('electionDB').execute()
await db.schema.dropTable('electionRollDB').execute()
await db.schema.dropTable('ballotDB').execute()
}

167 changes: 54 additions & 113 deletions backend/src/Models/Ballots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,146 +3,87 @@ import { Uid } from '../../../domain_model/Uid';
import { ILoggingContext } from '../Services/Logging/ILogger';
import Logger from '../Services/Logging/Logger';
import { IBallotStore } from './IBallotStore';
const className = 'BallotsDB';
import { Kysely, sql } from 'kysely';
import { Database } from './Database';
import { InternalServerError } from '@curveball/http-errors';

export default class BallotsDB implements IBallotStore {
const tableName = 'ballotDB';

export default class BallotsDB implements IBallotStore {
_postgresClient;
_tableName: string;
_tableName: string = tableName;

constructor(postgresClient:any) {
this._tableName = "ballotDB";
constructor(postgresClient: Kysely<Database>) {
this._postgresClient = postgresClient;
this.init();
this.init()
}

async init(): Promise<IBallotStore> {
var appInitContext = Logger.createContext("appInit");
Logger.debug(appInitContext, "BallotsDB.init");
//await this.dropTable(appInitContext);
var query = `
CREATE TABLE IF NOT EXISTS ${this._tableName} (
ballot_id VARCHAR PRIMARY KEY,
election_id VARCHAR,
user_id VARCHAR,
status VARCHAR,
date_submitted VARCHAR,
ip_address VARCHAR,
votes json NOT NULL,
history json,
precinct VARCHAR
);
`;
Logger.debug(appInitContext, query);
var p = this._postgresClient.query(query);
return p.then((_: any) => {
//This will add the new field to the live DB in prod. Once that's done we can remove this
var historyQuery = `
ALTER TABLE ${this._tableName} ADD COLUMN IF NOT EXISTS precinct VARCHAR
`;
return this._postgresClient.query(historyQuery).catch((err:any) => {
Logger.error(appInitContext, "err adding precinct column to DB: " + err.message);
return err;
});
}).then((_:any)=> {
return this;
});
return this;
}

async dropTable(ctx:ILoggingContext):Promise<void>{
var query = `DROP TABLE IF EXISTS ${this._tableName};`;
var p = this._postgresClient.query({
text: query,
});
return p.then((_: any) => {
Logger.debug(ctx, `Dropped it (like its hot)`);
});
async dropTable(ctx: ILoggingContext): Promise<void> {
Logger.debug(ctx, `${tableName}.dropTable`);
return this._postgresClient.schema.dropTable(tableName).execute()
}

submitBallot(ballot: Ballot, ctx:ILoggingContext, reason:string): Promise<Ballot> {
Logger.debug(ctx, `${className}.submit`, ballot);
var sqlString = `INSERT INTO ${this._tableName} (ballot_id,election_id,user_id,status,date_submitted,ip_address,votes,history,precinct)
VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING ballot_id;`;
Logger.debug(ctx, sqlString);
var p = this._postgresClient.query({
rowMode: 'array',
text: sqlString,
values: [
ballot.ballot_id,
ballot.election_id,
ballot.user_id,
ballot.status,
ballot.date_submitted,
ballot.ip_address,
JSON.stringify(ballot.votes),
JSON.stringify(ballot.history),
ballot.precinct]
});
submitBallot(ballot: Ballot, ctx: ILoggingContext, reason: string): Promise<Ballot> {
Logger.debug(ctx, `${tableName}.submit`, ballot);

return p.then((res: any) => {
Logger.debug(ctx, `set response rows:`, res);
ballot.ballot_id = res.rows[0][0];
Logger.state(ctx, `Ballot submitted`, { ballot: ballot, reason: reason});
return ballot;
});
return this._postgresClient
.insertInto(tableName)
.values(ballot)
.returningAll()
.executeTakeFirstOrThrow()
.then((ballot) => {
Logger.state(ctx, `Ballot submitted`, { ballot: ballot, reason: reason });
return ballot;
});
}

getBallotByID(ballot_id: string, ctx:ILoggingContext): Promise<Ballot | null> {
Logger.debug(ctx, `${className}.getBallotByID ${ballot_id}`);
var sqlString = `SELECT * FROM ${this._tableName} WHERE ballot_id = $1`;
Logger.debug(ctx, sqlString);
getBallotByID(ballot_id: string, ctx: ILoggingContext): Promise<Ballot | null> {
Logger.debug(ctx, `${tableName}.getBallotByID ${ballot_id}`);

var p = this._postgresClient.query({
text: sqlString,
values: [ballot_id]
});
return p.then((response: any) => {
var rows = response.rows;
if (rows.length == 0) {
Logger.debug(ctx, `.get null`);
return this._postgresClient
.selectFrom(tableName)
.selectAll()
.where('ballot_id', '=', ballot_id)
.executeTakeFirstOrThrow()
.catch((reason: any) => {
Logger.debug(ctx, `${tableName}.get null`, reason);
return null;
}
return rows[0] as Ballot;
});
})
}


getBallotsByElectionID(election_id: string, ctx:ILoggingContext): Promise<Ballot[] | null> {
Logger.debug(ctx, `${className}.getBallotsByElectionID ${election_id}`);
var sqlString = `SELECT * FROM ${this._tableName} WHERE election_id = $1`;
Logger.debug(ctx, sqlString);
getBallotsByElectionID(election_id: string, ctx: ILoggingContext): Promise<Ballot[] | null> {
Logger.debug(ctx, `${tableName}.getBallotsByElectionID ${election_id}`);

var p = this._postgresClient.query({
text: sqlString,
values: [election_id]
});
return p.then((response: any) => {
var rows = response.rows;
console.log(rows[0])
if (rows.length == 0) {
Logger.debug(ctx, `.get null`);
return [] as Ballot[];
}
return rows
});
return this._postgresClient
.selectFrom(tableName)
.selectAll()
.where('election_id', '=', election_id)
.execute()
}

delete(ballot_id: Uid, ctx:ILoggingContext, reason:string): Promise<boolean> {
Logger.debug(ctx, `${className}.delete ${ballot_id}`);
delete(ballot_id: Uid, ctx: ILoggingContext, reason: string): Promise<boolean> {
Logger.debug(ctx, `${tableName}.delete ${ballot_id}`);
var sqlString = `DELETE FROM ${this._tableName} WHERE ballot_id = $1`;
Logger.debug(ctx, sqlString);

var p = this._postgresClient.query({
rowMode: 'array',
text: sqlString,
values: [ballot_id]
});
return p.then((response: any) => {
if (response.rowCount == 1) {
Logger.state(ctx, `Ballot ${ballot_id} deleted:`, {ballotId: ballot_id, reason: reason });
return true;
}
return false;
});
return this._postgresClient
.deleteFrom(tableName)
.where('ballot_id', '=', ballot_id)
.returningAll()
.executeTakeFirst()
.then((ballot) => {
if (ballot) {
return true
} else {
return false
}
})
}
}
9 changes: 9 additions & 0 deletions backend/src/Models/Database.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Ballot } from "../../../domain_model/Ballot";
import { Election } from "../../../domain_model/Election";
import { ElectionRoll } from "../../../domain_model/ElectionRoll";

export interface Database {
electionDB: Election,
electionRollDB: ElectionRoll
ballotDB: Ballot
}
Loading

0 comments on commit afb9ba3

Please sign in to comment.