Skip to content
Open
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
57 changes: 55 additions & 2 deletions src/backend/src/controllers/tasks.controllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { validateWBS, WbsNumber } from 'shared';
export default class TasksController {
static async createTask(req: Request, res: Response, next: NextFunction) {
try {
const { title, deadline, startDate, priority, status, assignees, notes } = req.body;
const { title, deadline, startDate, priority, status, assignees, notes, labelIds } = req.body;
const wbsNum: WbsNumber = validateWBS(req.params.wbsNum as string);

const task = await TasksService.createTask(
Expand All @@ -17,6 +17,7 @@ export default class TasksController {
status,
assignees,
req.organization,
labelIds,
startDate ? new Date(startDate) : undefined,
deadline ? new Date(deadline) : undefined
);
Expand All @@ -29,7 +30,7 @@ export default class TasksController {

static async editTask(req: Request, res: Response, next: NextFunction) {
try {
const { title, notes, priority, deadline, startDate, wbsNum } = req.body;
const { title, notes, priority, deadline, startDate, wbsNum, labelIds } = req.body;
const { taskId } = req.params as Record<string, string>;

const updateTask = await TasksService.editTask(
Expand All @@ -39,6 +40,7 @@ export default class TasksController {
title,
notes,
priority,
labelIds,
startDate ? new Date(startDate) : undefined,
deadline ? new Date(deadline) : undefined,
wbsNum
Expand Down Expand Up @@ -133,4 +135,55 @@ export default class TasksController {
next(error);
}
}

static async getTasksByWbsNumAndLabels(req: Request, res: Response, next: NextFunction) {
try {
const wbsNum: WbsNumber = validateWBS(req.params.wbsNum as string);
const labelIds = req.query.labelIds ? String(req.query.labelIds).split(',') : [];
const tasks = await TasksService.getTasksByWbsNumAndLabels(wbsNum, labelIds, req.organization);
res.status(200).json(tasks);
} catch (error: unknown) {
next(error);
}
}

static async getAllTaskLabels(req: Request, res: Response, next: NextFunction) {
try {
const labels = await TasksService.getAllTaskLabels(req.organization);
res.status(200).json(labels);
} catch (error: unknown) {
next(error);
}
}

static async createTaskLabel(req: Request, res: Response, next: NextFunction) {
try {
const { name, colorHexCode } = req.body;
const label = await TasksService.createTaskLabel(req.currentUser, name, colorHexCode, req.organization);
res.status(200).json(label);
} catch (error: unknown) {
next(error);
}
}

static async editTaskLabel(req: Request, res: Response, next: NextFunction) {
try {
const { taskLabelId } = req.params as Record<string, string>;
const { name, colorHexCode } = req.body;
const label = await TasksService.editTaskLabel(req.currentUser, taskLabelId, name, colorHexCode, req.organization);
res.status(200).json(label);
} catch (error: unknown) {
next(error);
}
}

static async deleteTaskLabel(req: Request, res: Response, next: NextFunction) {
try {
const { taskLabelId } = req.params as Record<string, string>;
const deletedId = await TasksService.deleteTaskLabel(req.currentUser, taskLabelId, req.organization);
res.status(200).json(deletedId);
} catch (error: unknown) {
next(error);
}
}
}
6 changes: 4 additions & 2 deletions src/backend/src/prisma-query-args/tasks.query-args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export const getTaskQueryArgs = (organizationId: string) =>
wbsElement: true,
createdBy: getUserQueryArgs(organizationId),
deletedBy: getUserQueryArgs(organizationId),
assignees: getUserQueryArgs(organizationId)
assignees: getUserQueryArgs(organizationId),
labels: true
}
});

Expand All @@ -33,7 +34,8 @@ export const getCalendarTaskQueryArgs = (organizationId: string) =>
},
createdBy: getUserQueryArgs(organizationId),
deletedBy: getUserQueryArgs(organizationId),
assignees: getUserQueryArgs(organizationId)
assignees: getUserQueryArgs(organizationId),
labels: true
}
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
-- CreateTable
CREATE TABLE "Task_Label" (
"taskLabelId" TEXT NOT NULL,
"name" TEXT NOT NULL,
"colorHexCode" TEXT NOT NULL,
"dateCreated" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"dateDeleted" TIMESTAMP(3),
"userCreatedId" TEXT NOT NULL,
"userDeletedId" TEXT,
"organizationId" TEXT NOT NULL,

CONSTRAINT "Task_Label_pkey" PRIMARY KEY ("taskLabelId")
);

-- CreateTable
CREATE TABLE "_TaskToTask_Label" (
"A" TEXT NOT NULL,
"B" TEXT NOT NULL,

CONSTRAINT "_TaskToTask_Label_AB_pkey" PRIMARY KEY ("A","B")
);

-- CreateIndex
CREATE INDEX "Task_Label_organizationId_idx" ON "Task_Label"("organizationId");

-- CreateIndex
CREATE INDEX "_TaskToTask_Label_B_index" ON "_TaskToTask_Label"("B");

-- AddForeignKey
ALTER TABLE "Task_Label" ADD CONSTRAINT "Task_Label_userCreatedId_fkey" FOREIGN KEY ("userCreatedId") REFERENCES "User"("userId") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Task_Label" ADD CONSTRAINT "Task_Label_userDeletedId_fkey" FOREIGN KEY ("userDeletedId") REFERENCES "User"("userId") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Task_Label" ADD CONSTRAINT "Task_Label_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "Organization"("organizationId") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_TaskToTask_Label" ADD CONSTRAINT "_TaskToTask_Label_A_fkey" FOREIGN KEY ("A") REFERENCES "Task"("taskId") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "_TaskToTask_Label" ADD CONSTRAINT "_TaskToTask_Label_B_fkey" FOREIGN KEY ("B") REFERENCES "Task_Label"("taskLabelId") ON DELETE CASCADE ON UPDATE CASCADE;
21 changes: 21 additions & 0 deletions src/backend/src/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,8 @@ model User {
prospectiveSponsorsContacted Prospective_Sponsor[] @relation(name: "prospectiveSponsorContactor")
createdMeetingAttendances Meeting_Attendance[] @relation(name: "meetingAttendanceCreated")
attendedMeetingAttendances Meeting_Attendance[] @relation(name: "meetingAttendees")
createdTaskLabels Task_Label[] @relation(name: "taskLabelCreator")
deletedTaskLabels Task_Label[] @relation(name: "taskLabelDeleter")
}

model Role {
Expand Down Expand Up @@ -705,10 +707,28 @@ model Task {
dateCreated DateTime @default(now())
wbsElement WBS_Element @relation(fields: [wbsElementId], references: [wbsElementId])
wbsElementId String
labels Task_Label[]

@@index([wbsElementId])
}

model Task_Label {
taskLabelId String @id @default(uuid())
name String
colorHexCode String
dateCreated DateTime @default(now())
dateDeleted DateTime?
userCreated User @relation(fields: [userCreatedId], references: [userId], name: "taskLabelCreator")
userCreatedId String
userDeleted User? @relation(fields: [userDeletedId], references: [userId], name: "taskLabelDeleter")
userDeletedId String?
tasks Task[]
organization Organization @relation(fields: [organizationId], references: [organizationId])
organizationId String

@@index([organizationId])
}

model Reimbursement_Status {
reimbursementStatusId String @id @default(uuid())
type Reimbursement_Status_Type
Expand Down Expand Up @@ -1450,6 +1470,7 @@ model Organization {
calendars Calendar[]
eventTypes Event_Type[]
meetingAttendances Meeting_Attendance[]
taskLabels Task_Label[]
}

model FrequentlyAskedQuestion {
Expand Down
32 changes: 32 additions & 0 deletions src/backend/src/prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2754,6 +2754,16 @@ const performSeed: () => Promise<void> = async () => {
ner
);

/**
* Task Labels
*/
const taskLabelResearch = await TasksService.createTaskLabel(thomasEmrax, 'Research', '#3B82F6', ner);
const taskLabelDesign = await TasksService.createTaskLabel(thomasEmrax, 'Design', '#A855F7', ner);
const taskLabelTesting = await TasksService.createTaskLabel(thomasEmrax, 'Testing', '#EF4444', ner);
const taskLabelAdmin = await TasksService.createTaskLabel(thomasEmrax, 'Admin', '#F97316', ner);
const taskLabelBuild = await TasksService.createTaskLabel(thomasEmrax, 'Build', '#22C55E', ner);
const taskLabelBlocked = await TasksService.createTaskLabel(thomasEmrax, 'Blocked', '#1E3A8A', ner);

/**
* Tasks
*/
Expand All @@ -2766,6 +2776,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_PROGRESS,
[joeShmoe.userId],
ner,
[taskLabelResearch.taskLabelId],
undefined,
daysFromNow(10)
);
Expand All @@ -2779,6 +2790,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_BACKLOG,
[joeShmoe.userId],
ner,
[taskLabelDesign.taskLabelId],
daysAgo(5),
daysFromNow(15)
);
Expand All @@ -2792,6 +2804,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_PROGRESS,
[joeShmoe.userId, joeBlow.userId],
ner,
[taskLabelResearch.taskLabelId, taskLabelBlocked.taskLabelId],
undefined,
daysFromNow(8)
);
Expand All @@ -2806,6 +2819,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_PROGRESS,
[joeBlow.userId],
ner,
[taskLabelTesting.taskLabelId],
undefined,
daysFromNow(14)
);
Expand All @@ -2819,6 +2833,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_PROGRESS,
[thomasEmrax.userId],
ner,
[taskLabelAdmin.taskLabelId],
daysAgo(14),
daysFromNow(7)
);
Expand All @@ -2832,6 +2847,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_PROGRESS,
[thomasEmrax.userId, joeBlow.userId, joeShmoe.userId],
ner,
[taskLabelDesign.taskLabelId],
undefined,
daysFromNow(9)
);
Expand All @@ -2845,6 +2861,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_PROGRESS,
[thomasEmrax.userId],
ner,
[taskLabelAdmin.taskLabelId],
undefined,
daysFromNow(6)
);
Expand All @@ -2858,6 +2875,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.DONE,
[joeShmoe.userId],
ner,
[taskLabelBuild.taskLabelId],
undefined,
daysAgo(30)
);
Expand All @@ -2879,6 +2897,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.DONE,
[joeShmoe.userId],
ner,
[taskLabelBuild.taskLabelId],
undefined,
daysAgo(90)
);
Expand All @@ -2892,6 +2911,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.DONE,
[thomasEmrax.userId, joeBlow.userId, joeShmoe.userId],
ner,
[taskLabelAdmin.taskLabelId],
daysAgo(70),
daysAgo(55)
);
Expand All @@ -2905,6 +2925,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_BACKLOG,
[],
ner,
[taskLabelAdmin.taskLabelId],
undefined,
daysFromNow(12)
);
Expand All @@ -2918,6 +2939,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_PROGRESS,
[joeShmoe.userId],
ner,
[taskLabelTesting.taskLabelId],
undefined,
daysFromNow(8)
);
Expand All @@ -2931,6 +2953,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_PROGRESS,
[thomasEmrax.userId, joeShmoe.userId],
ner,
[taskLabelAdmin.taskLabelId],
undefined,
daysFromNow(7)
);
Expand All @@ -2944,6 +2967,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.DONE,
[thomasEmrax.userId],
ner,
[taskLabelDesign.taskLabelId],
daysAgo(80),
daysAgo(65)
);
Expand All @@ -2957,6 +2981,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_BACKLOG,
[thomasEmrax, joeShmoe, joeBlow].map((user) => user.userId),
ner,
[taskLabelBuild.taskLabelId, taskLabelBlocked.taskLabelId],
undefined,
daysFromNow(16)
);
Expand All @@ -2970,6 +2995,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_PROGRESS,
[joeShmoe.userId],
ner,
[taskLabelBuild.taskLabelId],
undefined,
daysFromNow(13)
);
Expand All @@ -2983,6 +3009,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_BACKLOG,
[joeShmoe.userId],
ner,
[taskLabelTesting.taskLabelId],
undefined,
daysFromNow(18)
);
Expand All @@ -2996,6 +3023,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.DONE,
[joeBlow.userId],
ner,
[],
undefined,
daysAgo(45)
);
Expand All @@ -3009,6 +3037,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.DONE,
[joeBlow.userId],
ner,
[taskLabelDesign.taskLabelId],
undefined,
daysAgo(60)
);
Expand All @@ -3022,6 +3051,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_PROGRESS,
[regina.userId],
ner,
[taskLabelResearch.taskLabelId, taskLabelAdmin.taskLabelId],
daysAgo(21),
daysAgo(10)
);
Expand All @@ -3035,6 +3065,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.DONE,
[zatanna.userId],
ner,
[taskLabelAdmin.taskLabelId],
daysAgo(10),
daysAgo(9)
);
Expand All @@ -3048,6 +3079,7 @@ const performSeed: () => Promise<void> = async () => {
Task_Status.IN_PROGRESS,
[sandy.userId],
ner,
[taskLabelResearch.taskLabelId],
daysAgo(16),
daysAgo(1)
);
Expand Down
Loading
Loading