Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
e492b70
Adjusted turbo.json and package.json to have deployment work.
okarney Aug 29, 2025
161c9d9
More adjustments to package.json.
okarney Aug 29, 2025
d55cd6e
another attempt to deploy
okarney Aug 29, 2025
10e058c
adjusted start script again
okarney Aug 29, 2025
7e06cbf
removed start line in package.json
okarney Sep 1, 2025
9728d66
Create web_application_planning_docs.md
okarney Sep 9, 2025
c7346c5
Add files via upload
okarney Sep 9, 2025
423f191
Rename CISC474 - Individual Project Site Map.pdf to site_map.pdf
okarney Sep 9, 2025
732ec21
Add files via upload
okarney Sep 9, 2025
174b92e
Rename Individual Website Basic Data Model.pdf to basic_data_model.pdf
okarney Sep 9, 2025
dc5af37
Create requirements.md
okarney Sep 9, 2025
be35be8
Delete apps/docs/public/site_map.pdf
okarney Sep 9, 2025
79e1763
Add files via upload
okarney Sep 9, 2025
71493ed
Delete apps/docs/public/CISC474 - Individual Project Site Map (1).pdf
okarney Sep 9, 2025
81a7a49
Add files via upload
okarney Sep 9, 2025
2472722
Rename CISC474 - Individual Project Site Map (2).pdf to site_map.pdf
okarney Sep 9, 2025
f69912b
Add files via upload
okarney Sep 9, 2025
1d796af
Delete apps/docs/public/CISC474 - Main Screens Wire Frames.pdf
okarney Sep 9, 2025
1f4e89a
Add files via upload
okarney Sep 9, 2025
56ae183
Rename CISC474 - Main Screens Wire Frames (1).pdf to wireframes.pdf
okarney Sep 9, 2025
6ce0653
Update web_application_planning_docs.md
okarney Sep 9, 2025
712c108
Update web_application_planning_docs.md
okarney Sep 9, 2025
d183c16
Update web_application_planning_docs.md
okarney Sep 9, 2025
e7fc1f3
Update web_application_planning_docs.md
okarney Sep 9, 2025
5e57baf
Delete apps/docs/public/requirements.md
okarney Sep 9, 2025
d82272e
Learning Next.js assignment. Created 5 pages that link to eachother.
okarney Sep 12, 2025
d9e4509
Merge branch 'main' of https://github.com/okarney/f25-cisc474-individual
okarney Sep 12, 2025
71d8668
Created schema.prisma and seed.ts file. Added test data from Supabase…
okarney Sep 20, 2025
33a9c31
Create database_schema_and_data.md
okarney Sep 20, 2025
28728ce
Update database_schema_and_data.md
okarney Sep 20, 2025
9e926f8
Update database_schema_and_data.md
okarney Sep 20, 2025
bd5b6d3
Update database_schema_and_data.md
okarney Sep 20, 2025
5ee6032
Update database_schema_and_data.md
okarney Sep 20, 2025
9d83d8d
Fixed formatting in schema.prisma
okarney Sep 20, 2025
4808063
Merge branch 'main' of https://github.com/okarney/f25-cisc474-individual
okarney Sep 20, 2025
eaa5704
Update database_schema_and_data.md
okarney Sep 20, 2025
118c3e2
Merge branch 'UD-CISC474-F25:main' into main
okarney Sep 24, 2025
0ac24d5
Added some logic for a user controller/module/service
okarney Sep 25, 2025
c1b5de2
More adjustment attempts.
okarney Sep 25, 2025
840199a
Small adjustment to configuration after merging with Bart's corrected…
okarney Sep 25, 2025
cb498bc
trying to merge main into create_backend
okarney Sep 25, 2025
92ad5a6
More attempts to connect to prisma
okarney Sep 25, 2025
51eb4cf
Successful connection to prisma database for users table.
okarney Sep 25, 2025
183139d
Added courses controller/module/service.
okarney Sep 25, 2025
6ee495c
Added enrollment service/module/controller.
okarney Sep 25, 2025
fe3a945
Added service/module/controller for Submission and Assignments tables…
okarney Sep 25, 2025
8f34028
Added service/module/controller for Feedback table.
okarney Sep 25, 2025
47d84d6
Merge pull request #1 from okarney/create_backend
okarney Sep 25, 2025
cffe7f2
Create nestjs_backend_endpoints.md
okarney Sep 25, 2025
03e6563
Update nestjs_backend_endpoints.md
okarney Sep 25, 2025
8ef82c5
Update nestjs_backend_endpoints.md
okarney Sep 25, 2025
d1ab7cf
Connected back and frontend with client components.
okarney Oct 5, 2025
df687a1
Updated enrollment file function name.
okarney Oct 5, 2025
e3c939e
Merge pull request #2 from okarney/connect_front_back_end
okarney Oct 5, 2025
b840149
Merge remote-tracking branch 'upstream/main'
okarney Oct 6, 2025
fb0ddbb
Switched to tanstack, switching to tailwind CSS, and wiring up backend
okarney Oct 8, 2025
7f82879
Connected courses page to be able to get the correct assignments from…
okarney Oct 9, 2025
4ce21c2
Wired up course/assignment page to dynamically link to the appropriat…
okarney Oct 10, 2025
cc2b920
Tried to delete package-lock.json and npm install again in hopes of a…
okarney Oct 10, 2025
4694d31
Deleted and reinstalled node_modules and package-lock.json as suggest…
okarney Oct 10, 2025
ef85f8f
Updated main.ts CORS to hopefully give the backend access to the fron…
okarney Oct 10, 2025
c2a9cca
Updated main.ts again.
okarney Oct 10, 2025
89fe0da
created files for dtos in packages/api
okarney Oct 16, 2025
0692e5c
Attempted to connect back and frontend with dto for index.tsx
okarney Oct 17, 2025
c541f80
Creation functionality is working
okarney Oct 17, 2025
c1b7a36
Working on update functionality
okarney Oct 17, 2025
2124135
Update Functionality is working on the course page.
okarney Oct 17, 2025
15da1db
Create, Update, and Delete functionalities completed with a descripti…
okarney Oct 20, 2025
9809a2d
Made adjustments to add authentication following the backend instruct…
okarney Oct 23, 2025
18e3237
Attempted to get auth0 working for the frontend.
okarney Oct 23, 2025
892791b
Fixed env issue and cleaned up old messaging on the frontend dashboar…
okarney Oct 24, 2025
a27a982
Attempting to deploy again.
okarney Oct 24, 2025
69ebdff
Fixed linting error hoping that now it will deploy.
okarney Oct 24, 2025
dd00996
Commented out bad lines related to old backend fetcher.
okarney Oct 24, 2025
68885ca
Adjusted wrangler.jsonc entry point.
okarney Oct 24, 2025
0d66c27
Another adjustment to wrangler.jsonc.
okarney Oct 24, 2025
3f4d8b3
One more attempt to adjust wrangler.jsonc
okarney Oct 24, 2025
bd3e4b4
Adjusting wrangler.jsonc for directories.
okarney Oct 24, 2025
d4ed3b8
Reversed changes to wrangler.jsonc since they didn't fix the problem.
okarney Oct 24, 2025
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
9 changes: 9 additions & 0 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,16 @@
"@isaacs/brace-expansion": "^5.0.0",
"@nestjs/common": "^11.0.0",
"@nestjs/core": "^11.0.0",
"@nestjs/jwt": "^11.0.1",
"@nestjs/mapped-types": "*",
"@nestjs/passport": "^11.0.5",
"@nestjs/platform-express": "^11.0.0",
"@repo/api": "*",
"ansis": "^4.1.0",
"jwks-rsa": "^3.2.0",
"passport": "^0.7.0",
"passport-auth0": "^1.4.4",
"passport-jwt": "^4.0.1",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1"
},
Expand All @@ -36,6 +43,8 @@
"@types/express": "^4.17.17",
"@types/jest": "^30.0.0",
"@types/node": "^22.10.7",
"@types/passport-auth0": "^1.0.9",
"@types/passport-jwt": "^4.0.1",
"@types/supertest": "^6.0.0",
"jest": "^29.7.0",
"source-map-support": "^0.5.21",
Expand Down
5 changes: 4 additions & 1 deletion apps/api/src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { PrismaService } from './prisma.service';
import { User, Prisma } from './../../../packages/database/generated/client';

@Controller()
export class AppController {
Expand All @@ -9,4 +11,5 @@ export class AppController {
getHello(): string {
return this.appService.getHello();
}
}

}
14 changes: 11 additions & 3 deletions apps/api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@ import { LinksModule } from './links/links.module';

import { AppService } from './app.service';
import { AppController } from './app.controller';
import { PrismaService } from './prisma.service';
import { UsersModule } from './users/users.module';
import { CoursesModule } from './courses/courses.module';
import { EnrollmentModule } from './enrollment/enrollment.module';
import { AssignmentsModule } from './assignments/assignments.module';
import { SubmissionsModule } from './submissions/submissions.module';
import { FeedbackModule } from './feedback/feedback.module';
import { AuthModule } from './auth/auth.module';

@Module({
imports: [LinksModule],
imports: [LinksModule, UsersModule, CoursesModule, EnrollmentModule, AssignmentsModule, SubmissionsModule, FeedbackModule, AuthModule],
controllers: [AppController],
providers: [AppService],
providers: [AppService, PrismaService],
})
export class AppModule {}
export class AppModule {}
4 changes: 4 additions & 0 deletions apps/api/src/app.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Injectable()
export class AppService {
constructor(private prisma: PrismaService) {}

getHello(): string {
return 'Hello World!';
}

}
20 changes: 20 additions & 0 deletions apps/api/src/assignments/assignments.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AssignmentsController } from './assignments.controller';
import { AssignmentsService } from './assignments.service';

describe('AssignmentsController', () => {
let controller: AssignmentsController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [AssignmentsController],
providers: [AssignmentsService],
}).compile();

controller = module.get<AssignmentsController>(AssignmentsController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
22 changes: 22 additions & 0 deletions apps/api/src/assignments/assignments.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Controller, Get, Param } from '@nestjs/common';
import { AssignmentsService } from './assignments.service';

@Controller('assignments')
export class AssignmentsController {
constructor(private readonly assignmentsService: AssignmentsService) {}

@Get()
findAll() {
return this.assignmentsService.findAll();
}

@Get(':id')
findOne(@Param('id') id: string) {
return this.assignmentsService.findOne(id);
}

@Get('course/:course_id')
findCourseAssignments(@Param('course_id') course_id: string) {
return this.assignmentsService.findCourseAssignments(course_id);
}
}
10 changes: 10 additions & 0 deletions apps/api/src/assignments/assignments.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { AssignmentsService } from './assignments.service';
import { AssignmentsController } from './assignments.controller';
import { PrismaService } from '../prisma.service';

@Module({
controllers: [AssignmentsController],
providers: [AssignmentsService, PrismaService],
})
export class AssignmentsModule {}
18 changes: 18 additions & 0 deletions apps/api/src/assignments/assignments.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AssignmentsService } from './assignments.service';

describe('AssignmentsService', () => {
let service: AssignmentsService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [AssignmentsService],
}).compile();

service = module.get<AssignmentsService>(AssignmentsService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
20 changes: 20 additions & 0 deletions apps/api/src/assignments/assignments.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma.service';

@Injectable()
export class AssignmentsService {
constructor(private prisma: PrismaService) {}

async findAll() {
return this.prisma.assignment.findMany();
}

async findOne(id) {
return this.prisma.assignment.findUnique( {where: {assignment_id: id}} );
}

async findCourseAssignments(course_id) {
return this.prisma.assignment.findMany( {where: {assignment_course_id: course_id}})
}

}
18 changes: 18 additions & 0 deletions apps/api/src/auth/auth.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AuthController } from './auth.controller';

describe('AuthController', () => {
let controller: AuthController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [AuthController],
}).compile();

controller = module.get<AuthController>(AuthController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
4 changes: 4 additions & 0 deletions apps/api/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Controller } from '@nestjs/common';

@Controller('auth')
export class AuthController {}
14 changes: 14 additions & 0 deletions apps/api/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './jwt.strategy';
import { PrismaService } from 'src/prisma.service';

@Module({
imports: [PassportModule.register({ defaultStrategy: 'jwt' })],
controllers: [AuthController],
providers: [AuthService, JwtStrategy, PrismaService],
exports: [PassportModule],
})
export class AuthModule {}
18 changes: 18 additions & 0 deletions apps/api/src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from './auth.service';

describe('AuthService', () => {
let service: AuthService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [AuthService],
}).compile();

service = module.get<AuthService>(AuthService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
4 changes: 4 additions & 0 deletions apps/api/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';

@Injectable()
export class AuthService {}
9 changes: 9 additions & 0 deletions apps/api/src/auth/current-user.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { JwtUser } from './jwt.strategy';

export const CurrentUser = createParamDecorator(
(data: unknown, ctx: ExecutionContext): JwtUser => {
const req = ctx.switchToHttp().getRequest();
return req.user as JwtUser;
},
);
96 changes: 96 additions & 0 deletions apps/api/src/auth/jwt.strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { passportJwtSecret } from 'jwks-rsa';
import * as dotenv from 'dotenv';
import { PrismaService } from 'src/prisma.service';

dotenv.config();

type JwtPayload = {
sub: string; // e.g. "auth0|abc123" or "google-oauth2|xyz"
iss: string;
aud: string | string[];
scope?: string;
};

export interface JwtUser {
userId: string;
provider: string;
providerId: string;
sub: string;
scopes: string[];
}

function splitSub(sub: string) {
// "provider|id" → { provider, providerId }
const [provider, ...rest] = sub.split('|');
return { provider, providerId: rest.join('|') };
}

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly prisma: PrismaService) {
super({
secretOrKeyProvider: passportJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: `${process.env.AUTH0_ISSUER_URL}.well-known/jwks.json`,
}),

jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
audience: process.env.AUTH0_AUDIENCE,
issuer: `${process.env.AUTH0_ISSUER_URL}`,
algorithms: ['RS256'],
});
}

async validate(payload: JwtPayload): Promise<JwtUser> {
// You can see the JWT here
// console.log('JWT payload', payload);

const { sub } = payload;
const { provider, providerId } = splitSub(sub);

// 1) Find Authentication by provider+providerId
let auth = await this.prisma.authentication.findFirst({
where: { authentication_provider: provider, authentication_provider_id: providerId },
include: { user: true },
});

// 2) If missing, create User + Authentication (using whatever claims we have)
if (!auth) {
const user = await this.prisma.user.create({
data: {
user_name: payload['name'] ?? 'New User',
user_email:
(payload as any)?.email ??
`${providerId}@${provider}.example.com`,
user_role: 'STUDENT',
user_authentication: {
create: {
authentication_provider: provider,
authentication_provider_id: providerId,
},
},
},
});
auth = { ...auth, user } as any;
} else {
// 3) Update user profile fields opportunistically (don’t overwrite with nulls)
await this.prisma.user.update({
where: { user_id: auth.authentication_user_id },
data: {},
});
}

return {
userId: auth.authentication_user_id,
provider,
providerId,
sub,
scopes: (payload.scope ?? '').split(' ').filter(Boolean),
} as JwtUser;
}
}
20 changes: 20 additions & 0 deletions apps/api/src/courses/courses.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing';
import { CoursesController } from './courses.controller';
import { CoursesService } from './courses.service';

describe('CoursesController', () => {
let controller: CoursesController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [CoursesController],
providers: [CoursesService],
}).compile();

controller = module.get<CoursesController>(CoursesController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
Loading