Table of Contents

Admin Role

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.

Access Rights

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.

Procedures

System Creation

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>;
}

Sub-System Creation

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];
}

Account Management

# 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];
}

Right Management

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];
}

Student Role

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;
}