Skip to content

Commit

Permalink
Add Result Viewing and Custom Team Assignment
Browse files Browse the repository at this point in the history
Bug found: I think the questions on creation that don't have score aren't saving, check this.
  • Loading branch information
Nephelite committed Oct 24, 2024
1 parent 850815e commit 17f34c5
Show file tree
Hide file tree
Showing 24 changed files with 1,700 additions and 432 deletions.
4 changes: 4 additions & 0 deletions backend/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import teamSetRoutes from './routes/teamSetRoutes';
import userRoutes from './routes/userRoutes';
import { connectToDatabase } from './utils/database';
import submissionRoutes from 'routes/submissionRoutes';
import assessmentAssignmentSetRoutes from 'routes/assessmentAssignmentSetRoutes';
import assessmentResultRoutes from 'routes/assessmentResultRoutes';

const env = process.env.NODE_ENV ?? 'development';
config({ path: `.env.${env}` });
Expand Down Expand Up @@ -48,6 +50,8 @@ app.use('/api/submissions', submissionRoutes)
app.use('/api/jira', jiraRoutes);
app.use('/api/metrics', metricRoutes);
app.use('/api/user', userRoutes);
app.use('/api/assessment-results', assessmentResultRoutes);
app.use('/api/assignment-sets', assessmentAssignmentSetRoutes);

app.listen(port, () => {
console.log(`Server is running at http://localhost:${port}`);
Expand Down
32 changes: 8 additions & 24 deletions backend/controllers/assessmentAssignmentSetController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import {
createAssignmentSet,
getAssignmentSetByAssessmentId,
updateAssignmentSet,
deleteAssignmentSet,
getAssignmentsByTAId,
} from '../services/assessmentAssignmentSetService';
import { BadRequestError, NotFoundError } from '../services/errors';
import { getAccountId } from 'utils/auth';
import { getUserIdByAccountId } from 'services/accountService';

/**
* Controller to create a new AssessmentAssignmentSet.
Expand Down Expand Up @@ -43,7 +44,7 @@ export const getAssignmentSetController = async (req: Request, res: Response) =>

try {
const assignmentSet = await getAssignmentSetByAssessmentId(assessmentId);
res.status(200).json(assignmentSet);
res.status(200).json(assignmentSet.assignedTeams);
} catch (error) {
if (error instanceof NotFoundError) {
res.status(404).json({ error: error.message });
Expand Down Expand Up @@ -79,34 +80,17 @@ export const updateAssignmentSetController = async (req: Request, res: Response)
}
};

/**
* Controller to delete an AssessmentAssignmentSet by assessment ID.
*/
export const deleteAssignmentSetController = async (req: Request, res: Response) => {
const { assessmentId } = req.params;

try {
await deleteAssignmentSet(assessmentId);
res.status(200).json({ message: 'AssessmentAssignmentSet deleted successfully' });
} catch (error) {
if (error instanceof NotFoundError) {
res.status(404).json({ error: error.message });
} else {
console.error('Error deleting AssessmentAssignmentSet:', error);
res.status(500).json({ error: 'Failed to delete AssessmentAssignmentSet' });
}
}
};

/**
* Controller to retrieve all teams assigned to a specific TA within an assessment.
*/
export const getAssignmentsByTAIdController = async (req: Request, res: Response) => {
const { assessmentId, taId } = req.params;
const { assessmentId } = req.params;
const accountId = await getAccountId(req);
const userId = await getUserIdByAccountId(accountId);

try {
const teamIds = await getAssignmentsByTAId(taId, assessmentId);
res.status(200).json({ teams: teamIds });
const assignments = await getAssignmentsByTAId(userId, assessmentId);
res.status(200).json(assignments);
} catch (error) {
if (error instanceof NotFoundError) {
res.status(404).json({ error: error.message });
Expand Down
89 changes: 89 additions & 0 deletions backend/controllers/assessmentResultController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// controllers/assessmentResultController.ts

import { Request, Response } from 'express';
import {
getOrCreateAssessmentResults,
recalculateResult,
checkMarkingCompletion,
} from '../services/assessmentResultService';
import { BadRequestError, NotFoundError } from '../services/errors';

/**
* Controller to retrieve or create AssessmentResults for an assessment.
* Route: GET /api/assessment-results/:assessmentId
*/
export const getOrCreateAssessmentResultsController = async (
req: Request,
res: Response,
) => {
const { assessmentId } = req.params;

try {
const assessmentResults = await getOrCreateAssessmentResults(assessmentId);
res.status(200).json({
success: true,
data: assessmentResults,
});
} catch (error) {
if (error instanceof BadRequestError) {
res.status(400).json({ error: error.message });
} else if (error instanceof NotFoundError) {
res.status(404).json({ error: error.message });
} else {
console.error('Error retrieving or creating AssessmentResults:', error);
res.status(500).json({ error: 'Failed to retrieve or create AssessmentResults' });
}
}
};

/**
* Controller to recalculate the average score of an AssessmentResult.
* Route: POST /api/assessment-results/:resultId/recalculate
*/
export const recalculateResultController = async (
req: Request,
res: Response,
) => {
const { resultId } = req.params;

try {
await recalculateResult(resultId);
res.status(200).json({
success: true,
message: 'Average score recalculated successfully.',
});
} catch (error) {
if (error instanceof NotFoundError) {
res.status(404).json({ error: error.message });
} else {
console.error('Error recalculating AssessmentResult:', error);
res.status(500).json({ error: 'Failed to recalculate AssessmentResult' });
}
}
};

/**
* Controller to check marking completion for an assessment.
* Route: GET /api/assessment-results/:assessmentId/check-marking-completion
*/
export const checkMarkingCompletionController = async (
req: Request,
res: Response,
) => {
const { assessmentId } = req.params;

try {
const unmarkedTeams = await checkMarkingCompletion(assessmentId);
res.status(200).json({
success: true,
data: unmarkedTeams,
});
} catch (error) {
if (error instanceof NotFoundError) {
res.status(404).json({ error: error.message });
} else {
console.error('Error checking marking completion:', error);
res.status(500).json({ error: 'Failed to check marking completion' });
}
}
};
118 changes: 118 additions & 0 deletions backend/controllers/internalAssessmentController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
releaseInternalAssessmentById,
recallInternalAssessmentById,
} from 'services/internalAssessmentService';
import { checkMarkingCompletion, getOrCreateAssessmentResults, recalculateResult } from 'services/assessmentResultService';

export const getInternalAssessment = async (req: Request, res: Response) => {
try {
Expand Down Expand Up @@ -236,3 +237,120 @@ export const recallInternalAssessment = async (req: Request, res: Response) => {
}
}
};


export const fetchAssessmentResults = async (
req: Request,
res: Response,
) => {
const { assessmentId } = req.params;

try {
const assessmentResults = await getOrCreateAssessmentResults(assessmentId);
res.status(200).json({
success: true,
data: assessmentResults,
});
} catch (error) {
if (error instanceof NotFoundError) {
res.status(404).json({ error: error.message });
} else if (error instanceof BadRequestError) {
res.status(400).json({ error: error.message });
} else if (error instanceof MissingAuthorizationError) {
res.status(401).json({ error: 'Missing authorization' });
} else {
console.error('Error recalling assessment:', error);
res.status(500).json({ error: 'Failed to recall assessment' });
}
}
};

/**
* Controller to retrieve or create AssessmentResults for an assessment.
* Route: GET /internal-assessments/:assessmentId/results
*/
export const getOrCreateAssessmentResultsController = async (
req: Request,
res: Response,
) => {
const { assessmentId } = req.params;

try {
const assessmentResults = await getOrCreateAssessmentResults(assessmentId);
res.status(200).json({
success: true,
data: assessmentResults,
});
} catch (error) {
if (error instanceof NotFoundError) {
res.status(404).json({ error: error.message });
} else if (error instanceof BadRequestError) {
res.status(400).json({ error: error.message });
} else if (error instanceof MissingAuthorizationError) {
res.status(401).json({ error: 'Missing authorization' });
} else {
console.error('Error recalling assessment:', error);
res.status(500).json({ error: 'Failed to recall assessment' });
}
}
};

/**
* Controller to recalculate the average score of an AssessmentResult.
* Route: POST /results/:resultId/recalculate
*/
export const recalculateResultController = async (
req: Request,
res: Response,
) => {
const { resultId } = req.params;

try {
await recalculateResult(resultId);
res.status(200).json({
success: true,
message: 'Average score recalculated successfully.',
});
} catch (error) {
if (error instanceof NotFoundError) {
res.status(404).json({ error: error.message });
} else if (error instanceof BadRequestError) {
res.status(400).json({ error: error.message });
} else if (error instanceof MissingAuthorizationError) {
res.status(401).json({ error: 'Missing authorization' });
} else {
console.error('Error recalling assessment:', error);
res.status(500).json({ error: 'Failed to recall assessment' });
}
}
};

/**
* Controller to check marking completion for an assessment.
* Route: GET /internal-assessments/:assessmentId/check-marking-completion
*/
export const checkMarkingCompletionController = async (
req: Request,
res: Response,
) => {
const { assessmentId } = req.params;

try {
const unmarkedTeams = await checkMarkingCompletion(assessmentId);
res.status(200).json({
success: true,
data: unmarkedTeams,
});
} catch (error) {
if (error instanceof NotFoundError) {
res.status(404).json({ error: error.message });
} else if (error instanceof BadRequestError) {
res.status(400).json({ error: error.message });
} else if (error instanceof MissingAuthorizationError) {
res.status(401).json({ error: 'Missing authorization' });
} else {
console.error('Error recalling assessment:', error);
res.status(500).json({ error: 'Failed to recall assessment' });
}
}
};
25 changes: 23 additions & 2 deletions backend/models/AssessmentAssignmentSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import mongoose, { Schema, Types, Document } from 'mongoose';
import { Team } from './Team';
import { User } from './User';
import { InternalAssessment } from './InternalAssessment'; // Adjust the import path as necessary
import { InternalAssessment } from './InternalAssessment';

/**
* Interface for Assigned Teams within the AssessmentAssignmentSet.
Expand All @@ -13,13 +13,22 @@ export interface AssignedTeam {
tas: Types.ObjectId[] | User[];
}

/**
* Interface for Assigned Users within the AssessmentAssignmentSet.
*/
export interface AssignedUser {
user: Types.ObjectId | User;
tas: Types.ObjectId[] | User[];
}

/**
* Interface for the AssessmentAssignmentSet document.
*/
export interface AssessmentAssignmentSet extends Document {
assessment: Types.ObjectId | InternalAssessment;
originalTeams: Types.ObjectId[] | Team[];
assignedTeams: AssignedTeam[];
assignedTeams?: AssignedTeam[];
assignedUsers?: AssignedUser[]; // Only used for if the assignment is for assessments with individual granularity
}

/**
Expand All @@ -33,6 +42,17 @@ const assignedTeamSchema = new Schema<AssignedTeam>(
{ _id: false }
);

/**
* Schema for AssignedUser subdocuments.
*/
const assignedUserSchema = new Schema<AssignedUser>(
{
user: { type: Schema.Types.ObjectId, ref: 'User', required: true },
tas: [{ type: Schema.Types.ObjectId, ref: 'User' }],
},
{ _id: false }
);

/**
* Schema for AssessmentAssignmentSet.
*/
Expand All @@ -41,6 +61,7 @@ const assessmentAssignmentSetSchema = new Schema<AssessmentAssignmentSet>(
assessment: { type: Schema.Types.ObjectId, ref: 'InternalAssessment', required: true, unique: true },
originalTeams: [{ type: Schema.Types.ObjectId, ref: 'Team', required: true }],
assignedTeams: [assignedTeamSchema],
assignedUsers: [assignedUserSchema],
},
{ timestamps: true }
);
Expand Down
Loading

0 comments on commit 17f34c5

Please sign in to comment.