Skip to content
Draft
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
36 changes: 26 additions & 10 deletions lib/services/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,28 @@ import * as config from '../config.js';

const googleAuthClient = new OAuth2Client();

type UserRole = 'root' | 'god' | 'admin' | 'write' | 'read' | 'doorman';

export type User = {
id: string;
username: string;
displayName: string;
role: string;
subClaim: string;
role: UserRole;
subClaim: string | null;
};

type UserRow = {
id: string;
username: string;
displayName: string;
role: UserRole;
status: string;
created: Date;
updated: Date;
};

type RefreshTokenRow = {
userId: string;
};

class AuthServiceError extends Error {
Expand Down Expand Up @@ -211,9 +227,9 @@ export async function refreshAccessToken(refreshToken: string, {userAgent, ip}:
throw new AuthServiceError('Failed to query for user', 'DB_ERROR', e);
}

let refreshTokenData;
let refreshTokenData: RefreshTokenRow | undefined;
try {
[refreshTokenData] = await sql`
[refreshTokenData] = await sql<RefreshTokenRow[]>`
SELECT user_id
FROM refresh_tokens
WHERE id = ${jti}
Expand Down Expand Up @@ -255,10 +271,10 @@ export function checkScope(userRole: string, scopeRequired: string) {
return ~userLevel && userLevel <= roles.indexOf(scopeRequired);
}

export async function getUsers() {
let users;
export async function getUsers(): Promise<UserRow[]> {
let users: UserRow[];
try {
users = await sql`
users = await sql<UserRow[]>`
SELECT id, username, display_name, role, status, created, updated
FROM users
`;
Expand All @@ -269,10 +285,10 @@ export async function getUsers() {
return users;
}

export async function getUser(id: string) {
let user;
export async function getUser(id: string): Promise<UserRow> {
let user: UserRow | undefined;
try {
[user] = await sql`
[user] = await sql<UserRow[]>`
SELECT id, username, display_name, role, status, created, updated
FROM users
WHERE id = ${id}
Expand Down
55 changes: 41 additions & 14 deletions lib/services/customers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class CustomerServiceError extends Error {
code: string;
context?: unknown;

constructor(message = 'An unknown error occured', code = 'UNKNOWN', context) {
constructor(message = 'An unknown error occured', code = 'UNKNOWN', context?: unknown) {
super(message);

this.name = this.constructor.name;
Expand All @@ -21,6 +21,33 @@ export class CustomerServiceError extends Error {
}
}

export type Customer = {
id: string;
email: string;
firstName: string;
lastName: string;
created: Date;
updated: Date;
updatedBy: string | null;
meta: Record<string, unknown>;
};

type CustomerInput = {
firstName: string;
lastName: string;
email: string;
meta?: Record<string, unknown>;
};

type CustomerUpdate = {
firstName?: string;
lastName?: string;
email?: string;
meta?: Record<string, unknown>;
updatedBy?: string;
status?: string;
};

const customerColumns = [
'id',
'email',
Expand All @@ -33,7 +60,7 @@ const customerColumns = [
];


export async function createCustomer({ firstName, lastName, email, meta }) {
export async function createCustomer({ firstName, lastName, email, meta }: CustomerInput): Promise<Customer> {
if(!firstName || !lastName || !email) throw new CustomerServiceError('Missing customer data', 'INVALID');
if(!/.+@.+\..{2,}/.test(email)) throw new CustomerServiceError('Invalid email', 'INVALID');

Expand All @@ -48,20 +75,20 @@ export async function createCustomer({ firstName, lastName, email, meta }) {
};

try {
const [createdCustomer] = (await sql`
const [createdCustomer] = await sql<Customer[]>`
INSERT INTO customers ${sql(customer)}
RETURNING ${sql(customerColumns)}
`);
`;

return createdCustomer;
} catch(e) {
throw new CustomerServiceError('Could not create customer', 'UNKNOWN', e);
}
}

export async function getCustomers() {
export async function getCustomers(): Promise<Customer[]> {
try {
const customers = await sql`
const customers = await sql<Customer[]>`
SELECT ${sql(customerColumns)}
FROM customers
`;
Expand All @@ -72,14 +99,14 @@ export async function getCustomers() {
}
}

export async function getCustomer(id) {
let customer;
export async function getCustomer(id: string): Promise<Customer> {
let customer: Customer | undefined;
try {
[customer] = (await sql`
[customer] = await sql<Customer[]>`
SELECT ${sql(customerColumns)}
FROM customers
WHERE id = ${id}
`);
`;
} catch(e) {
throw new CustomerServiceError('Could not query customers', 'UNKNOWN', e);
}
Expand All @@ -89,7 +116,7 @@ export async function getCustomer(id) {
return customer;
}

export async function updateCustomer(id, updates) {
export async function updateCustomer(id: string, updates: CustomerUpdate): Promise<Customer> {
for(const u in updates) {
// Update whitelist
if(![
Expand All @@ -103,14 +130,14 @@ export async function updateCustomer(id, updates) {

if(Object.keys(updates).length === 1 && updates.updatedBy) throw new CustomerServiceError('Invalid customer data', 'INVALID');

let customer;
let customer: Customer | undefined;
try {
[customer] = (await sql`
[customer] = await sql<Customer[]>`
UPDATE customers
SET ${sql(updates)}, updated = now()
WHERE id = ${id}
RETURNING ${sql(customerColumns)}
`);
`;
} catch(e) {
throw new CustomerServiceError('Could not update customer', 'UNKNOWN', e);
}
Expand Down
15 changes: 11 additions & 4 deletions lib/services/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ import MailChimpClient from 'mailchimp-api-v3';
const mailgun = MailgunJs({apiKey: config.mailgun.apiKey, domain: config.mailgun.domain});

const mailchimp = new MailChimpClient(config.mailchimp.apiKey),
md5 = string => crypto.createHash('md5').update(string).digest('hex');
md5 = (string: string): string => crypto.createHash('md5').update(string).digest('hex');

type EmailSubscriberInput = {
email: string;
firstName: string;
lastName: string;
tags?: string[];
};

/* eslint-disable max-len */
/**
Expand All @@ -25,7 +32,7 @@ const mailchimp = new MailChimpClient(config.mailchimp.apiKey),
* @param {Array} [tags=[] string }] tags to apply to member
* @return {Promise}
*/
export async function upsertEmailSubscriber(listId, { email, firstName, lastName, tags = [] }) {
export async function upsertEmailSubscriber(listId: string, { email, firstName, lastName, tags = [] }: EmailSubscriberInput): Promise<void> {
const memberHash = md5(email.toLowerCase());

try {
Expand All @@ -50,7 +57,7 @@ export async function upsertEmailSubscriber(listId, { email, firstName, lastName
}
}

export function sendReceipt(guestFirstName, guestLastName, guestEmail, confirmation, orderId, orderToken, amount) {
export function sendReceipt(guestFirstName: string, guestLastName: string, guestEmail: string, confirmation: string, orderId: string, orderToken: string, amount: number): void {
mailgun.messages().send({
from: 'Mustache Bash Tickets <contact@mustachebash.com>',
to: guestFirstName + ' ' + guestLastName + ' <' + guestEmail + '> ',
Expand Down Expand Up @@ -360,7 +367,7 @@ table[class=body] .article {
.catch(err => log.error({err, customerEmail, confirmation}, 'Receipt email failed to send'));
}

export function sendTransfereeConfirmation(transfereeFirstName, transfereeLastName, transfereeEmail, parentOrderId, orderToken) {
export function sendTransfereeConfirmation(transfereeFirstName: string, transfereeLastName: string, transfereeEmail: string, parentOrderId: string, orderToken: string): void {
mailgun.messages().send({
from: 'Mustache Bash Tickets <contact@mustachebash.com>',
to: transfereeFirstName + ' ' + transfereeLastName + ' <' + transfereeEmail + '> ',
Expand Down
Loading
Loading