Skip to content

Commit

Permalink
Merge pull request #769 from Lunatic-Labs/SKIL-487
Browse files Browse the repository at this point in the history
SKIL-487
  • Loading branch information
aparriaran authored Nov 19, 2024
2 parents f72d48c + a955cc2 commit c5b2f6e
Show file tree
Hide file tree
Showing 7 changed files with 374 additions and 186 deletions.
20 changes: 20 additions & 0 deletions BackEndFlask/controller/Routes/Completed_assessment_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,26 @@ def get_all_completed_assessments():
except Exception as e:
return create_bad_response(f"An error occurred retrieving all completed assessments: {e}", "completed_assessments", 400)

@bp.route('/completed_assessment', methods = ['GET'])
@jwt_required()
@bad_token_check()
@AuthCheck()
def get_completed_assessment_by_team_or_user_id():
try:
completed_assessment_id = request.args.get("completed_assessment_id")
unit = request.args.get("unit")
if not completed_assessment_id:
return create_bad_response("No completed_assessment_id provided", "completed_assessments", 400)

if unit == "team":
one_completed_assessment = get_completed_assessment_with_team_name(completed_assessment_id)
elif unit == "user":
one_completed_assessment = get_completed_assessment_with_user_name(completed_assessment_id)
else:
create_bad_response("Invalid unit provided", "completed_assessments", 400)
return create_good_response(completed_assessment_schema.dump(one_completed_assessment), 200, "completed_assessments")
except Exception as e:
return create_bad_response(f"An error occurred fetching a completed assessment: {e}", "completed_assessments", 400)

@bp.route('/completed_assessment', methods = ['POST'])
@jwt_required()
Expand Down
45 changes: 38 additions & 7 deletions BackEndFlask/controller/Routes/Team_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
get_team_by_course_id,
create_team,
get_teams_by_observer_id,
replace_team
replace_team,
delete_team
)
from models.assessment_task import get_assessment_tasks_by_team_id
from models.completed_assessment import completed_assessment_team_or_user_exists
from models.team_user import *
from controller.security.CustomDecorators import AuthCheck, bad_token_check
from models.queries import (
Expand Down Expand Up @@ -94,14 +97,14 @@ def get_nonfull_adhoc_teams():
try:
if request.args and request.args.get("assessment_task_id"):
assessment_task_id = int(request.args.get("assessment_task_id"))
valid_teams = [{"team_name": f"Team {team}", "team_id": team} for team in get_all_nonfull_adhoc_teams(assessment_task_id)]
return create_good_response(valid_teams, 200, "teams")

valid_teams = [{"team_name": f"Team {team}", "team_id": team} for team in get_all_nonfull_adhoc_teams(assessment_task_id)]

return create_good_response(valid_teams, 200, "teams")

except Exception as e:
return create_bad_response(f"An error occurred getting nonfull adhoc teams {e}", "teams", 400)


@bp.route('/team', methods = ['POST'])
@jwt_required()
Expand Down Expand Up @@ -167,6 +170,34 @@ def update_team_user_by_edit():
except Exception as e:
return create_bad_response(f"An error occurred updating a team: {e}", "teams", 400)

@bp.route('/team', methods = ['DELETE'])
@jwt_required()
@bad_token_check()
@AuthCheck()
def delete_selected_teams():
try:
if request.args and request.args.get("team_id"):
team_id = int(request.args.get("team_id"))
team = get_team(team_id)
if not team:
return create_bad_response("Team does not exist", "teams", 400)

associated_tasks = completed_assessment_team_or_user_exists(team_id, user_id=None)
if associated_tasks is None:
associated_tasks = []
if len(associated_tasks) > 0:
refetched_tasks = completed_assessment_team_or_user_exists(team_id, user_id=None)
if not refetched_tasks:
delete_team(team_id)
return create_good_response([], 200, "teams")
else:
return create_bad_response("Cannot delete team with associated tasks", "teams", 400)
else:
delete_team(team_id)
return create_good_response([], 200, "teams")

except Exception as e:
return create_bad_response(f"An error occurred deleting a team: {e}", "teams", 400)

class TeamSchema(ma.Schema):
class Meta:
Expand Down
3 changes: 1 addition & 2 deletions BackEndFlask/models/assessment_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def get_assessment_tasks_by_role_id(role_id):

@error_log
def get_assessment_tasks_by_team_id(team_id):
return db.session.query(AssessmentTask).join(Team, AssessmentTask.course_id == Team.course_id).filter(
db.session.query(AssessmentTask).join(Team, AssessmentTask.course_id == Team.course_id).filter(
Team.team_id == team_id
and
(
Expand All @@ -72,7 +72,6 @@ def get_assessment_tasks_by_team_id(team_id):
(AssessmentTask.due_date >= Team.date_created and AssessmentTask.due_date <= Team.active_until)
)
).all()

@error_log
def get_assessment_task(assessment_task_id):
one_assessment_task = AssessmentTask.query.filter_by(assessment_task_id=assessment_task_id).first()
Expand Down
8 changes: 8 additions & 0 deletions BackEndFlask/models/completed_assessment.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ def completed_assessment_exists(team_id, assessment_task_id, user_id):
else:
return CompletedAssessment.query.filter_by(user_id=user_id, assessment_task_id=assessment_task_id).first()

@error_log
def completed_assessment_team_or_user_exists(team_id, user_id):
if team_id is not None:
return CompletedAssessment.query.filter_by(team_id=team_id).all()
elif user_id is not None:
return CompletedAssessment.query.filter_by(user_id=user_id).all()
else:
return []

@error_log
def create_completed_assessment(completed_assessment_data):
Expand Down
258 changes: 146 additions & 112 deletions FrontEndReact/src/View/Admin/View/ViewTeams/AdminViewTeams.js
Original file line number Diff line number Diff line change
@@ -1,118 +1,152 @@
import 'bootstrap/dist/css/bootstrap.css';
import React, { Component } from 'react';
import ErrorMessage from '../../../Error/ErrorMessage.js';
import ViewTeams from './ViewTeams.js';
import { genericResourceGET, parseUserNames } from '../../../../utility.js';
import { Box, Button, Typography } from '@mui/material';
import Loading from '../../../Loading/Loading.js';
import SuccessMessage from '../../../Success/SuccessMessage.js';


import "bootstrap/dist/css/bootstrap.css";
import React, { Component } from "react";
import ErrorMessage from "../../../Error/ErrorMessage.js";
import ViewTeams from "./ViewTeams.js";
import { genericResourceGET,
parseUserNames } from "../../../../utility.js";
import { Box, Button, Typography } from "@mui/material";
import Loading from "../../../Loading/Loading.js";
import SuccessMessage from "../../../Success/SuccessMessage.js";

class AdminViewTeams extends Component {
constructor(props) {
super(props);

this.state = {
errorMessage: null,
isLoaded: false,
teams: null,
users: null
}
}

componentDidMount() {
var navbar = this.props.navbar;
var state = navbar.state;
var chosenCourse = state.chosenCourse;

genericResourceGET(`/team?course_id=${chosenCourse["course_id"]}`, "teams", this);

var url = (
chosenCourse["use_tas"] ?
`/user?course_id=${chosenCourse["course_id"]}&role_id=4` :
`/user?uid=${chosenCourse["admin_id"]}`
);

genericResourceGET(url, "users", this);
constructor(props) {
super(props);

this.state = {
errorMessage: null,
isLoaded: false,
teams: null,
users: null,
prevTeamsLength: 0,
successMessage: null
};
}


fetchData = () => {
var navbar = this.props.navbar;
var state = navbar.state;
var chosenCourse = state.chosenCourse;

genericResourceGET(
`/team?course_id=${chosenCourse["course_id"]}`,
"teams",
this,
);

var url = chosenCourse["use_tas"]
? `/user?course_id=${chosenCourse["course_id"]}&role_id=4`
: `/user?uid=${chosenCourse["admin_id"]}`;

genericResourceGET(url, "users", this);
};

componentDidMount() {
this.fetchData();
}


componentDidUpdate(){
if (this.state.teams && this.state.teams.length !== this.state.prevTeamsLength) {
this.setState({ prevTeamsLength: this.state.teams.length });
this.fetchData();
}

render() {
const {
errorMessage,
isLoaded,
teams,
users
} = this.state;

var navbar = this.props.navbar;

navbar.adminViewTeams.teams = teams;
navbar.adminViewTeams.users = users ? parseUserNames(users) : [];

var setNewTab = navbar.setNewTab;
var setAddTeamTabWithUsers = navbar.setAddTeamTabWithUsers;

if (errorMessage) {
return(
<div className='container'>
<ErrorMessage
fetchedResource={"Teams"}
errorMessage={errorMessage}
/>
</div>
)

} else if (!isLoaded || !teams || !users) {
return(
<Loading />
)

} else {
return(
<Box>
{navbar.state.successMessage !== null &&
<div className='container'>
<SuccessMessage
successMessage={navbar.state.successMessage}
aria-label="adminViewTeamsSuccessMessage"
/>
</div>
}
<Box sx={{mb:"20px"}}className="subcontent-spacing" >
<Typography sx={{fontWeight:'700'}} variant="h5">Teams</Typography>
<Box sx={{display:"flex", gap:"20px"}}>
<Button className='primary-color'
variant='contained'
onClick={() => {
setNewTab("AdminTeamBulkUpload");
}}
aria-label="adminBulkUploadButton"
>
Team Bulk Upload
</Button>
<Button className='primary-color'
variant='contained'
onClick={() => {
setAddTeamTabWithUsers(users);
}}
aria-label="adminAddTeamButton"
>
Add Team
</Button>
</Box>
</Box>
<Box className="table-spacing">
<ViewTeams
navbar={this.props.navbar}
teams={teams}
users={users ? parseUserNames(users) : []}
/>
</Box>
</Box>
)
}
}
setErrorMessage = (message) => {
this.setState({ errorMessage: message });
// Clear error message after 3 seconds
setTimeout(() => {
this.setState({ errorMessage: null });
}, 3000);
}

setSuccessMessage = (message) => {
this.setState({ successMessage: message });
// Clear success message after 3 seconds
setTimeout(() => {
this.setState({ successMessage: null });
}, 3000);
}
render() {
const { errorMessage, isLoaded, teams, users, successMessage } = this.state;

var navbar = this.props.navbar;

navbar.adminViewTeams.teams = teams;
navbar.adminViewTeams.users = users ? parseUserNames(users) : [];

var setNewTab = navbar.setNewTab;
var setAddTeamTabWithUsers = navbar.setAddTeamTabWithUsers;

if (errorMessage) {
return (
<div className="container">
<ErrorMessage fetchedResource={"Teams"} errorMessage={errorMessage} />
</div>
);
} else if (!isLoaded || !teams || !users) {
return <Loading />;
} else {
return (
<Box>
{successMessage && (
<div className="container">
<SuccessMessage
successMessage={successMessage}
aria-label="adminViewTeamsSuccessMessage"
/>
</div>
)}
{errorMessage && (
<div className="container">
<ErrorMessage
fetchedResource={"Teams"}
errorMessage={errorMessage}
aria-label="adminViewTeamsErrorMessage"
/>
</div>
)}
<Box sx={{ mb: "20px" }} className="subcontent-spacing">
<Typography sx={{ fontWeight: "700" }} variant="h5">
Teams
</Typography>
<Box sx={{ display: "flex", gap: "20px" }}>
<Button
className="primary-color"
variant="contained"
onClick={() => {
setNewTab("AdminTeamBulkUpload");
}}
aria-label="adminBulkUploadButton"
>
Team Bulk Upload
</Button>
<Button
className="primary-color"
variant="contained"
onClick={() => {
setAddTeamTabWithUsers(users);
}}
aria-label="adminAddTeamButton"
>
Add Team
</Button>
</Box>
</Box>
<Box className="table-spacing">
<ViewTeams
navbar={this.props.navbar}
teams={teams}
users={users ? parseUserNames(users) : []}
onError={this.setErrorMessage}
onSuccess={this.setSuccessMessage}
refreshData={this.fetchData}
/>
</Box>
</Box>
);
}
}
}

export default AdminViewTeams;
export default AdminViewTeams;
Loading

0 comments on commit c5b2f6e

Please sign in to comment.