901 lines
24 KiB
TypeScript
901 lines
24 KiB
TypeScript
import bcrypt from 'bcrypt';
|
|
import sql from '$lib/db/db.server';
|
|
import { error } from '@sveltejs/kit';
|
|
import { deleteLogo, saveAvatar, saveLogo } from '$lib/index.server';
|
|
import {
|
|
EmploymentType,
|
|
type User,
|
|
type Company,
|
|
type Tag,
|
|
type Posting,
|
|
type Application
|
|
} from '$lib/types';
|
|
import { sendEmployerNotificationEmail } from '$lib/emailer.server';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
|
|
export async function createUser(user: User): Promise<number> {
|
|
const password_hash: string = await bcrypt.hash(user.password!, 12);
|
|
|
|
const response = await sql`
|
|
INSERT INTO users (username, password_hash, perms, created_at, last_signin, active, email, phone, full_name, company_code)
|
|
VALUES (${user.username}, ${password_hash}, ${user.perms}, NOW(), NOW(), ${user.active}, ${user.email}, ${user.phone}, ${user.fullName}, ${user.companyCode})
|
|
RETURNING id;
|
|
`;
|
|
|
|
// TODO: handle custom image uploads
|
|
user.id = response[0].id;
|
|
await saveAvatar(user);
|
|
|
|
return response[0].id;
|
|
}
|
|
|
|
export async function updateUser(user: User): Promise<number> {
|
|
let password_hash: string | null = null;
|
|
|
|
// Hash the password if provided
|
|
if (user.password) {
|
|
password_hash = await bcrypt.hash(user.password, 12);
|
|
}
|
|
|
|
// Construct the SQL query
|
|
const response = await sql`UPDATE users
|
|
SET
|
|
username = ${user.username},
|
|
${user.perms !== undefined ? sql`perms = ${user.perms},` : sql``}
|
|
${user.active !== undefined ? sql`active = ${user.active},` : sql``}
|
|
${password_hash !== null ? sql`password_hash = ${password_hash},` : sql``}
|
|
email = ${user.email},
|
|
phone = ${user.phone},
|
|
full_name = ${user.fullName},
|
|
company_code = ${user.companyCode}
|
|
WHERE id = ${user.id}
|
|
RETURNING id;`;
|
|
|
|
await saveAvatar(user);
|
|
|
|
return response[0].id;
|
|
}
|
|
|
|
export async function checkUserCreds(username: string, password: string): Promise<User | null> {
|
|
const [user] = await sql`
|
|
SELECT id, username, password_hash, perms, active, company_id AS "companyId"
|
|
FROM users
|
|
WHERE username = ${username}
|
|
`;
|
|
|
|
if (!user) {
|
|
return null;
|
|
}
|
|
if (await bcrypt.compare(password, user.password_hash)) {
|
|
delete user.password_hash;
|
|
return <User>user;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// should require MANAGE_USERS permission
|
|
export async function getUsers(searchQuery: string | null = null): Promise<User[]> {
|
|
const users = await sql`
|
|
SELECT id,
|
|
username,
|
|
perms,
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
|
last_signin AT TIME ZONE 'UTC' AS "lastSignIn",
|
|
active,
|
|
email,
|
|
phone,
|
|
full_name AS "fullName",
|
|
company_id
|
|
FROM users
|
|
WHERE username ILIKE ${searchQuery ? `%${searchQuery}%` : '%'};
|
|
`;
|
|
users.forEach((user) => {
|
|
user.company = {
|
|
id: user.company_id
|
|
};
|
|
delete user.company_id;
|
|
});
|
|
return <User[]>(<unknown>users);
|
|
}
|
|
|
|
export async function getCompanies(searchQuery: string | null = null): Promise<Company[]> {
|
|
return sql<Company[]>`
|
|
SELECT id,
|
|
name,
|
|
description,
|
|
website,
|
|
company_code AS "companyCode",
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt"
|
|
FROM companies
|
|
WHERE name ILIKE ${searchQuery ? `%${searchQuery}%` : '%'};
|
|
`;
|
|
}
|
|
|
|
// should require MANAGE_USERS permission
|
|
export async function getUser(id: number): Promise<User> {
|
|
const [user] = await sql`
|
|
SELECT id, username, perms,
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
|
last_signin AT TIME ZONE 'UTC' AS "lastSignIn",
|
|
active, email, phone, full_name AS "fullName", company_id, company_code
|
|
FROM users
|
|
WHERE id = ${id};
|
|
`;
|
|
if (!user) {
|
|
error(404, 'User not found');
|
|
}
|
|
user.company = {
|
|
id: user.company_id
|
|
};
|
|
delete user.company_id;
|
|
return <User>user;
|
|
}
|
|
|
|
export async function getUserWithCompany(id: number): Promise<User> {
|
|
const [user] = await sql`
|
|
SELECT
|
|
u.id,
|
|
u.username,
|
|
u.perms,
|
|
u.email,
|
|
u.phone,
|
|
u.full_name AS "fullName",
|
|
u.created_at AT TIME ZONE 'UTC' AS "createdAt",
|
|
u.last_signin AT TIME ZONE 'UTC' AS "lastSignIn",
|
|
u.active,
|
|
c.id AS company_id,
|
|
c.name AS company_name,
|
|
c.description AS company_description,
|
|
c.website AS company_website,
|
|
c.created_at AS company_created_at
|
|
FROM
|
|
users u
|
|
LEFT JOIN
|
|
companies c ON u.company_id = c.id
|
|
WHERE
|
|
u.id = ${id};
|
|
`;
|
|
if (!user) {
|
|
error(404, 'User not found');
|
|
}
|
|
user.company = {
|
|
id: user.company_id,
|
|
name: user.company_name,
|
|
description: user.company_description,
|
|
website: user.company_website,
|
|
createdAt: user.company_created_at
|
|
};
|
|
|
|
// Remove the company-specific columns from the user object
|
|
delete user.company_id;
|
|
delete user.company_name;
|
|
delete user.company_description;
|
|
delete user.company_website;
|
|
delete user.company_created_at;
|
|
|
|
return <User>user;
|
|
}
|
|
|
|
export async function getUserWithCompanyAndApplications(
|
|
id: number
|
|
): Promise<{ user: User; applications: Application[] }> {
|
|
const data = await sql`
|
|
WITH company_data AS (
|
|
SELECT
|
|
id,
|
|
name,
|
|
description,
|
|
website,
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt"
|
|
FROM companies
|
|
WHERE id = (SELECT company_id FROM users WHERE id = ${id})
|
|
),
|
|
user_data AS (
|
|
SELECT
|
|
id,
|
|
username,
|
|
perms,
|
|
email,
|
|
phone,
|
|
full_name AS "fullName",
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
|
last_signin AT TIME ZONE 'UTC' AS "lastSignIn",
|
|
active
|
|
FROM users
|
|
WHERE "id" = ${id}
|
|
),
|
|
application_data AS (
|
|
SELECT
|
|
id,
|
|
posting_id AS "postingId",
|
|
(SELECT title FROM postings WHERE id = posting_id) AS "postingTitle",
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt"
|
|
FROM applications
|
|
WHERE "user_id" = ${id}
|
|
)
|
|
SELECT
|
|
(
|
|
SELECT row_to_json(company_data)
|
|
FROM company_data
|
|
) AS company,
|
|
(
|
|
SELECT row_to_json(user_data)
|
|
FROM user_data
|
|
) AS user,
|
|
(
|
|
SELECT json_agg(row_to_json(application_data))
|
|
FROM application_data
|
|
) AS applications;
|
|
`;
|
|
|
|
if (!data) {
|
|
error(404, 'User not found');
|
|
}
|
|
let user = data[0].user;
|
|
user.company = data[0].company;
|
|
|
|
user.createdAt = new Date(user.createdAt);
|
|
user.lastSignIn = new Date(user.lastSignIn);
|
|
if (user.company) {
|
|
user.company.createdAt = new Date(user.company.createdAt);
|
|
}
|
|
let applications = data[0].applications;
|
|
if (applications) {
|
|
applications.forEach((application: { createdAt: string | number | Date }) => {
|
|
application.createdAt = new Date(application.createdAt);
|
|
});
|
|
}
|
|
|
|
return {
|
|
user: <User>user,
|
|
applications: <Application[]>applications
|
|
};
|
|
}
|
|
|
|
// should require MANAGE_USERS permission
|
|
export async function deleteUser(id: number): Promise<void> {
|
|
await sql`
|
|
DELETE FROM users
|
|
WHERE id = ${id};
|
|
`;
|
|
}
|
|
|
|
// should require MANAGE_TAGS permission
|
|
export async function getTags(searchQuery: string | null): Promise<Tag[]> {
|
|
return sql<Tag[]>`
|
|
SELECT id, display_name as "displayName", created_at AT TIME ZONE 'UTC' AS "createdAt"
|
|
FROM tags
|
|
WHERE display_name ILIKE ${searchQuery ? `%${searchQuery}%` : '%'};
|
|
`;
|
|
}
|
|
|
|
export async function updateLastSignin(username: string): Promise<void> {
|
|
await sql`
|
|
UPDATE users
|
|
SET last_signin = NOW()
|
|
WHERE username = ${username};
|
|
`;
|
|
}
|
|
|
|
export async function createCompany(company: Company): Promise<number> {
|
|
const response = await sql`
|
|
INSERT INTO companies (name, description, website, created_at, company_code)
|
|
VALUES (${company.name}, ${company.description}, ${company.website}, NOW(), generate_company_code(CAST(CURRVAL('companies_id_seq') AS INT)))
|
|
RETURNING id;
|
|
`;
|
|
|
|
await saveLogo(company);
|
|
|
|
return response[0].id;
|
|
}
|
|
|
|
export async function editCompany(company: Company): Promise<number> {
|
|
const response = await sql`
|
|
UPDATE companies
|
|
SET name = ${company.name}, description = ${company.description}, website = ${company.website}
|
|
WHERE id = ${company.id}
|
|
RETURNING id;
|
|
`;
|
|
|
|
await saveLogo(company);
|
|
|
|
return response[0].id;
|
|
}
|
|
|
|
export async function deleteCompany(id: number): Promise<void> {
|
|
await sql`
|
|
DELETE FROM companies
|
|
WHERE id = ${id};
|
|
`;
|
|
|
|
await deleteLogo(<Company>{ id: id });
|
|
}
|
|
|
|
export async function getCompany(id: number): Promise<Company> {
|
|
const [company] = await sql`
|
|
SELECT id, name, description, website, created_at AS "createdAt", company_code AS "companyCode"
|
|
FROM companies
|
|
WHERE id = ${id};
|
|
`;
|
|
|
|
if (!company) {
|
|
error(404, 'Company not found');
|
|
}
|
|
|
|
return <Company>company;
|
|
}
|
|
|
|
export async function getCompanyFullData(
|
|
id: number
|
|
): Promise<{ company: Company; users: User[]; postings: Posting[] }> {
|
|
const data = await sql`
|
|
WITH company_data AS (
|
|
SELECT
|
|
id,
|
|
name,
|
|
description,
|
|
website,
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt"
|
|
FROM companies
|
|
WHERE id = ${id}
|
|
),
|
|
user_data AS (
|
|
SELECT
|
|
id,
|
|
username,
|
|
email,
|
|
phone,
|
|
full_name AS "fullName"
|
|
FROM users
|
|
WHERE "company_id" = ${id}
|
|
),
|
|
posting_data AS (
|
|
SELECT
|
|
id,
|
|
title,
|
|
description,
|
|
employer_id AS "employerId",
|
|
address,
|
|
employment_type AS "employmentType",
|
|
wage,
|
|
link,
|
|
tag_ids AS "tagIds",
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
|
updated_at AT TIME ZONE 'UTC' AS "updatedAt",
|
|
flyer_link AS "flyerLink"
|
|
FROM postings
|
|
WHERE "company_id" = ${id}
|
|
)
|
|
SELECT
|
|
(
|
|
SELECT row_to_json(company_data)
|
|
FROM company_data
|
|
) AS company,
|
|
(
|
|
SELECT json_agg(row_to_json(user_data))
|
|
FROM user_data
|
|
) AS users,
|
|
(
|
|
SELECT json_agg(row_to_json(posting_data))
|
|
FROM posting_data
|
|
) AS postings;
|
|
`;
|
|
|
|
if (!data) {
|
|
error(404, 'Company not found');
|
|
}
|
|
if (data[0].company) {
|
|
data[0].company.createdAt = new Date(data[0].company.createdAt);
|
|
}
|
|
if (data[0].postings) {
|
|
data[0].postings.forEach(
|
|
(posting: {
|
|
createdAt: string | number | Date;
|
|
updatedAt: string | number | Date;
|
|
tagIds: number[] | undefined;
|
|
tags: { id: number; displayName: null; createdAt: null }[];
|
|
}) => {
|
|
posting.createdAt = new Date(posting.createdAt);
|
|
posting.updatedAt = new Date(posting.updatedAt);
|
|
if (posting.tagIds) {
|
|
posting.tagIds?.forEach((tagId: number) => {
|
|
posting.tags.push({ id: tagId, displayName: null, createdAt: null });
|
|
});
|
|
}
|
|
delete posting.tagIds;
|
|
}
|
|
);
|
|
}
|
|
|
|
return {
|
|
company: <Company>data[0].company,
|
|
users: <User[]>data[0].users,
|
|
postings: <Posting[]>data[0].postings
|
|
};
|
|
}
|
|
|
|
export async function createPosting(posting: Posting): Promise<number> {
|
|
if (posting.tagIds === null || posting.tagIds === undefined) {
|
|
posting.tagIds = [];
|
|
}
|
|
posting.tags?.forEach((tag) => {
|
|
posting.tagIds?.push(tag.id);
|
|
});
|
|
if (posting.companyId === null || posting.companyId === undefined) {
|
|
if (posting.company) {
|
|
posting.companyId = posting.company.id;
|
|
} else {
|
|
posting.companyId = null;
|
|
}
|
|
}
|
|
const response = await sql`
|
|
INSERT INTO postings (title, description, employer_id, address, employment_type, wage, link, tag_ids, created_at, updated_at, flyer_link, company_id)
|
|
VALUES (${posting.title}, ${posting.description}, ${posting.employerId}, ${posting.address}, ${posting.employmentType}, ${posting.wage}, ${posting.link}, ${posting.tagIds}, NOW(), NOW(), ${posting.flyerLink}, ${posting.companyId})
|
|
RETURNING id;
|
|
`;
|
|
|
|
return response[0].id;
|
|
}
|
|
|
|
export async function editPosting(posting: Posting): Promise<number> {
|
|
if (posting.tagIds === null || posting.tagIds === undefined) {
|
|
posting.tagIds = [];
|
|
}
|
|
posting.tags?.forEach((tag) => {
|
|
posting.tagIds?.push(tag.id);
|
|
});
|
|
if (posting.companyId === null || posting.companyId === undefined) {
|
|
if (posting.company) {
|
|
posting.companyId = posting.company.id;
|
|
} else {
|
|
posting.companyId = null;
|
|
}
|
|
}
|
|
|
|
const response = await sql`
|
|
UPDATE postings
|
|
SET title = ${posting.title}, description = ${posting.description}, employer_id = ${posting.employerId}, address = ${posting.address}, employment_type = ${posting.employmentType}, wage = ${posting.wage}, link = ${posting.link}, tag_ids = ${posting.tagIds}, updated_at = NOW(), flyer_link = ${posting.flyerLink}, company_id = ${posting.companyId}
|
|
WHERE id = ${posting.id}
|
|
RETURNING id;
|
|
`;
|
|
|
|
return response[0].id;
|
|
}
|
|
|
|
export async function deletePosting(id: number): Promise<void> {
|
|
await sql`
|
|
DELETE FROM postings
|
|
WHERE id = ${id};
|
|
`;
|
|
}
|
|
|
|
export async function getCompanyEmployers(
|
|
id: number
|
|
): Promise<{ company: Company; users: User[] }> {
|
|
const data = await sql`
|
|
WITH company_data AS (
|
|
SELECT
|
|
id,
|
|
name,
|
|
description,
|
|
website,
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
|
company_code AS "companyCode"
|
|
FROM companies
|
|
WHERE id = ${id}
|
|
),
|
|
user_data AS (SELECT id,
|
|
username,
|
|
email,
|
|
phone,
|
|
full_name AS "fullName",
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
|
last_signin AT TIME ZONE 'UTC' AS "lastSignIn",
|
|
company_id as "companyId"
|
|
FROM users
|
|
WHERE "company_id" = ${id})
|
|
SELECT
|
|
(
|
|
SELECT row_to_json(company_data)
|
|
FROM company_data
|
|
) AS company,
|
|
(
|
|
SELECT json_agg(row_to_json(user_data))
|
|
FROM user_data
|
|
) AS users;
|
|
`;
|
|
|
|
if (!data) {
|
|
error(404, 'Company not found');
|
|
}
|
|
if (data[0].users) {
|
|
data[0].users.forEach(
|
|
(user: {
|
|
company: { id: any };
|
|
companyId: any;
|
|
createdAt: string | number | Date;
|
|
lastSignIn: string | number | Date;
|
|
}) => {
|
|
user.company = {
|
|
id: user.companyId
|
|
};
|
|
user.createdAt = new Date(user.createdAt);
|
|
user.lastSignIn = new Date(user.lastSignIn);
|
|
delete user.companyId;
|
|
}
|
|
);
|
|
}
|
|
|
|
return {
|
|
company: <Company>data[0].company,
|
|
users: <User[]>data[0].users
|
|
};
|
|
}
|
|
|
|
export async function getCompanyEmployersAndRequests(
|
|
id: number
|
|
): Promise<{ company: Company; employers: User[]; requests: User[] }> {
|
|
const data = await sql`
|
|
WITH company_data AS (
|
|
SELECT
|
|
id,
|
|
name,
|
|
description,
|
|
website,
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
|
company_code AS "companyCode"
|
|
FROM companies
|
|
WHERE id = ${id}
|
|
),
|
|
employer_data AS (SELECT id,
|
|
username,
|
|
email,
|
|
phone,
|
|
full_name AS "fullName",
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
|
last_signin AT TIME ZONE 'UTC' AS "lastSignIn",
|
|
company_id as "companyId"
|
|
FROM users
|
|
WHERE "company_id" = ${id}),
|
|
request_data AS (SELECT id,
|
|
username,
|
|
email,
|
|
phone,
|
|
full_name AS "fullName",
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
|
last_signin AT TIME ZONE 'UTC' AS "lastSignIn",
|
|
company_id as "companyId"
|
|
FROM users
|
|
WHERE "company_code" = (SELECT company_code FROM companies WHERE id = ${id}))
|
|
SELECT
|
|
(
|
|
SELECT row_to_json(company_data)
|
|
FROM company_data
|
|
) AS company,
|
|
(
|
|
SELECT json_agg(row_to_json(employer_data))
|
|
FROM employer_data
|
|
) AS employers,
|
|
(
|
|
SELECT json_agg(row_to_json(request_data))
|
|
FROM request_data
|
|
) AS requests;
|
|
`;
|
|
|
|
if (!data) {
|
|
error(404, 'Company not found');
|
|
}
|
|
if (data[0].employers) {
|
|
data[0].employers.forEach(
|
|
(user: {
|
|
company: { id: any };
|
|
companyId: any;
|
|
createdAt: string | number | Date;
|
|
lastSignIn: string | number | Date;
|
|
}) => {
|
|
user.company = {
|
|
id: user.companyId
|
|
};
|
|
user.createdAt = new Date(user.createdAt);
|
|
user.lastSignIn = new Date(user.lastSignIn);
|
|
delete user.companyId;
|
|
}
|
|
);
|
|
}
|
|
if (data[0].requests) {
|
|
data[0].requests.forEach(
|
|
(user: {
|
|
company: { id: any };
|
|
companyId: any;
|
|
createdAt: string | number | Date;
|
|
lastSignIn: string | number | Date;
|
|
}) => {
|
|
user.company = {
|
|
id: user.companyId
|
|
};
|
|
user.createdAt = new Date(user.createdAt);
|
|
user.lastSignIn = new Date(user.lastSignIn);
|
|
delete user.companyId;
|
|
}
|
|
);
|
|
}
|
|
|
|
return {
|
|
company: <Company>data[0].company,
|
|
employers: <User[]>data[0].employers,
|
|
requests: <User[]>data[0].requests
|
|
};
|
|
}
|
|
|
|
export async function removeEmployerFromCompany(companyId: number, userId: number): Promise<void> {
|
|
await sql`
|
|
UPDATE users
|
|
SET company_id = NULL,
|
|
company_code = NULL
|
|
WHERE id = ${userId};
|
|
`;
|
|
}
|
|
|
|
export async function addEmployerToCompany(companyId: number, userId: number): Promise<void> {
|
|
await sql`
|
|
UPDATE users
|
|
SET company_id = ${companyId}
|
|
WHERE id = ${userId};
|
|
`;
|
|
}
|
|
|
|
export async function getPostings(searchQuery: string | null = null): Promise<Posting[]> {
|
|
const postings = await sql<Posting[]>`
|
|
SELECT p.id,
|
|
p.title,
|
|
p.description,
|
|
p.employer_id AS "employerId",
|
|
p.address,
|
|
p.employment_type AS "employmentType",
|
|
p.wage,
|
|
p.link,
|
|
p.tag_ids AS "tagIds",
|
|
p.created_at AT TIME ZONE 'UTC' AS "createdAt",
|
|
p.updated_at AT TIME ZONE 'UTC' AS "updatedAt",
|
|
p.flyer_link AS "flyerLink",
|
|
p.company_id AS "companyId",
|
|
c.name AS "companyName"
|
|
FROM postings p
|
|
LEFT JOIN companies c ON p.company_id = c.id
|
|
WHERE title ILIKE ${searchQuery ? `%${searchQuery}%` : '%'};
|
|
`;
|
|
postings.forEach((posting) => {
|
|
posting.company = <Company>{};
|
|
if (posting.companyName) {
|
|
posting.company.name = posting.companyName;
|
|
}
|
|
delete posting.companyName;
|
|
posting.tags = [];
|
|
|
|
posting.employmentType = EmploymentType[posting.employmentType as keyof typeof EmploymentType];
|
|
if (posting.tagIds) {
|
|
posting.tagIds?.forEach((tagId: number) => {
|
|
posting.tags.push({ id: tagId, displayName: null, createdAt: null });
|
|
});
|
|
}
|
|
delete posting.tagIds;
|
|
});
|
|
return <Posting[]>(<unknown>postings);
|
|
}
|
|
|
|
export async function getPosting(id: number): Promise<Posting> {
|
|
const data = await sql<Posting[]>`
|
|
SELECT id,
|
|
title,
|
|
description,
|
|
employer_id AS "employerId",
|
|
address,
|
|
employment_type AS "employmentType",
|
|
wage,
|
|
link,
|
|
tag_ids AS "tagIds",
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
|
updated_at AT TIME ZONE 'UTC' AS "updatedAt",
|
|
flyer_link AS "flyerLink",
|
|
company_id AS "companyId"
|
|
FROM postings
|
|
WHERE id = ${id};
|
|
`;
|
|
const posting = data[0];
|
|
posting.tags = [];
|
|
posting.employmentType = EmploymentType[posting.employmentType as keyof typeof EmploymentType];
|
|
if (posting.tagIds) {
|
|
posting.tagIds?.forEach((tagId: number) => {
|
|
posting.tags.push({ id: tagId, displayName: null, createdAt: null });
|
|
});
|
|
}
|
|
delete posting.tagIds;
|
|
|
|
if (posting.createdAt) {
|
|
posting.createdAt = new Date(posting.createdAt);
|
|
}
|
|
if (posting.updatedAt) {
|
|
posting.updatedAt = new Date(posting.updatedAt);
|
|
}
|
|
|
|
return posting;
|
|
}
|
|
|
|
export async function getPostingWithCompanyUser(id: number): Promise<Posting> {
|
|
const data = await sql`
|
|
WITH company_data AS (
|
|
SELECT
|
|
id,
|
|
name,
|
|
description,
|
|
website,
|
|
created_at AS "createdAt"
|
|
FROM companies
|
|
WHERE id = (SELECT company_id FROM postings WHERE id = ${id})
|
|
),
|
|
user_data AS (
|
|
SELECT
|
|
username,
|
|
email,
|
|
phone,
|
|
full_name AS "fullName"
|
|
FROM users
|
|
WHERE "company_id" = (SELECT company_id FROM postings WHERE id = ${id})
|
|
),
|
|
posting_data AS (
|
|
SELECT
|
|
id,
|
|
title,
|
|
description,
|
|
employer_id AS "employerId",
|
|
address,
|
|
employment_type AS "employmentType",
|
|
wage,
|
|
link,
|
|
tag_ids AS "tagIds",
|
|
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
|
updated_at AT TIME ZONE 'UTC' AS "updatedAt",
|
|
flyer_link AS "flyerLink"
|
|
FROM postings
|
|
WHERE id = ${id}
|
|
)
|
|
SELECT
|
|
(
|
|
SELECT row_to_json(company_data)
|
|
FROM company_data
|
|
) AS company,
|
|
(
|
|
SELECT row_to_json(user_data)
|
|
FROM user_data
|
|
) AS user,
|
|
(
|
|
SELECT row_to_json(posting_data)
|
|
FROM posting_data
|
|
) AS posting;
|
|
`;
|
|
|
|
if (!data) {
|
|
error(404, 'Posting not found');
|
|
}
|
|
let posting = <Posting>data[0].posting;
|
|
posting.company = <Company>data[0].company;
|
|
posting.employer = <User>data[0].user;
|
|
|
|
if (posting.createdAt) {
|
|
posting.createdAt = new Date(posting.createdAt);
|
|
}
|
|
if (posting.updatedAt) {
|
|
posting.updatedAt = new Date(posting.updatedAt);
|
|
}
|
|
|
|
return posting;
|
|
}
|
|
|
|
export async function createApplication(application: Application): Promise<number> {
|
|
const response = await sql`
|
|
INSERT INTO applications (posting_id, user_id, candidate_statement, created_at)
|
|
VALUES (${application.postingId}, ${application.userId}, ${application.candidateStatement}, NOW())
|
|
RETURNING id;
|
|
`;
|
|
|
|
sendEmployerNotificationEmail(application.postingId).catch((err) => {
|
|
console.error('Failed to send employer notification email: ', err);
|
|
});
|
|
return response[0].id;
|
|
}
|
|
|
|
export async function deleteApplication(id: number): Promise<void> {
|
|
const response = await sql`
|
|
DELETE FROM applications
|
|
WHERE id = ${id};
|
|
`;
|
|
}
|
|
|
|
export async function deleteApplicationWithUser(
|
|
applicationId: number,
|
|
userId: number
|
|
): Promise<void> {
|
|
console.log(applicationId, userId);
|
|
const response = await sql`
|
|
DELETE FROM applications
|
|
WHERE id = ${applicationId} AND user_id = ${userId};
|
|
`;
|
|
}
|
|
|
|
export async function getApplications(postingId: number): Promise<Application[]> {
|
|
const data = await sql`
|
|
SELECT
|
|
a.id,
|
|
a.candidate_statement AS "candidateStatement",
|
|
a.created_at AS "createdAt",
|
|
u.id AS "userId",
|
|
u.username,
|
|
u.email,
|
|
u.phone,
|
|
u.full_name AS "fullName"
|
|
FROM applications a
|
|
JOIN users u ON a.user_id = u.id
|
|
WHERE a.posting_id = ${postingId};
|
|
`;
|
|
|
|
data.forEach((application) => {
|
|
application.createdAt = new Date(application.createdAt);
|
|
application.user = {
|
|
id: application.userId,
|
|
username: application.username,
|
|
email: application.email,
|
|
phone: application.phone,
|
|
fullName: application.fullName,
|
|
resume: fs.existsSync(
|
|
path.join(process.cwd(), 'static', 'uploads', 'resumes', `${application.userId}.pdf`)
|
|
)
|
|
};
|
|
delete application.userId;
|
|
delete application.username;
|
|
delete application.email;
|
|
delete application.phone;
|
|
delete application.fullName;
|
|
});
|
|
|
|
return <Application[]>(<unknown>data);
|
|
}
|
|
|
|
export async function setUserCompanyId(userId: number, companyId: number): Promise<void> {
|
|
await sql`
|
|
UPDATE users
|
|
SET company_id = ${companyId},
|
|
company_code = (SELECT company_code FROM companies WHERE id = ${companyId})
|
|
WHERE id = ${userId};
|
|
`;
|
|
}
|
|
|
|
export async function getNotificationInfo(
|
|
postingId: number
|
|
): Promise<{ title: string; emails: string[] }> {
|
|
const data = await sql`
|
|
WITH posting_data AS (
|
|
SELECT title, company_id
|
|
FROM postings
|
|
WHERE id = ${postingId}
|
|
),
|
|
user_emails AS (
|
|
SELECT email
|
|
FROM users
|
|
WHERE company_id = (SELECT company_id FROM posting_data)
|
|
)
|
|
SELECT
|
|
(SELECT title FROM posting_data) AS title,
|
|
(SELECT json_agg(email) FROM user_emails) AS emails;
|
|
`;
|
|
|
|
if (!data || !data[0]) {
|
|
error(404, 'Posting not found');
|
|
}
|
|
|
|
return {
|
|
title: data[0].title,
|
|
emails: data[0].emails
|
|
};
|
|
}
|