Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
de18e52
setup & create task, category
maxn990 Aug 3, 2025
da5e6f7
fixed pr review comments
maxn990 Aug 5, 2025
20fd180
Merge pull request #13 from Code-4-Community/mn-1-2-create-task
amywng Aug 5, 2025
73da3ed
add label and migration to add tasks/labels tables
amywng Aug 6, 2025
270ea04
update datasource
maxn990 Aug 6, 2025
d728338
Merge pull request #14 from Code-4-Community/amy/create-label
amywng Aug 6, 2025
71338f1
finish setup
maxn990 Aug 8, 2025
9ba4ee5
Update example.env
maxn990 Aug 8, 2025
8f9f435
Merge pull request #16 from Code-4-Community/mn-15/setup-and-seeding
maxn990 Aug 8, 2025
16f1d6d
Create CreateTaskDTO
aaronashby Aug 10, 2025
9564ecf
Create post endpoint
aaronashby Aug 10, 2025
c51ac01
Merge branch 'main' into aa-3-create-task-route
aaronashby Aug 10, 2025
4ce5e12
Fixed db migration issues
aaronashby Aug 10, 2025
e5d2491
Final commit for the branch
dburkhart07 Aug 12, 2025
f358ad1
Created initally working endpoint. Still need to do some edge case ha…
dburkhart07 Aug 12, 2025
5e685d1
add npm run test
maxn990 Aug 12, 2025
c4399e8
Merge pull request #18 from Code-4-Community/mn-testing
maxn990 Aug 12, 2025
6532e66
Added testing
dburkhart07 Aug 12, 2025
232996c
Removed e2e testing
dburkhart07 Aug 12, 2025
e79d900
Completed unit tests
dburkhart07 Aug 12, 2025
82f2e26
Finished test updates
dburkhart07 Aug 12, 2025
51f5d51
Create CODEOWNERS
maxn990 Aug 12, 2025
a08684e
Merge pull request #19 from Code-4-Community/maxn990-patch-1
maxn990 Aug 12, 2025
4f52de0
Merged main into branch
dburkhart07 Aug 12, 2025
bb0a0a6
Completed testing
dburkhart07 Aug 12, 2025
468b224
Refactor task creation DTO and service logic
aaronashby Aug 12, 2025
19de9b9
Merge branch 'main' into aa-3-create-task-route
aaronashby Aug 12, 2025
0f5370a
Simplified task creation
aaronashby Aug 12, 2025
b196f0c
Added unit tests for controller
aaronashby Aug 13, 2025
331258d
Added unit tests for service
aaronashby Aug 14, 2025
8607013
Merge pull request #20 from Code-4-Community/7-move-task-route
dburkhart07 Aug 14, 2025
4b4b026
Resolved merge conflicts
dburkhart07 Aug 14, 2025
fdc030c
Merge pull request #17 from Code-4-Community/11-get-all-tasks
dburkhart07 Aug 14, 2025
f1dadd9
Merge branch 'main' into aa-3-create-task-route
aaronashby Aug 14, 2025
fefbc1a
Merge pull request #21 from Code-4-Community/aa-3-create-task-route
aaronashby Aug 14, 2025
151659f
setup frontend tickets
maxn990 Aug 17, 2025
05d7ee4
Merge pull request #26 from Code-4-Community/mn-components
maxn990 Aug 17, 2025
955fedb
move to src
maxn990 Aug 17, 2025
7b27ff7
Merge pull request #27 from Code-4-Community/mn-components
maxn990 Aug 17, 2025
661e74c
implemented/tested delete_labels route
Ryaken-Nakamoto Aug 18, 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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @maxn990 @amywng
10 changes: 0 additions & 10 deletions apps/backend-e2e/src/apps/backend/apps/backend.spec.ts

This file was deleted.

9 changes: 7 additions & 2 deletions apps/backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ import { TypeOrmModule } from '@nestjs/typeorm';

import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TaskModule } from './task/task.module';
import AppDataSource from './data-source';
import { TaskModule } from './task/task.module';
import { LabelModule } from './label/label.module';

@Module({
imports: [TypeOrmModule.forRoot(AppDataSource.options), TaskModule],
imports: [
TypeOrmModule.forRoot(AppDataSource.options),
TaskModule,
LabelModule,
],
controllers: [AppController],
providers: [AppService],
})
Expand Down
18 changes: 0 additions & 18 deletions apps/backend/src/auth/auth.controller.spec.ts

This file was deleted.

18 changes: 0 additions & 18 deletions apps/backend/src/auth/auth.service.spec.ts

This file was deleted.

3 changes: 2 additions & 1 deletion apps/backend/src/data-source.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DataSource } from 'typeorm';
import { PluralNamingStrategy } from './strategies/plural-naming.strategy';
import { Task } from './task/types/task.entity';
import { Label } from './label/types/label.entity';
import * as dotenv from 'dotenv';

dotenv.config();
Expand All @@ -12,7 +13,7 @@ const AppDataSource = new DataSource({
username: process.env.NX_DB_USERNAME,
password: process.env.NX_DB_PASSWORD,
database: process.env.NX_DB_DATABASE,
entities: [Task],
entities: [Task, Label],
migrations: ['apps/backend/src/migrations/*.js'],
// Setting synchronize: true shouldn't be used in production - otherwise you can lose production data
synchronize: false,
Expand Down
30 changes: 30 additions & 0 deletions apps/backend/src/label/label.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Test, TestingModule } from '@nestjs/testing';
import { LabelsController } from './label.controller';
import { LabelsService } from './label.service';

// Mock implementation for LabelsService
const mockLabelService = {};

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

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [LabelsController],
providers: [
{
provide: LabelsService,
useValue: mockLabelService,
},
],
}).compile();

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

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

/* Test for create new label */
});
27 changes: 27 additions & 0 deletions apps/backend/src/label/label.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {
Controller,
Get,

Check warning on line 3 in apps/backend/src/label/label.controller.ts

View workflow job for this annotation

GitHub Actions / pre-deploy

'Get' is defined but never used
Post,

Check warning on line 4 in apps/backend/src/label/label.controller.ts

View workflow job for this annotation

GitHub Actions / pre-deploy

'Post' is defined but never used
Body,

Check warning on line 5 in apps/backend/src/label/label.controller.ts

View workflow job for this annotation

GitHub Actions / pre-deploy

'Body' is defined but never used
Patch,

Check warning on line 6 in apps/backend/src/label/label.controller.ts

View workflow job for this annotation

GitHub Actions / pre-deploy

'Patch' is defined but never used
Param,

Check warning on line 7 in apps/backend/src/label/label.controller.ts

View workflow job for this annotation

GitHub Actions / pre-deploy

'Param' is defined but never used
Delete,

Check warning on line 8 in apps/backend/src/label/label.controller.ts

View workflow job for this annotation

GitHub Actions / pre-deploy

'Delete' is defined but never used
Query,

Check warning on line 9 in apps/backend/src/label/label.controller.ts

View workflow job for this annotation

GitHub Actions / pre-deploy

'Query' is defined but never used
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { LabelsService } from './label.service';
import { Label } from './types/label.entity';

@ApiTags('labels')
@Controller('labels')
export class LabelsController {
constructor(private readonly labelsService: LabelsService) {}

/** Creates a new label.
* @param LabelDto - The data transfer object containing label details.
* @returns The created label.
* @throws BadRequestException if the label name is not unique
* @throws BadRequestException if label name is not provided
* @throws BadRequestException if color is not provided or is not hexadecimal
*/
}
13 changes: 13 additions & 0 deletions apps/backend/src/label/label.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Label } from './types/label.entity';
import { LabelsService } from './label.service';
import { LabelsController } from './label.controller';

@Module({
imports: [TypeOrmModule.forFeature([Label])],
providers: [LabelsService],
controllers: [LabelsController],
exports: [LabelsService],
})
export class LabelModule {}
32 changes: 32 additions & 0 deletions apps/backend/src/label/label.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Test, TestingModule } from '@nestjs/testing';
import { mock } from 'jest-mock-extended';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Label } from './types/label.entity';
import { LabelsService } from './label.service';

const mockLabelsRepository = mock<Repository<Label>>();

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

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
LabelsService,
{
provide: getRepositoryToken(Label),
useValue: mockLabelsRepository,
},
],
}).compile();

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

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

/* Tests for create new label */
});
14 changes: 14 additions & 0 deletions apps/backend/src/label/label.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Label } from './types/label.entity';

@Injectable()
export class LabelsService {
constructor(
@InjectRepository(Label)
private labelRepository: Repository<Label>,
) {}

// Creates a new label
}
20 changes: 20 additions & 0 deletions apps/backend/src/label/types/label.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Column, Entity, PrimaryGeneratedColumn, ManyToMany } from 'typeorm';
import { Task } from '../../task/types/task.entity';

@Entity()
export class Label {
@PrimaryGeneratedColumn()
id: number;

@Column({ unique: true })
name: string;

@Column({ nullable: true })
description: string;

@Column()
color: string;

@ManyToMany(() => Task, (task) => task.labels)
tasks: Task[];
}
19 changes: 0 additions & 19 deletions apps/backend/src/migrations/1754254886189-add_task.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class AddLabelRelationToTask1754510950040 implements MigrationInterface {
name = 'AddLabelRelationToTask1754510950040';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TYPE "public"."tasks_category_enum" AS ENUM('Draft', 'To Do', 'In Progress', 'Completed')`,
);
await queryRunner.query(
`CREATE TABLE "labels" ("id" SERIAL NOT NULL, "name" character varying NOT NULL, "description" character varying, "color" character varying NOT NULL, CONSTRAINT "UQ_543605929e5ebe08eeeab493f60" UNIQUE ("name"), CONSTRAINT "PK_c0c4e97f76f1f3a268c7a70b925" PRIMARY KEY ("id"))`,
);
await queryRunner.query(
`CREATE TABLE "tasks" ("id" SERIAL NOT NULL, "title" character varying NOT NULL, "description" character varying, "dateCreated" TIMESTAMP NOT NULL DEFAULT now(), "dueDate" TIMESTAMP, "category" "public"."tasks_category_enum" NOT NULL DEFAULT 'Draft', CONSTRAINT "PK_8d12ff38fcc62aaba2cab748772" PRIMARY KEY ("id"))`,
);
await queryRunner.query(
`CREATE TABLE "tasks_labels_labels" ("tasksId" integer NOT NULL, "labelsId" integer NOT NULL, CONSTRAINT "PK_f85aea2ec53934cf2a19c64d5ac" PRIMARY KEY ("tasksId", "labelsId"))`,
);
await queryRunner.query(
`CREATE INDEX "IDX_f20c9d0af5f9650c92f0b95001" ON "tasks_labels_labels" ("tasksId") `,
);
await queryRunner.query(
`CREATE INDEX "IDX_9eb372639eba51a1539303cca9" ON "tasks_labels_labels" ("labelsId") `,
);
await queryRunner.query(
`ALTER TABLE "tasks_labels_labels" ADD CONSTRAINT "FK_f20c9d0af5f9650c92f0b95001c" FOREIGN KEY ("tasksId") REFERENCES "tasks"("id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
await queryRunner.query(
`ALTER TABLE "tasks_labels_labels" ADD CONSTRAINT "FK_9eb372639eba51a1539303cca97" FOREIGN KEY ("labelsId") REFERENCES "labels"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "tasks_labels_labels" DROP CONSTRAINT "FK_9eb372639eba51a1539303cca97"`,
);
await queryRunner.query(
`ALTER TABLE "tasks_labels_labels" DROP CONSTRAINT "FK_f20c9d0af5f9650c92f0b95001c"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_9eb372639eba51a1539303cca9"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_f20c9d0af5f9650c92f0b95001"`,
);
await queryRunner.query(`DROP TABLE "tasks_labels_labels"`);
await queryRunner.query(`DROP TABLE "tasks"`);
await queryRunner.query(`DROP TABLE "labels"`);
await queryRunner.query(`DROP TYPE "public"."tasks_category_enum"`);
}
}
95 changes: 95 additions & 0 deletions apps/backend/src/seeds/seed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import dataSource from '../data-source'; // adjust path as needed
import { Task } from '../task/types/task.entity';
import { Label } from '../label/types/label.entity';
import { TaskCategory } from '../task/types/category';

async function seed() {
try {
console.log('🌱 Starting database seed...');

// Initialize the data source
await dataSource.initialize();
console.log('✅ Database connection established');

// Clear existing data (drop and recreate schema)
console.log('🧹 Clearing existing data...');
await dataSource.query('DROP SCHEMA public CASCADE; CREATE SCHEMA public;');

// Recreate tables
await dataSource.synchronize();
console.log('✅ Database schema synchronized');

// Create labels
console.log('🏷️ Creating labels...');
const labels = await dataSource.getRepository(Label).save([
{ name: 'High Priority', color: '#FF4444' },
{ name: 'Bug Fix', color: '#FF8800' },
{ name: 'Feature', color: '#00AA00' },
{ name: 'Documentation', color: '#4488FF' },
]);
console.log(`✅ Created ${labels.length} labels`);

// Create tasks
console.log('📝 Creating tasks...');
const tasks = await dataSource.getRepository(Task).save([
{
title: 'Complete project proposal',
description: 'Draft and finalize the Q4 project proposal document',
dueDate: new Date('2025-08-15'),
category: TaskCategory.IN_PROGRESS,
},
{
title: 'Review code changes',
description: 'Review pull requests for the authentication module',
dueDate: new Date('2025-08-10'),
category: TaskCategory.TODO,
},
{
title: 'Team meeting preparation',
description: 'Prepare agenda and materials for weekly team sync',
dueDate: new Date('2025-08-09'),
category: TaskCategory.COMPLETED,
},
{
title: 'Update documentation',
description: 'Update API documentation with recent endpoint changes',
category: TaskCategory.DRAFT,
},
]);
console.log(`✅ Created ${tasks.length} tasks`);

// Optionally assign some labels to tasks
console.log('🔗 Assigning labels to tasks...');

// Assign "High Priority" and "Feature" to first task
tasks[0].labels = [labels[0], labels[2]];
await dataSource.getRepository(Task).save(tasks[0]);

// Assign "Bug Fix" to second task
tasks[1].labels = [labels[1]];
await dataSource.getRepository(Task).save(tasks[1]);

// Assign "Documentation" to last task
tasks[3].labels = [labels[3]];
await dataSource.getRepository(Task).save(tasks[3]);

console.log('✅ Labels assigned to tasks');

console.log('🎉 Database seed completed successfully!');
} catch (error) {
console.error('❌ Seed failed:', error);
throw error;
} finally {
// Close the database connection
if (dataSource.isInitialized) {
await dataSource.destroy();
console.log('✅ Database connection closed');
}
}
}

// Run the seed function
seed().catch((error) => {
console.error('❌ Fatal error during seed:', error);
process.exit(1);
});
Loading
Loading