fix: superadmin course access + navigate to correct course from courses page

Backend: list_students, add_student, import_students now bypass
tutor_courses check for superadmins, matching the existing pattern
in list_assigned_tutors. A superadmin creating a new course was
getting 401 when accessing it because no tutor_courses row exists
for them.

Frontend: courses page passes ?courseId= to students/sessions links;
both pages now pre-select the matching course on mount instead of
always defaulting to courses[0].
This commit is contained in:
2026-05-06 15:46:54 +02:00
parent 553eb00f87
commit c8a4bc1820
4 changed files with 19 additions and 12 deletions

View File

@@ -126,13 +126,14 @@ async fn list_assigned_tutors(
Ok(Json(tutors))
}
// Fix 3: verify tutor has access to this course
async fn list_students(
claims: TutorClaims,
State(pool): State<SqlitePool>,
Path(course_id): Path<i64>,
) -> Result<Json<Vec<Student>>, AppError> {
super::verify_tutor_course_access(&pool, claims.sub, course_id).await?;
if !claims.is_superadmin {
super::verify_tutor_course_access(&pool, claims.sub, course_id).await?;
}
let students = sqlx::query_as::<_, Student>(
"SELECT id, course_id, name FROM students WHERE course_id = ? ORDER BY id",
)
@@ -142,14 +143,15 @@ async fn list_students(
Ok(Json(students))
}
// Fix 3: verify tutor has access to this course
async fn add_student(
claims: TutorClaims,
State(pool): State<SqlitePool>,
Path(course_id): Path<i64>,
Json(req): Json<CreateStudent>,
) -> Result<(StatusCode, Json<Value>), AppError> {
super::verify_tutor_course_access(&pool, claims.sub, course_id).await?;
if !claims.is_superadmin {
super::verify_tutor_course_access(&pool, claims.sub, course_id).await?;
}
let id = sqlx::query("INSERT INTO students (course_id, name) VALUES (?, ?)")
.bind(course_id)
.bind(&req.name)
@@ -162,14 +164,15 @@ async fn add_student(
))
}
// Fix 3 + Fix 4: verify access, validate CSV header, wrap in transaction, size check
async fn import_students(
claims: TutorClaims,
State(pool): State<SqlitePool>,
Path(course_id): Path<i64>,
mut multipart: Multipart,
) -> Result<(StatusCode, Json<Value>), AppError> {
super::verify_tutor_course_access(&pool, claims.sub, course_id).await?;
if !claims.is_superadmin {
super::verify_tutor_course_access(&pool, claims.sub, course_id).await?;
}
let mut count = 0i64;