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
135 changes: 74 additions & 61 deletions codewit/api/src/controllers/course.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from '../models';
import { CourseResponse } from '../typings/response.types';
import { formatCourseResponse } from '../utils/responseFormatter';
import { generate_id, commit_id, rollback_id } from "../utils/id_generator";

async function createCourse(
title: string,
Expand All @@ -30,77 +31,89 @@ async function createCourse(
instructors?: number[],
roster?: number[]
): Promise<CourseResponse> {
return sequelize.transaction(async (transaction) => {
// acquire SHARE ROW EXCLUSIVE lock, This lock allows concurrent reads
// and locks the table against concurrent writes to avoid race conditions
// when reading the current count of courses to create a unique course id
// refer: https://www.postgresql.org/docs/16/explicit-locking.html
await sequelize.query('LOCK TABLE "courses" IN SHARE ROW EXCLUSIVE MODE', {
transaction,
});
// will need to store the id of the generated name so that we can either
// commit or rollback
let id = 0;

try {
let result = await sequelize.transaction(async (transaction) => {
if (auto_enroll && !enrolling) {
auto_enroll = false;
}

if (auto_enroll && !enrolling) {
auto_enroll = false;
}
let [successful, name, gen_id] = generate_id();

const course_count = await Course.count({ transaction });
const course = await Course.create(
{
id: uniqueNamesGenerator({
dictionaries: [adjectives, colors, animals],
separator: '-',
// use the current count of courses as the seed to ensure uniqueness
seed: course_count + 1,
}),
title,
enrolling,
auto_enroll,
},
{ transaction }
);
if (!successful) {
// based on how the id is currently generated, it will only fail if we
// reach the max attempts or if there are no more ids to generate
throw new Error("failed to generate course id");
}

if (language) {
const [lang] = await Language.findOrCreate({
where: { name: language },
transaction,
});
id = gen_id;

await course.setLanguage(lang, { transaction });
}

if (modules) {
await Promise.all(
modules.map(async (moduleId, idx) => {
await course.addModule(moduleId, {
through: { ordering: idx + 1 },
transaction,
});
})
const course = await Course.create(
{
id: name,
title,
enrolling,
auto_enroll,
},
{ transaction }
);
}

if (instructors) {
await course.setInstructors(instructors, { transaction });
}
if (language) {
const [lang] = await Language.findOrCreate({
where: { name: language },
transaction,
});

if (roster) {
await course.setRoster(roster, { transaction });
}
await course.setLanguage(lang, { transaction });
}

await course.reload({
// eager load the instructors
include: [
Language,
Module,
{ association: Course.associations.instructors },
{ association: Course.associations.roster },
],
order: [[Module, CourseModules, 'ordering', 'ASC']],
transaction,
if (modules) {
await Promise.all(
modules.map(async (moduleId, idx) => {
await course.addModule(moduleId, {
through: { ordering: idx + 1 },
transaction,
});
})
);
}

if (instructors) {
await course.setInstructors(instructors, { transaction });
}

if (roster) {
await course.setRoster(roster, { transaction });
}

await course.reload({
// eager load the instructors
include: [
Language,
Module,
{ association: Course.associations.instructors },
{ association: Course.associations.roster },
],
order: [[Module, CourseModules, 'ordering', 'ASC']],
transaction,
});

return formatCourseResponse(course);
});

return formatCourseResponse(course);
});
commit_id(id);

return result;
} catch(err) {
// not going to deal with the error other than rollback the id generated if
// one was made
rollback_id(id);

throw err;
}
}

async function updateCourse(
Expand Down
23 changes: 6 additions & 17 deletions codewit/api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,10 @@ import { COOKIE_KEY, HOST, PORT, REDIS_HOST, REDIS_PORT } from './secrets';
import './auth/passport';
import { checkAuth } from './middleware/auth';
import { catchError, asyncHandle } from "./middleware/catch";
// import { RedisStore } from "connect-redis";
// import { createClient } from "redis";
import { init } from "./utils/id_generator";

const app = express();

// let redisClient = createClient(
// {
// url: `redis://${REDIS_HOST}:${REDIS_PORT}`,
// }
// )
// redisClient.connect().catch(console.error)

// let redisStore = new RedisStore({
// client: redisClient,
// prefix: "codewit:",
// })

app.use(
session({
secret: COOKIE_KEY,
Expand Down Expand Up @@ -60,6 +47,8 @@ app.use('/attempts', checkAuth, attemptRouter);

app.use(catchError);

app.listen(PORT, HOST, async () => {
console.log(`[ ready ] http://${HOST}:${PORT}`);
});
init()
.then(() => app.listen(PORT, HOST, async () => {
console.log(`[ ready ] http://${HOST}:${PORT}`);
}))
.catch(console.error);
Loading
Loading