Administrators mostly have access to the procedures at the top level, i.e. The Whole Stat System, and those in the section User Accounts and Roles.
An admin in general could be allowed to see anything, but its unnecessary and redundant. What he has to be able to see though, are the User Accounts and Roles section in total and the top level elements with their attributes of the Exercise Management and Sheets and Exam Management and Grades sections.
To be able to list this procedure somewhere, it is listed here. However, it is not actually a procedure which you would call for an existing system, obviously.
createEmptyStats() { remove /stats; # procedures only operate on valid documents, so we have to get rid of "whatever was there" before insert / <stats revision="0"> <account username="admin" lastName="admin" firstName="admin" email="admin@stats.system" password="some hash of 'admin'"> <admin /> </account> </stats>; }
createExercise(ident uid, ident id, string lecture, string term) { assume exists /account[uid]/admin; assume not exists /exercise[id]; insert / <exercise id=[id] lecture=[lecture] term=[term] open=[false] /> }
createExam(ident uid, ident id, ident eid, string title, string date, string time, string location) { assume exists /account[uid]/admin; assume not exists /exam[id]; assume exists /exercise[eid]; insert / <exam id=[id] title=[title] date=[date] time=[time] location=[location] free=[false] published=[false] exercise=[eid] /> }
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; }
changeAttributes(ident uid, ident id, string title, string date, string time, string location) { assume exists /account[uid]/admin || exists /account[uid]/examiner[id]; assume exists /exam[id]; # implicitly true in OO implementations update /exam[id]/title title; update /exam[id]/date date; update /exam[id]/time time; update /exam[id]/location location; }
deleteExercise(ident uid, ident id) { assume exists /account[uid]/admin; assume exists /exercise[id]; assume size(/exercise[id]/assistant) = 0; assume size(/exercise[id]/group/tutor) = 0; assume size(/exercise[id]/student) = 0; # don't allow to delete if students are there remove /exercise[id]; }
deleteExam(ident uid, ident id) { assume exists /account[uid]/admin; assume exists /exam[id]; assume size(/exam[id]/examiner) = 0; assume size(/exam[id]/participant) = 0; # don't allow to delete if participants are there remove /exam[id]; }
# This doesn't take account validation into consideration at all. It probably has to be allowed to replace an unvalidated account. createAccount(ident uid, ident username, string lastName, string firstName, string email, string password) { assume exists /account[uid]/admin; assume not exists /account[username]; insert / <account username=[username] lastName=[lastName] firstName=[firstName] email=[email] password=[password] /> }
# the current implementation also changes the username, i.e. it would need an additional parameter, # I can't support it and I would forbid it anyway. changeAttributes(ident uid, ident username, string firstName, string lastName) { assume exists /account[uid]/admin || uid = username; assume exists /account[username]; # implicitly true in OO implementations update /account[username]/firstName firstName; update /account[username]/lastName lastName; }
deleteAccount(ident uid, ident username) { assume exists /account[uid]/admin; assume uid != username; # or do we want to allow an admin to delete himself? assume exists /account[username]; assume size(/account[username]/examiner) = 0; assume size(/account[username]/assistant) = 0; assume size(/account[username]/tutor) = 0; # not yet a constraint of the implementation, but is seems practically relevant :-) if exists /account[username]/admin then assume size(/account/admin) > 1; fi if exists /account[username]/student then assume size(/exercise/student[/account[username]/student/id]) = 0; assume size(/exam/participant[/account[username]/student/id]) = 0; fi remove /account[username]; }
grantAdminRights(ident uid, ident username) { assume exists /account[uid]/admin; assume exists /account[username]; # implicitly true in OO implementations assume not exists /account[username]/admin; insert /account[username] <admin />; }
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] />; }
grantExaminerRights(ident uid, ident username, ident examId) { assume exists /account[uid]/admin; assume exists /account[username]; # implicitly true in OO implementations assume exists /exam[examId]; assume not exists /account[username]/examiner[examId]); assume not exists /exam[examId]/examiner[username]); # implied by integrity and the assumption before insert /account[username] <examiner exam=[examId] />; insert /exam[examId] <examiner account=[username] />; }
revokeAdminRights(ident uid, ident username) { assume exists /account[uid]/admin; assume exists /account[username]/admin; # implies the account exists, which is implicitly true anyway assume size(/account/admin) > 1; # kind of a practical constraint remove /account[username]/admin; }
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]; }
revokeExaminerRights(ident uid, ident username, ident examId) { assume exists /account[uid]/admin; assume exists /account[username]/examiner[examId]; # implies the account exists, which is implicitly true anyway assume exists /exam[examId]/examiner[username]; # implied by integrity and the assumption before remove /account[username]/examiner[examId]; remove /exam[examId]/examiner[username]; }
Normal accounts are created by admins, while students can create an account for themselves, which then has to have a student ID already. So there two procedures make only sense for admins, in the context of general right management. I put it into a separate section, however, to point out the oddity.
addStudentId(ident uid, ident username, ident id) { assume exists /account[uid]/admin; assume exists /account[username]; # implicitly true in OO implementations assume not exists /account[username]/student; assume count(id, /account/student/id) = 0; insert /account[username] <student id=[id] />; }
removeStudentId(ident uid, ident username) { assume exists /account[uid]/admin; assume exists /account[username]/student; # implies the account exists, which is implicitly true anyway assume size(/exercise/student[/account[username]/student/id]) = 0; assume size(/exam/participant[/account[username]/student/id]) = 0; remove /account[username]/student; }