diff --git a/README.md b/README.md
index 08515a9f..463203bd 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Scaffolding
+# Jumpstart
@@ -32,10 +32,4 @@ To run both the frontend and backend with one command:
```
nx run-many -t serve -p frontend backend
-```
-
-## Other commands
-
-Run `git submodule update --remote` to pull the latest changes from the component library
-
-When cloning the repo, make sure to add the `--recurse-modules` flag to also clone the component library submodule (e.g. `git clone --recurse-submodules https://github.com/Code-4-Community/scaffolding.git` for the `scaffolding` repo)
+```
\ No newline at end of file
diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts
index 54fb044e..8ed15a46 100644
--- a/apps/backend/src/app.module.ts
+++ b/apps/backend/src/app.module.ts
@@ -1,14 +1,21 @@
+/*
import { Module } from '@nestjs/common';
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],
})
export class AppModule {}
+*/
\ No newline at end of file
diff --git a/apps/backend/src/auth/auth.controller.spec.ts b/apps/backend/src/auth/auth.controller.spec.ts
deleted file mode 100644
index 27a31e61..00000000
--- a/apps/backend/src/auth/auth.controller.spec.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-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);
- });
-
- it('should be defined', () => {
- expect(controller).toBeDefined();
- });
-});
diff --git a/apps/backend/src/auth/auth.controller.ts b/apps/backend/src/auth/auth.controller.ts
deleted file mode 100644
index bb04b6b7..00000000
--- a/apps/backend/src/auth/auth.controller.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-import {
- BadRequestException,
- Body,
- Controller,
- Post,
- Request,
- UseGuards,
-} from '@nestjs/common';
-
-import { SignInDto } from './dtos/sign-in.dto';
-import { SignUpDto } from './dtos/sign-up.dto';
-import { AuthService } from './auth.service';
-import { UsersService } from '../users/users.service';
-import { VerifyUserDto } from './dtos/verify-user.dto';
-import { DeleteUserDto } from './dtos/delete-user.dto';
-import { User } from '../users/user.entity';
-import { SignInResponseDto } from './dtos/sign-in-response.dto';
-import { RefreshTokenDto } from './dtos/refresh-token.dto';
-import { AuthGuard } from '@nestjs/passport';
-import { ConfirmPasswordDto } from './dtos/confirm-password.dto';
-import { ForgotPasswordDto } from './dtos/forgot-password.dto';
-import { ApiTags } from '@nestjs/swagger';
-
-@ApiTags('Auth')
-@Controller('auth')
-export class AuthController {
- constructor(
- private authService: AuthService,
- private usersService: UsersService,
- ) {}
-
- @Post('/signup')
- async createUser(@Body() signUpDto: SignUpDto): Promise {
- // By default, creates a standard user
- try {
- await this.authService.signup(signUpDto);
- } catch (e) {
- throw new BadRequestException(e.message);
- }
-
- const user = await this.usersService.create(
- signUpDto.email,
- signUpDto.firstName,
- signUpDto.lastName,
- );
-
- return user;
- }
-
- // TODO deprecated if verification code is replaced by link
- @Post('/verify')
- verifyUser(@Body() body: VerifyUserDto): void {
- try {
- this.authService.verifyUser(body.email, body.verificationCode);
- } catch (e) {
- throw new BadRequestException(e.message);
- }
- }
-
- @Post('/signin')
- signin(@Body() signInDto: SignInDto): Promise {
- return this.authService.signin(signInDto);
- }
-
- @Post('/refresh')
- refresh(@Body() refreshDto: RefreshTokenDto): Promise {
- return this.authService.refreshToken(refreshDto);
- }
-
- @Post('/forgotPassword')
- forgotPassword(@Body() body: ForgotPasswordDto): Promise {
- return this.authService.forgotPassword(body.email);
- }
-
- @Post('/confirmPassword')
- confirmPassword(@Body() body: ConfirmPasswordDto): Promise {
- return this.authService.confirmForgotPassword(body);
- }
-
- @Post('/delete')
- async delete(@Body() body: DeleteUserDto): Promise {
- const user = await this.usersService.findOne(body.userId);
-
- try {
- await this.authService.deleteUser(user.email);
- } catch (e) {
- throw new BadRequestException(e.message);
- }
-
- this.usersService.remove(user.id);
- }
-}
diff --git a/apps/backend/src/auth/auth.module.ts b/apps/backend/src/auth/auth.module.ts
deleted file mode 100644
index 09f5965c..00000000
--- a/apps/backend/src/auth/auth.module.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { Module } from '@nestjs/common';
-import { TypeOrmModule } from '@nestjs/typeorm';
-import { PassportModule } from '@nestjs/passport';
-
-import { AuthController } from './auth.controller';
-import { AuthService } from './auth.service';
-import { UsersService } from '../users/users.service';
-import { User } from '../users/user.entity';
-import { JwtStrategy } from './jwt.strategy';
-
-@Module({
- imports: [
- TypeOrmModule.forFeature([User]),
- PassportModule.register({ defaultStrategy: 'jwt' }),
- ],
- controllers: [AuthController],
- providers: [AuthService, UsersService, JwtStrategy],
-})
-export class AuthModule {}
diff --git a/apps/backend/src/auth/auth.service.spec.ts b/apps/backend/src/auth/auth.service.spec.ts
deleted file mode 100644
index 800ab662..00000000
--- a/apps/backend/src/auth/auth.service.spec.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-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);
- });
-
- it('should be defined', () => {
- expect(service).toBeDefined();
- });
-});
diff --git a/apps/backend/src/auth/auth.service.ts b/apps/backend/src/auth/auth.service.ts
deleted file mode 100644
index d78a12dd..00000000
--- a/apps/backend/src/auth/auth.service.ts
+++ /dev/null
@@ -1,179 +0,0 @@
-import { Injectable } from '@nestjs/common';
-import {
- AdminDeleteUserCommand,
- AdminInitiateAuthCommand,
- AttributeType,
- CognitoIdentityProviderClient,
- ConfirmForgotPasswordCommand,
- ConfirmSignUpCommand,
- ForgotPasswordCommand,
- ListUsersCommand,
- SignUpCommand,
-} from '@aws-sdk/client-cognito-identity-provider';
-
-import CognitoAuthConfig from './aws-exports';
-import { SignUpDto } from './dtos/sign-up.dto';
-import { SignInDto } from './dtos/sign-in.dto';
-import { SignInResponseDto } from './dtos/sign-in-response.dto';
-import { createHmac } from 'crypto';
-import { RefreshTokenDto } from './dtos/refresh-token.dto';
-import { Status } from '../users/types';
-import { ConfirmPasswordDto } from './dtos/confirm-password.dto';
-
-@Injectable()
-export class AuthService {
- private readonly providerClient: CognitoIdentityProviderClient;
- private readonly clientSecret: string;
-
- constructor() {
- this.providerClient = new CognitoIdentityProviderClient({
- region: CognitoAuthConfig.region,
- credentials: {
- accessKeyId: process.env.NX_AWS_ACCESS_KEY,
- secretAccessKey: process.env.NX_AWS_SECRET_ACCESS_KEY,
- },
- });
-
- this.clientSecret = process.env.COGNITO_CLIENT_SECRET;
- }
-
- // Computes secret hash to authenticate this backend to Cognito
- // Hash key is the Cognito client secret, message is username + client ID
- // Username value depends on the command
- // (see https://docs.aws.amazon.com/cognito/latest/developerguide/signing-up-users-in-your-app.html#cognito-user-pools-computing-secret-hash)
- calculateHash(username: string): string {
- const hmac = createHmac('sha256', this.clientSecret);
- hmac.update(username + CognitoAuthConfig.clientId);
- return hmac.digest('base64');
- }
-
- async getUser(userSub: string): Promise {
- const listUsersCommand = new ListUsersCommand({
- UserPoolId: CognitoAuthConfig.userPoolId,
- Filter: `sub = "${userSub}"`,
- });
-
- // TODO need error handling
- const { Users } = await this.providerClient.send(listUsersCommand);
- return Users[0].Attributes;
- }
-
- async signup(
- { firstName, lastName, email, password }: SignUpDto,
- status: Status = Status.STANDARD,
- ): Promise {
- // Needs error handling
- const signUpCommand = new SignUpCommand({
- ClientId: CognitoAuthConfig.clientId,
- SecretHash: this.calculateHash(email),
- Username: email,
- Password: password,
- UserAttributes: [
- {
- Name: 'name',
- Value: `${firstName} ${lastName}`,
- },
- // Optional: add a custom Cognito attribute called "role" that also stores the user's status/role
- // If you choose to do so, you'll have to first add this custom attribute in your user pool
- {
- Name: 'custom:role',
- Value: status,
- },
- ],
- });
-
- const response = await this.providerClient.send(signUpCommand);
- return response.UserConfirmed;
- }
-
- async verifyUser(email: string, verificationCode: string): Promise {
- const confirmCommand = new ConfirmSignUpCommand({
- ClientId: CognitoAuthConfig.clientId,
- SecretHash: this.calculateHash(email),
- Username: email,
- ConfirmationCode: verificationCode,
- });
-
- await this.providerClient.send(confirmCommand);
- }
-
- async signin({ email, password }: SignInDto): Promise {
- const signInCommand = new AdminInitiateAuthCommand({
- AuthFlow: 'ADMIN_USER_PASSWORD_AUTH',
- ClientId: CognitoAuthConfig.clientId,
- UserPoolId: CognitoAuthConfig.userPoolId,
- AuthParameters: {
- USERNAME: email,
- PASSWORD: password,
- SECRET_HASH: this.calculateHash(email),
- },
- });
-
- const response = await this.providerClient.send(signInCommand);
-
- return {
- accessToken: response.AuthenticationResult.AccessToken,
- refreshToken: response.AuthenticationResult.RefreshToken,
- idToken: response.AuthenticationResult.IdToken,
- };
- }
-
- // Refresh token hash uses a user's sub (unique ID), not their username (typically their email)
- async refreshToken({
- refreshToken,
- userSub,
- }: RefreshTokenDto): Promise {
- const refreshCommand = new AdminInitiateAuthCommand({
- AuthFlow: 'REFRESH_TOKEN_AUTH',
- ClientId: CognitoAuthConfig.clientId,
- UserPoolId: CognitoAuthConfig.userPoolId,
- AuthParameters: {
- REFRESH_TOKEN: refreshToken,
- SECRET_HASH: this.calculateHash(userSub),
- },
- });
-
- const response = await this.providerClient.send(refreshCommand);
-
- return {
- accessToken: response.AuthenticationResult.AccessToken,
- refreshToken: refreshToken,
- idToken: response.AuthenticationResult.IdToken,
- };
- }
-
- async forgotPassword(email: string) {
- const forgotCommand = new ForgotPasswordCommand({
- ClientId: CognitoAuthConfig.clientId,
- Username: email,
- SecretHash: this.calculateHash(email),
- });
-
- await this.providerClient.send(forgotCommand);
- }
-
- async confirmForgotPassword({
- email,
- confirmationCode,
- newPassword,
- }: ConfirmPasswordDto) {
- const confirmComamnd = new ConfirmForgotPasswordCommand({
- ClientId: CognitoAuthConfig.clientId,
- SecretHash: this.calculateHash(email),
- Username: email,
- ConfirmationCode: confirmationCode,
- Password: newPassword,
- });
-
- await this.providerClient.send(confirmComamnd);
- }
-
- async deleteUser(email: string): Promise {
- const adminDeleteUserCommand = new AdminDeleteUserCommand({
- Username: email,
- UserPoolId: CognitoAuthConfig.userPoolId,
- });
-
- await this.providerClient.send(adminDeleteUserCommand);
- }
-}
diff --git a/apps/backend/src/auth/aws-exports.ts b/apps/backend/src/auth/aws-exports.ts
deleted file mode 100644
index 5c3a2dec..00000000
--- a/apps/backend/src/auth/aws-exports.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-const CognitoAuthConfig = {
- userPoolId: 'USER POOL ID HERE',
- clientId: 'CLIENT ID HERE',
- region: 'us-east-2',
-};
-
-export default CognitoAuthConfig;
diff --git a/apps/backend/src/auth/dtos/confirm-password.dto.ts b/apps/backend/src/auth/dtos/confirm-password.dto.ts
deleted file mode 100644
index ec1d63bb..00000000
--- a/apps/backend/src/auth/dtos/confirm-password.dto.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { IsEmail, IsString } from 'class-validator';
-
-export class ConfirmPasswordDto {
- @IsEmail()
- email: string;
-
- @IsString()
- newPassword: string;
-
- @IsString()
- confirmationCode: string;
-}
diff --git a/apps/backend/src/auth/dtos/delete-user.dto.ts b/apps/backend/src/auth/dtos/delete-user.dto.ts
deleted file mode 100644
index 1a616376..00000000
--- a/apps/backend/src/auth/dtos/delete-user.dto.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { IsPositive } from 'class-validator';
-
-export class DeleteUserDto {
- @IsPositive()
- userId: number;
-}
diff --git a/apps/backend/src/auth/dtos/forgot-password.dto.ts b/apps/backend/src/auth/dtos/forgot-password.dto.ts
deleted file mode 100644
index bbedf083..00000000
--- a/apps/backend/src/auth/dtos/forgot-password.dto.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { IsEmail } from 'class-validator';
-
-export class ForgotPasswordDto {
- @IsEmail()
- email: string;
-}
diff --git a/apps/backend/src/auth/dtos/refresh-token.dto.ts b/apps/backend/src/auth/dtos/refresh-token.dto.ts
deleted file mode 100644
index f67905d3..00000000
--- a/apps/backend/src/auth/dtos/refresh-token.dto.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { IsString } from 'class-validator';
-
-export class RefreshTokenDto {
- @IsString()
- refreshToken: string;
-
- @IsString()
- userSub: string;
-}
diff --git a/apps/backend/src/auth/dtos/sign-in-response.dto.ts b/apps/backend/src/auth/dtos/sign-in-response.dto.ts
deleted file mode 100644
index 571a02f8..00000000
--- a/apps/backend/src/auth/dtos/sign-in-response.dto.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-export class SignInResponseDto {
- /**
- * The JWT access token to be passed in API requests
- * @example eyJ...
- */
- accessToken: string;
-
- /**
- * The JWT refresh token to maintain user sessions by requesting new access tokens
- * @example eyJ...
- */
- refreshToken: string;
-
- /**
- * The JWT ID token that carries the user's information
- * @example eyJ...
- */
- idToken: string;
-}
diff --git a/apps/backend/src/auth/dtos/sign-in.dto.ts b/apps/backend/src/auth/dtos/sign-in.dto.ts
deleted file mode 100644
index 51cd9c95..00000000
--- a/apps/backend/src/auth/dtos/sign-in.dto.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { IsEmail, IsString } from 'class-validator';
-
-export class SignInDto {
- @IsEmail()
- email: string;
-
- @IsString()
- password: string;
-}
diff --git a/apps/backend/src/auth/dtos/sign-up.dto.ts b/apps/backend/src/auth/dtos/sign-up.dto.ts
deleted file mode 100644
index 5756f186..00000000
--- a/apps/backend/src/auth/dtos/sign-up.dto.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { IsEmail, IsString } from 'class-validator';
-
-export class SignUpDto {
- @IsString()
- firstName: string;
-
- @IsString()
- lastName: string;
-
- @IsEmail()
- email: string;
-
- @IsString()
- password: string;
-}
diff --git a/apps/backend/src/auth/dtos/verify-user.dto.ts b/apps/backend/src/auth/dtos/verify-user.dto.ts
deleted file mode 100644
index 66391605..00000000
--- a/apps/backend/src/auth/dtos/verify-user.dto.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { IsEmail, IsString } from 'class-validator';
-
-export class VerifyUserDto {
- @IsEmail()
- email: string;
-
- @IsString()
- verificationCode: string;
-}
diff --git a/apps/backend/src/auth/jwt.strategy.ts b/apps/backend/src/auth/jwt.strategy.ts
deleted file mode 100644
index 44d8789d..00000000
--- a/apps/backend/src/auth/jwt.strategy.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { Injectable } from '@nestjs/common';
-import { PassportStrategy } from '@nestjs/passport';
-import { passportJwtSecret } from 'jwks-rsa';
-import { ExtractJwt, Strategy } from 'passport-jwt';
-
-import CognitoAuthConfig from './aws-exports';
-
-@Injectable()
-export class JwtStrategy extends PassportStrategy(Strategy) {
- constructor() {
- const cognitoAuthority = `https://cognito-idp.${CognitoAuthConfig.region}.amazonaws.com/${CognitoAuthConfig.userPoolId}`;
-
- super({
- jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
- ignoreExpiration: false,
- _audience: CognitoAuthConfig.clientId,
- issuer: cognitoAuthority,
- algorithms: ['RS256'],
- secretOrKeyProvider: passportJwtSecret({
- cache: true,
- rateLimit: true,
- jwksRequestsPerMinute: 5,
- jwksUri: cognitoAuthority + '/.well-known/jwks.json',
- }),
- });
- }
-
- async validate(payload) {
- return { idUser: payload.sub, email: payload.email };
- }
-}
diff --git a/apps/backend/src/data-source.ts b/apps/backend/src/data-source.ts
index 4cd06624..dff1bf6a 100644
--- a/apps/backend/src/data-source.ts
+++ b/apps/backend/src/data-source.ts
@@ -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();
@@ -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,
diff --git a/apps/backend/src/interceptors/current-user.interceptor.ts b/apps/backend/src/interceptors/current-user.interceptor.ts
deleted file mode 100644
index 3d5d8297..00000000
--- a/apps/backend/src/interceptors/current-user.interceptor.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import {
- Injectable,
- NestInterceptor,
- ExecutionContext,
- CallHandler,
-} from '@nestjs/common';
-import { AuthService } from '../auth/auth.service';
-import { UsersService } from '../users/users.service';
-
-@Injectable()
-export class CurrentUserInterceptor implements NestInterceptor {
- constructor(
- private authService: AuthService,
- private usersService: UsersService,
- ) {}
-
- async intercept(context: ExecutionContext, handler: CallHandler) {
- const request = context.switchToHttp().getRequest();
- const cognitoUserAttributes = await this.authService.getUser(
- request.user.idUser,
- );
- const userEmail = cognitoUserAttributes.find(
- (attribute) => attribute.Name === 'email',
- ).Value;
- const users = await this.usersService.find(userEmail);
-
- if (users.length > 0) {
- const user = users[0];
-
- request.user = user;
- }
-
- return handler.handle();
- }
-}
diff --git a/apps/backend/src/label/dtos/create-label.dto.ts b/apps/backend/src/label/dtos/create-label.dto.ts
new file mode 100644
index 00000000..f2a0ea8f
--- /dev/null
+++ b/apps/backend/src/label/dtos/create-label.dto.ts
@@ -0,0 +1,4 @@
+// should include a name (string) and hex color (string)
+export class CreateLabelDTO {
+
+}
\ No newline at end of file
diff --git a/apps/backend/src/label/dtos/update-single-label.dto.ts b/apps/backend/src/label/dtos/update-single-label.dto.ts
new file mode 100644
index 00000000..4f18c769
--- /dev/null
+++ b/apps/backend/src/label/dtos/update-single-label.dto.ts
@@ -0,0 +1,3 @@
+// should include an optional name (string) and optional hex color (string)
+export class UpdateSingleLabelDTO {
+}
\ No newline at end of file
diff --git a/apps/backend/src/label/label.controller.spec.ts b/apps/backend/src/label/label.controller.spec.ts
new file mode 100644
index 00000000..e69de29b
diff --git a/apps/backend/src/label/label.controller.ts b/apps/backend/src/label/label.controller.ts
new file mode 100644
index 00000000..b160a917
--- /dev/null
+++ b/apps/backend/src/label/label.controller.ts
@@ -0,0 +1,71 @@
+import {
+ Controller,
+ Get,
+ Post,
+ Body,
+ Patch,
+ Param,
+ Delete,
+} from '@nestjs/common';
+import { ApiTags } from '@nestjs/swagger';
+import { LabelsService } from './label.service';
+import { Label } from './types/label.entity';
+import { CreateLabelDTO } from './dtos/create-label.dto';
+import { UpdateSingleLabelDTO } from './dtos/update-single-label.dto';
+
+@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
+ */
+
+ @Post('/label')
+ async createLabel(@Body() labelDto: CreateLabelDTO): Promise