refactor: reorganize imports in course route and update middleware for course tags endpoint

This commit is contained in:
Rotimi Best
2026-03-12 22:16:51 +01:00
parent 4fe4fc168d
commit 420409722a
5 changed files with 30 additions and 14 deletions
+7 -7
View File
@@ -25,33 +25,33 @@ import {
getCourseProgress, getCourseProgress,
updateCourse updateCourse
} from '@api/services/course/course'; } from '@api/services/course/course';
import { enrollInCourse } from '@api/services/course/invite';
import { getCourseTags, replaceCourseTags } from '@api/services/tag'; import { getCourseTags, replaceCourseTags } from '@api/services/tag';
import { createRateLimiter } from '@api/middlewares/rate-limiter';
import { extractClientIp } from '@api/utils/redis/key-generators';
import { Hono } from '@api/utils/hono'; import { Hono } from '@api/utils/hono';
import { attendanceRouter } from '@api/routes/course/attendance'; import { attendanceRouter } from '@api/routes/course/attendance';
import { authMiddleware } from '@api/middlewares/auth'; import { authMiddleware } from '@api/middlewares/auth';
import { cloneCourse } from '@api/services/course/clone'; import { cloneCourse } from '@api/services/course/clone';
import { contentRouter } from '@api/routes/course/content';
import { courseMemberMiddleware } from '@api/middlewares/course-member'; import { courseMemberMiddleware } from '@api/middlewares/course-member';
import { courseTeamMemberMiddleware } from '@api/middlewares/course-team-member'; import { courseTeamMemberMiddleware } from '@api/middlewares/course-team-member';
import { contentRouter } from '@api/routes/course/content'; import { createRateLimiter } from '@api/middlewares/rate-limiter';
import { enrollInCourse } from '@api/services/course/invite';
import { exerciseRouter } from '@api/routes/course/exercise'; import { exerciseRouter } from '@api/routes/course/exercise';
import { extractClientIp } from '@api/utils/redis/key-generators';
import { generateCertificate } from '@api/utils/certificate'; import { generateCertificate } from '@api/utils/certificate';
import { generateCoursePdf } from '@api/utils/course'; import { generateCoursePdf } from '@api/utils/course';
import { handleError } from '@api/utils/errors'; import { handleError } from '@api/utils/errors';
import { invitesRouter } from '@api/routes/course/invite';
import { katexRouter } from '@api/routes/course/katex'; import { katexRouter } from '@api/routes/course/katex';
import { lessonRouter } from '@api/routes/course/lesson'; import { lessonRouter } from '@api/routes/course/lesson';
import { markRouter } from '@api/routes/course/mark'; import { markRouter } from '@api/routes/course/mark';
import { sectionRouter } from '@api/routes/course/section';
import { membersRouter } from '@api/routes/course/people'; import { membersRouter } from '@api/routes/course/people';
import { invitesRouter } from '@api/routes/course/invite';
import { newsfeedRouter } from '@api/routes/course/newsfeed'; import { newsfeedRouter } from '@api/routes/course/newsfeed';
import { orgAdminMiddleware } from '@api/middlewares/org-admin'; import { orgAdminMiddleware } from '@api/middlewares/org-admin';
import { orgMemberMiddleware } from '@api/middlewares/org-member'; import { orgMemberMiddleware } from '@api/middlewares/org-member';
import { paymentRequestRouter } from '@api/routes/course/payment-request'; import { paymentRequestRouter } from '@api/routes/course/payment-request';
import { presignRouter } from '@api/routes/course/presign'; import { presignRouter } from '@api/routes/course/presign';
import { sectionRouter } from '@api/routes/course/section';
import { submissionRouter } from '@api/routes/course/submission'; import { submissionRouter } from '@api/routes/course/submission';
import { zValidator } from '@hono/zod-validator'; import { zValidator } from '@hono/zod-validator';
@@ -157,7 +157,7 @@ export const courseRouter = new Hono()
* GET /course/:courseId/tags * GET /course/:courseId/tags
* Gets tags assigned to a course (organization admin only) * Gets tags assigned to a course (organization admin only)
*/ */
.get('/:courseId/tags', authMiddleware, orgAdminMiddleware, zValidator('param', ZCourseTagParam), async (c) => { .get('/:courseId/tags', authMiddleware, orgMemberMiddleware, zValidator('param', ZCourseTagParam), async (c) => {
try { try {
const orgId = c.req.header('cio-org-id')!; const orgId = c.req.header('cio-org-id')!;
const { courseId } = c.req.valid('param'); const { courseId } = c.req.valid('param');
+2 -2
View File
@@ -50,9 +50,9 @@ export async function getAccountData(userId: string): Promise<GetAccountDataResu
roleId: ROLE.STUDENT, roleId: ROLE.STUDENT,
verified: true verified: true
}); });
organizations = await getOrganizationByProfileId(userId);
} }
organizations = await getOrganizationByProfileId(userId);
} }
} }
+11 -4
View File
@@ -1,20 +1,23 @@
import * as schema from '@cio/db/schema';
import { AppError, ErrorCodes } from '@api/utils/errors'; import { AppError, ErrorCodes } from '@api/utils/errors';
import { and, eq, isNull } from 'drizzle-orm'; import { and, eq, isNull } from 'drizzle-orm';
import { import {
checkEmailsExistInOrg, checkEmailsExistInOrg,
createOrganizationMembers,
createOrganizationInvite, createOrganizationInvite,
createOrganizationInviteAudit, createOrganizationInviteAudit,
createOrganizationMembers,
getOrganizationById, getOrganizationById,
getOrganizationInviteByTokenHash, getOrganizationInviteByTokenHash,
revokeActiveOrganizationInvitesByEmails revokeActiveOrganizationInvitesByEmails
} from '@cio/db/queries/organization'; } from '@cio/db/queries/organization';
import { ROLE } from '@cio/utils/constants';
import crypto from 'node:crypto';
import { db } from '@cio/db/drizzle'; import { db } from '@cio/db/drizzle';
import { getDashboardBaseUrl } from '@api/config/dashboard-url'; import { getDashboardBaseUrl } from '@api/config/dashboard-url';
import { markUserAndProfileEmailVerified } from '@cio/db/queries/auth/profile';
import { sendEmail } from '@cio/email'; import { sendEmail } from '@cio/email';
import { ROLE } from '@cio/utils/constants';
import * as schema from '@cio/db/schema';
import crypto from 'node:crypto';
type OrganizationInviteStatus = 'ACTIVE' | 'EXPIRED' | 'REVOKED' | 'ACCEPTED'; type OrganizationInviteStatus = 'ACTIVE' | 'EXPIRED' | 'REVOKED' | 'ACCEPTED';
@@ -302,6 +305,8 @@ export async function acceptOrganizationInvite(token: string, user: TAuthUser, c
} }
if (status === 'ACCEPTED') { if (status === 'ACCEPTED') {
await markUserAndProfileEmailVerified(user.id, tx);
return { return {
organization: row.organization, organization: row.organization,
roleId: row.invite.roleId, roleId: row.invite.roleId,
@@ -366,6 +371,8 @@ export async function acceptOrganizationInvite(token: string, user: TAuthUser, c
} }
} }
await markUserAndProfileEmailVerified(user.id, tx);
const [acceptedInvite] = await tx const [acceptedInvite] = await tx
.update(schema.organizationInvite) .update(schema.organizationInvite)
.set({ .set({
@@ -4,6 +4,7 @@ import { and, eq } from 'drizzle-orm';
import { User } from 'better-auth'; import { User } from 'better-auth';
import { db } from '@db/drizzle'; import { db } from '@db/drizzle';
import { markUserAndProfileEmailVerified } from '@db/queries/auth';
const DEFAULT_STUDENT_ROLE_ID = 3; const DEFAULT_STUDENT_ROLE_ID = 3;
@@ -60,6 +61,8 @@ export async function ensureOrgMembership(
updatedAt: new Date().toISOString() updatedAt: new Date().toISOString()
}) })
.where(eq(schema.organizationInvite.id, invite.id)); .where(eq(schema.organizationInvite.id, invite.id));
await markUserAndProfileEmailVerified(userId, tx);
}); });
console.debug('User joined org via invite:', orgId); console.debug('User joined org via invite:', orgId);
+7 -1
View File
@@ -515,6 +515,12 @@ export async function getExerciseWithRelationsOptimized(
*/ */
export async function syncOptionIdSequence(dbClient: DbOrTxClient = db): Promise<void> { export async function syncOptionIdSequence(dbClient: DbOrTxClient = db): Promise<void> {
await dbClient.execute( await dbClient.execute(
sql`SELECT setval(pg_get_serial_sequence('option', 'id'), COALESCE((SELECT MAX(id) FROM "option"), 0))` sql`
SELECT setval(
pg_get_serial_sequence('option', 'id'),
COALESCE((SELECT MAX(id) FROM "option"), 1),
EXISTS(SELECT 1 FROM "option")
)
`
); );
} }