Table of Contents

User Accounts and Roles

This page describes a major part of the STAT System XCend Schema, namely the user accounts and the Roles handling. It is part of The Whole Stat System.

Schema

  element account * username {
    attribute lastName          { string }
    attribute firstName         { string }
    attribute email             { string }
    attribute password          { string }
    attribute code ?            { string }
    attribute reset ?           { string }
 
    element admin ?             { }
    element examiner * exam     {[ exists /exam[./exam]/examiner[../username] ]}
    element assistant * exercise {[ exists /exercise[./exercise]/assistant[../username] ]}
    element tutor * exercise {    
      element group * id        {[ exists /exercise[../exercise]/group[./id]/tutor[..account/username] ]}
    }                             
    element student ? {           
      attribute id              { ident [ count(., /account/student/id) = 1 ]}
    }                             
  } [ size(./account/admin) > 0 ]

Procedures

Change Attributes

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

Password Management

changePassword(ident uid, ident username, string password) {
  assume exists /account[uid]/admin || uid = username;
 
  assume exists /account[username]; # implicitly true in OO implementations
 
  update /account[username]/password password;
}
requestReset(ident username, string reset) {
  assume exists /account[username];
 
  assume not exists /account[username]/code; # account is already validated
 
  if not exists /account[username]/reset then
    insert /account[username]/reset;
  fi
  update /account[username]/reset reset;
}
resetPassword(ident username, string reset, string password) {
  assume exists /account[username]/reset; # reset code was requested before, implies account exists
  assume /account[username]/reset = reset; 
 
  remove /account[username]/reset;
  update /account[username]/password password;
}

Student Role

The students in the Exercise Management and Sheets section, as well as the participants in the Exam Management and Grades section, depend on the student role. This restricts the deletion of the role, i.e. the host language first has to delete these dependencies with corresponding procedures.

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

Admin Role

The admin role is pretty much just a flag, without any constraints at all. The precondition is therefore only concerned with uniqueness and trivial stuff.

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

Examiner Role

The examiner role has to fulfill integrity constraints and has a counterpart in the Exam Management and Grades section of the document.

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

Assistant Role

The assistant role relates to exercises like the examiner role relates to exams, so it also has to fulfill integrity constraints and has a counterpart in Exercise Management and Sheets.

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

Tutor Role

The tutor role also behaves similarly, but this time it references two identifiers in the Exercise Management and Sheets section, where it also has a counterpart.

This modeling of tutor rights is different from the current implementation. It might also be a nice design, if you can be tutor for an exercise, without (yet) having a group. This would grant some access rights already, I think.

grantTutorRights(ident uid, ident username, ident exerciseId, ident groupId) {
  assume exists /account[uid]/assistant[exerciseId];
 
  assume exists /account[username]; # implicitly true in OO implementations
  assume exists /exercise[exerciseId]/group[groupId];
 
  assume not exists /account[username]/tutor[exerciseId]/group[groupId]);
  assume not exists /exercise[exerciseId]/group[groupId]/tutor[username];
    # implied by integrity and the assumption before
 
  if not exists /account[username]/tutor[exerciseId] then # we could split the tutor rights here
    insert /account[username] <tutor exercise=[exerciseId] />;
  fi
  insert /account[username]/tutor[exerciseId] <group id=[groupId] />;
  insert /exercise[exerciseId]/group[groupId] <tutor account=[account] />;
}
revokeTutorRights(ident uid, ident username, ident exerciseId, ident groupId) {
  assume exists /account[uid]/assistant[exerciseId];
 
  assume exists /account[username]/tutor[exerciseId]/group[groupId];
  assume exists /exercise[exerciseId]/group[groupId]/tutor[username];
    # implied by integrity and the assumption before
 
  remove /account[username]/tutor[exerciseId]/group[groupId];
  if size(/account[username]/tutor[exerciseId]/group) = 0 then # should this be an additional procedure?
    remove /account[username]/tutor[exerciseId];
  fi
  remove /exercise[exerciseId]/group[groupId]/tutor[username];
}