Table of Contents

Exercise Management and Sheets

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.

Schema

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

Procedures

Change Attributes

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

Assistant Management

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

Group Management

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

Sheet Management

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

Student Management

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