Table of Contents

Procedures

This page lists all associated procedures to the XCend Schema of the STAT System.

Overview

Details

Add Participant

addParticipant(ident uid, ident id, ident studentId) {
  assume exists /account[uid]/student && /account[uid]/student/id = studentId && /exam[id]/free
      || exists /account[uid]/examiner[id];
 
  assume exists /exam[id]; # implicitly true in OO implementations
  assume count (studentId, /account/student/id) = 1;
 
  assume not exists /exam[id]/participant[studentId];
 
  insert /exam[id]/participant[studentId];
}

Add Result (Sheet)

addResult(ident uid, ident id, ident studentId, ident sheetId, double points) {
  assume exists /account[uid]/assistant[id] 
      || exists /account[uid]/tutor[id]/group[/exercise[id]/student[studentId]/group];
 
  assume exists /exercise[id]/student[studentId]; # implies the existence of the exercise
  assume exists /exercise[id]/sheet[sheetId]; # dito
 
  assume not exists /exercise[id]/student[studentId]/result[sheetId];
 
  assume points >= 0 && points <= /exercise[id]/sheet[sheetId]/maxPoints;
 
  insert /exercise[id]/student[studentId] <result sheet=[sheetId] points=[points] />;
}

Add Result (Task)

addResult(ident uid, ident id, ident studentId, ident taskId, double points) {
  assume exists /account[uid]/examiner[id];
 
  assume exists /exam[id]/participant[studentId]; # can also be implicitly true in an OO language
  assume exists /exam[id]/task[taskId];
 
  assume not exists /exam[id]/participant[studentId]/result[taskId];
 
  assume points >= 0 && points <= /exam[id]/task[taskId]/maxPoints;
 
  insert /exam[id]/participant[studentId] <result task=[taskId] points=[points] />;
}

Add Student ID

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

Assign Team

assignTeam(ident uid, ident id, ident studentId, ident teamId) {
  assume exists /account[uid]/tutor[id]/group[/exercise[id]/student[studentId]/group];
    # implies the existence of the student, the exercise, the group and enough rights by a tutor account
 
  assume not exists /exercise[id]/student[studentId]/team;
 
  insert /exercise[id]/student[studentId]/team teamId;
}

Authenticate

authenticate(ident username, string password) {
  assume exists /account[username];
 
  assume /account[username]/password = password;
}

Change Attributes (Account)

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

Change Attributes (Exam)

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

Change Attributes (Exercise)

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

Change Attributes (Group)

changeAttributes(ident uid, ident id, ident groupId, string day, string time, string location, integer maxSize) {
  assume exists /account[uid]/assistant[id];
 
  assume exists /exercise[id]/group[groupId]; # implicitly true in OO implementations
 
  assume maxSize >= 0;
  assume /exercise[id]/group[groupId]/curSize <= maxSize;
 
  update /exercise[id]/group[groupId]/day day;
  update /exercise[id]/group[groupId]/time time;
  update /exercise[id]/group[groupId]/location location;
  update /exercise[id]/group[groupId]/maxSize maxSize;
}

Change Attributes (Sheet)

changeAttributes(ident uid, ident id, ident sheetId, double maxPoints) {
  assume exists /account[uid]/assistant[id];
 
  assume exists /exercise[id]/sheet[sheetId]; # implies the existence of the exercise
 
  assume maxPoints >= 0;
  assume /exercise[id]/student[x]/result[sheetId]/points <= maxPoints;
 
  update /exercise[id]/sheet[sheetId]/maxPoints maxPoints;
}

Change Attributes (Task)

changeAttributes(ident uid, ident id, ident taskId, double maxPoints) {
  assume exists /account[uid]/examiner[id];
 
  assume exists /exam[id]/task[taskId]; # implies the existence of the exam
 
  assume maxPoints >= 0;
  assume /exam[id]/participant[x]/result[taskId]/points <= maxPoints;
 
  update /exam[id]/task[taskId]/maxPoints maxPoints;
}

Change Password

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

Change Result (Sheet)

changeResult(ident uid, ident id, ident studentId, ident sheetId, double points) {
  assume exists /account[uid]/assistant[id]
      || exists /account[uid]/tutor[id]/group[/exercise[id]/student[studentId]/group];
 
  assume exists /exercise[id]/student[studentId]; # implies the existence of the exercise
  assume exists /exercise[id]/sheet[sheetId]; # dito
 
  assume points >= 0 && points <= /exercise[id]/sheet[sheetId]/maxPoints;
 
  assume exists /exercise[id]/student[studentId]/result[sheetId];
 
  update /exercise[id]/student[studentId]/result[sheetId]/points points;
}

Change Result (Task)

changeResult(ident uid, ident id, ident studentId, ident taskId, double points) {
  assume exists /account[uid]/examiner[id];
 
  assume exists /exam[id]/participant[studentId];
  assume exists /exam[id]/task[taskId];
 
  assume points >= 0 && points <= /exam[id]/task[taskId]/maxPoints;
 
  assume exists /exam[id]/participant[studentId]/result[taskId];
 
  update /exam[id]/participant[studentId]/result[taskId]/points points;
}

Close Registration

closeRegistration(ident uid, ident id) {
  assume exists /account[uid]/examiner[id];
 
  assume exists /exam[id];
 
  assume /exam[id]/free;
 
  update /exam[id]/free false;
}

Close Sign-Up

closeSignUp(ident uid, ident id) {
  assume exists /account[uid]/assistant[id];
 
  assume exists /exercise[id];
 
  assume /exercise[id]/open;
 
  update /exercise[id]/open false;
}

Create Account

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

Create Empty Stat System

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

Create Exam

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

Create Exercise

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

Create Grade

createGrade(ident uid, ident id, ident gradeId, string name, double value, double minPoints) {
  assume exists /account[uid]/examiner[id];
 
  assume exists /exam[id]; # implicitly true in OO implementations
  assume not exists /exam[id]/grade[gradeId];
 
  assume count(value, /exam[id]/grade/value) = 0;
  assume count(minPoints, /exam[id]/grade/minPoints) = 0;
 
  assume exists /exam[id]/grade[x] && /exam[id]/grade[x]/value < value -> /exam[id]/grade[x]/minPoints > minPoints;
  assume exists /exam[id]/grade[x] && value < /exam[id]/grade[x]/value -> minPoints > /exam[id]/grade[x]/minPoints;
 
  insert /exam[id] <grade id=[gradeId] name=[name] value=[value] minPoints=[minPoints] />;
}

Create Group

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

Create Sheet

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

Create Student Account

createStudentAccount(ident username, ident studentId, string lastName, string firstName, string email, string password, string code) {
  assume not exists /account[username];
  assume count(studentId, /account/student/id) = 0;
 
  insert /
    <account username=[username] lastName=[lastName] firstName=[firstName] email=[email] password=[password] code=[code]>
      <student id=[studentId] />
    </account>
}

Create Task

createTask(ident uid, ident id, ident taskId, double maxPoints) {
  assume exists /account[uid]/examiner[id];
 
  assume exists /exam[id]; # implicitly true in OO implementations
  assume not exists /exam[id]/task[taskId];
 
  assume maxPoints >= 0;
 
  insert /exam[id] <task id=[taskId] maxPoints=[maxPoints] />;
}

Delete Account

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

Delete Exam

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

Delete Exercise

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

Delete Grade

deleteGrade(ident uid, ident id, ident gradeId) {
  assume exists /account[uid]/examiner[id];
 
  assume exists /exam[id]/grade[gradeId]; # implies the exam exists, which is implicitly true anyway
 
  remove /exam[id]/grade[gradeId];
}

Delete Group

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

Delete Sheet

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

Delete Task

deleteTask(ident uid, ident id, ident taskId) {
  assume exists /account[uid]/examiner[id];
 
  assume exists /exam[id]/task[taskId]; # implies the exam exists, which is implicitly true anyway
 
  assume size(/exam[id]/participant/result[taskId]) = 0;
 
  remove /exam[id]/task[taskId];
}

Grant Admin Rights

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

Grant Assistant Rights

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

Grant Examiner Rights

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

Grant Tutor Rights

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

Hide Results

hideResults(ident uid, ident id) {
  assume exists /account[uid]/examiner[id];
 
  assume exists /exam[id];
 
  assume /exam[id]/published;
 
  update /exam[id]/published false;
}

Leave Team

leaveTeam(ident uid, ident id, ident studentId) {
  assume exists /account[uid]/tutor[id]/group[/exercise[id]/student[studentId]/group];
    # implies the existence of the student, the exercise, the group and enough rights by a tutor account
 
  assume exists /exercise[id]/student[studentId]/team;
 
  remove /exercise[id]/student[studentId]/team;
}

Open Registration

openRegistration(ident uid, ident id) {
  assume exists /account[uid]/examiner[id];
 
  assume exists /exam[id];
 
  assume not /exam[id]/free;
 
  update /exam[id]/free true;
}

Open Sign-Up

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

Publish Results

publishResults(ident uid, ident id) {
  assume exists /account[uid]/examiner[id];
 
  assume exists /exam[id];
 
  assume not /exam[id]/published;
 
  update /exam[id]/published true;
}

Register Student

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

Remove Participant

removeParticipant(ident uid, ident id, ident studentId) {
  assume exists /account[uid]/student && /account[uid]/student/id = studentId && /exam[id]/free
      || exists /account[uid]/examiner[id];
 
  assume exists /exam[id]/participant[studentId]; # implies the exam exists, which is implicitly true anyway
 
  assume size(/exam[id]/participant[studentId]/result) = 0; # don't allow to remove if results are there
 
  remove /exam[id]/participant[studentId];
}

Remove Result (Sheet)

removeResult(ident uid, ident id, ident studentId, ident sheetId) {
  assume exists /account[uid]/assistant[id]
      || exists /account[uid]/tutor[id]/group[/exercise[id]/student[studentId]/group];
 
  assume exists /exercise[id]/student[studentId]/result[sheetId]; # implies the existence of pretty much everything
 
  remove /exercise[id]/student[studentId]/result[sheetId];
}

Remove Result (Task)

removeResult(ident uid, ident id, ident studentId, ident taskId) {
  assume exists /account[uid]/examiner[id];
 
  assume exists /exam[id]/participant[studentId]/result[taskId];
    # implies the exam, account, student role and task exist by integrity
 
  remove /exam[id]/participant[studentId]/result[taskId];
}

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

Request Reset

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

Reset Password

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

Revoke Admin Rights

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

Revoke Assistant Rights

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

Revoke Examiner Rights

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

Revoke Tutor Rights

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

Sign-Out Group

signOutGroup(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]/group;
    # implies existence of the exercise and student, even the group
 
 
  update /exercise[id]/group[/exercise[id]/student[studentId]/group]/curSize
    (/exercise[id]/group[/exercise[id]/student[studentId]/group]/curSize - 1)
  remove /exercise[id]/student[studentId]/group;
}

Sign-Up Group

signUpGroup(ident uid, ident id, ident studentId, ident groupId) {
  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 existence of the exercise
  assume exists /exercise[id]/group[groupId]; # also implies it, but once is really enough
 
  assume not exists /exercise[id]/student[studentId]/group;
  assume /exercise[id]/group[groupId]/curSize < /exercise[id]/group[groupId]/maxSize;
 
  insert /exercise[id]/student[studentId]/group groupId;
  update /exercise[id]/group[groupId]/curSize (/exercise[id]/group[groupId]/curSize + 1);
}

Unregister Student

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

Validate Account

validateAccount(ident username, string code) {
  assume exists /account[username]/code; # implies existence of the account
 
  assume /account[username]/code = code;
 
  remove /account[username]/code;
}