This page describes a major part of the STAT System XCend Schema, namely the exercise management, including groups, sheets and student results. It is a part of The Whole Stat System and contains Registered Students as well as Exercise Groups.
element exercise * id { attribute lecture { string } attribute term { string } attribute open { boolean } element assistant * account {[ exists /account[./account]/assistant[..exercise/id] ]}
element group * id { [ count(./id, ..exercise/student/group) <= ./maxSize ] attribute day { "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday" | "Sunday" } attribute time { string } attribute location { string } attribute curSize { integer [ . = count(../id, ..exercise/student/group) ]} attribute maxSize { integer [ . >= 0 ]} element tutor * account {[ exists /account[./account]/tutor[..exercise/id]/group[..group/id] ]} }
element sheet * id { attribute maxPoints { double [ . >= 0 ]} }
element student * id { [ count (./id, /account/student/id) = 1 ] attribute group ? { ident [ exists ..exercise/group[.] ]} attribute team ? { ident [ exists ../group ]} element result * sheet { [ exists ..exercise/sheet[./sheet] ] attribute points { double [ . >= 0 && . <= ..exercise/sheet[../sheet]/maxPoints ]} } }
}
changeAttributes(ident uid, ident id, string lecture, string term) { assume exists /account[uid]/admin || exists /account[uid]/assistant[id]; assume exists /exercise[id]; # implicitly true in OO implementations update /exercise[id]/lecture lecture; update /exercise[id]/term term; }
The procedures from User Accounts and Roles for the assistant role can be directly reused.
grantAssistantRights(ident uid, ident username, ident exerciseId) { assume exists /account[uid]/admin; assume exists /account[username]; # implicitly true in OO implementations assume exists /exercise[exerciseId]; assume not exists /account[username]/assistant[exerciseId]); assume not exists /exercise[exerciseId]/assistant[username]; # implied by integrity and the assumption before insert /account[username] <assistant exercise=[exerciseId] />; insert /exercise[exerciseId] <assistant account=[username] />; }
revokeAssistantRights(ident uid, ident username, ident exerciseId) { assume exists /account[uid]/admin; assume exists /account[username]/assistant[exerciseId]; # implies the account exists, which is implicitly true anyway assume exists /exercise[exerciseId]/assistant[username]; # implied by integrity and the assumption before remove /account[username]/assistant[exerciseId]; remove /exercise[exerciseId]/assistant[username]; }
The tutor role from section User Accounts and Roles and the students depend on groups, which restricts deletion. The Exercise Groups are a large enough parts of the schema to have their own section and associated procedures.
createGroup(ident uid, ident id, ident groupId, string day, string time, string location, integer maxSize) { assume exists /account[uid]/assistant[id]; assume exists /exercise[id]; assume not exists /exercise[id]/group[groupId]; assume maxSize >= 0; assume day = "Monday" || day = "Tuesday" || ...; insert /exercise[id] <group id=[groupId] day=[day] time=[time] location=[location] curSize=[0] maxSize=[maxSize] />; }
deleteGroup(ident uid, ident id, ident groupId) { assume exists /account[uid]/assistant[id]; assume exists /exercise[id]/group[groupId]; assume size(/exercise[id]/group[groupId]/tutor) = 0; assume count(groupId, /exercise[id]/student/group)) = 0; remove /exercise[id]/group[groupId]; }
The student results depend on sheets.
createSheet(ident uid, ident id, ident sheetId, double maxPoints) { assume exists /account[uid]/assistant[id]; assume exists /exercise[id]; assume not exists /exercise[id]/sheet[sheetId]; assume maxPoints >= 0; insert /exercise[id] <sheet id=[sheetId] maxPoints=[maxPoints] />; }
deleteSheet(ident uid, ident id, ident sheetId) { assume exists /account[uid]/assistant[id]; assume exists /exercise[id]/sheet[sheetId]; # implies existence of the exercise assume size(/exercise[id]/student/result[sheetId]) = 0; remove /exercise[id]/sheet[sheetId]; }
Students themselves depend on an account, but nothing depends on them; Their results stand for themselves. As with Exercise Groups, Registered Students are large enough to warrant their own section and associated procedures.
registerStudent(ident uid, ident id, ident studentId) { assume count (studentId, /account/student/id) = 1; assume exists /exercise[id] && /exercise[id]/open && exists /account[uid]/student && /account[uid]/student/id = studentId || exists /account[uid]/assistant[id]; assume exists /exercise[id]; assume not exists /exercise[id]/student[studentId]; insert /exercise[id] <student id=[studentId] />; }
unregisterStudent(ident uid, ident id, ident studentId) { assume exists /exercise[id] && /exercise[id]/open && exists /account[uid]/student && /account[uid]/student/id = studentId || exists /account[uid]/assistant[id]; assume exists /exercise[id]/student[studentId]; # implies the exercise exists assume size(/exercise[id]/student[studentId]/result) = 0; # don't allow unregistering if results are there assume not exists /exercise[id]/student[studentId]/group; # don't allow if signed in a group remove /exercise[id]/student[studentId]; }
openSignUp(ident uid, ident id) { assume exists /account[uid]/assistant[id]; assume exists /exercise[id]; assume not /exercise[id]/open; update /exercise[id]/open true; }
closeSignUp(ident uid, ident id) { assume exists /account[uid]/assistant[id]; assume exists /exercise[id]; assume /exercise[id]/open; update /exercise[id]/open false; }