Skip to content

Commit 326193c

Browse files
committed
course -- fix #4495: remove student from course projects in all cases when you delete them
1 parent ac57381 commit 326193c

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

src/packages/frontend/course/student-projects/actions.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { CourseActions } from "../actions";
2020
import { CourseStore } from "../store";
2121
import { UpgradeGoal } from "../types";
2222
import { Result, run_in_all_projects } from "./run-in-all-projects";
23+
import type { StudentRecord } from "../store";
2324

2425
// for tasks that are "easy" to run in parallel, e.g. starting projects
2526
export const MAX_PARALLEL_TASKS = 30;
@@ -894,4 +895,31 @@ export class StudentProjectsActions {
894895
await webapp_client.project_client.set_quotas(x);
895896
}
896897
};
898+
899+
removeFromAllStudentProjects = async (student: StudentRecord) => {
900+
/*
901+
- Remove student from their project
902+
- Remove student from shared project
903+
- TODO: Cancel any outstanding invite, in case they haven't even created their account yet.
904+
This isn't even implemented yet as an api endpoint... but will cause confusion.
905+
*/
906+
const shared_id = this.get_store()?.get_shared_project_id();
907+
const account_id = student.get("account_id");
908+
const project_id = student.get("project_id");
909+
if (account_id) {
910+
if (project_id) {
911+
// remove them from their project
912+
await redux
913+
.getActions("projects")
914+
.remove_collaborator(project_id, account_id);
915+
}
916+
917+
if (shared_id) {
918+
// remove them from shared project
919+
await redux
920+
.getActions("projects")
921+
.remove_collaborator(shared_id, account_id);
922+
}
923+
}
924+
};
897925
}

src/packages/frontend/course/students/actions.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { defaults, required, uuid } from "@cocalc/util/misc";
1515
import { reuseInFlight } from "@cocalc/util/reuse-in-flight";
1616
import { CourseActions } from "../actions";
1717
import { CourseStore, StudentRecord } from "../store";
18-
import { SyncDBRecordStudent } from "../types";
18+
import type { SyncDBRecordStudent } from "../types";
1919
import { Map as iMap } from "immutable";
2020

2121
const STUDENT_STATUS_UPDATE_MS = 60 * 1000;
@@ -99,11 +99,16 @@ export class StudentsActions {
9999
): Promise<void> {
100100
const store = this.get_store();
101101
const student = store.get_student(student_id);
102-
if (student == null) return;
102+
if (student == null) {
103+
return;
104+
}
103105
this.doDeleteStudent(student, noTrash);
104-
// since they may get removed from shared project, etc.
105-
await delay(1); // so store is updated, since it is used by configure
106-
await this.course_actions.student_projects.configure_all_projects();
106+
// We always remove any deleted student from all student projects and the
107+
// shared project when they are deleted, since this best aligns with
108+
// user expectations. We do this, even if "allow collaborators" is enabled.
109+
await this.course_actions.student_projects.removeFromAllStudentProjects(
110+
student,
111+
);
107112
}
108113

109114
undelete_student = async (student_id: string): Promise<void> => {

0 commit comments

Comments
 (0)