CodEx - Design Manual
CodEx - Design Manual
Martin Mares
Tomas Gavenciak
Martin Krulis
Jiri Svoboda
Lukas Turek
Table of Contents
1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 An Introduction to Automatic Grading Systems. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Overview of the CodEx System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3 Development Timeline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4 CodEx Components and Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4.1 Components of the CodEx Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4.2 Third-party Components Distributed with CodEx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4.3 External Dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.5 Assessment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.3.2 Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.3.3 Authorization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.3.3.1 Admin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.3.3.2 Protected Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.3.3.3 Rights . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.3.3.4 Delegated Rights . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.3.4 Implementation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3 Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.1 Services Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.1.1 Protocol Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.1.1.1 Client Query . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.1.1.2 Service Response . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.1.2 Services Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.2 Creating New Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.2.1 Debugging and Security Matters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.3 Implemented Services. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.3.1 add_user Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.3.1.1 Query Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.3.1.2 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.3.2 edit_user Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.3.2.1 Query Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.3.2.2 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.3.3 list_group_results Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.3.3.1 Query Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.3.3.2 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.3.4 change_membership Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.3.4.1 Query Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.3.4.2 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4 Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.1 MVC (Model-View-Controller) Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.1.1 MVC General Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.1.1.1 Processing Requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.1.1.2 Bootstrap (index.php) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.1.1.3 Page Representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4.1.1.4 Routing and Dispatching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.1.2 PageManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.1.2.1 Page Paths and Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.1.2.2 Component Paths and Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.1.2.3 Generics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.1.3 Dispatcher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.1.4 PageAbstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.1.4.1 Initialization and Rights Verification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.1.4.2 Filtering GET (URL) Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.1.4.3 Creating URLs and Redirects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.1.4.4 CSS and JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.1.4.5 Page Rendering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.1.4.6 Error and Informational Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.1.5 ParamFilter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.1.6 View Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.1.7 Session . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.1.7.1 Implementation Details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
iii
5 Database Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.1 Database Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.2 Database Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.3 Table users . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.4 Table groups. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.5 User-group Relation Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.5.1 Table users_in_groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.5.2 Table bonus_points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.6 Table exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.6.1 Table texts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.7 Table tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.8 Table task_points . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
5.9 Table submits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
5.9.1 Table solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
iv
6 Data in Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
6.1 Directory structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
6.2 Exercise Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
6.3 Metadata File Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
6.3.1 Generic Format. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
6.3.2 Attribute Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
6.4 Exercise Export And Import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
6.4.1 Package Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
6.4.2 XML Contents File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
6.4.3 Exporting/Importing Mechanism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
7 Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
7.1 Communication Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
7.1.1 Definition of Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
7.1.2 Protocol Specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
7.2 Evaluation Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
7.3 Modifications for CodEx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
7.4 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Appendix A Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
1 Introduction
Generally an automatic grading system can evaluate the source code statically (i.e. by
examining the code without running it, for example assessing the coding style) or dynamically,
running the code on some testing data. The testing data can be provided by the author of the
problem, or sometimes even generated on the fly.
Among the main strengths of CodEx is its comfortable web-based interface, allowing the
users to enter and solve problems from practically anywhere. CodEx is very modular and it
can be easily run in a distributed fashion, making it highly scalable. Finally, having its security
based on a sandboxing/virtualization principle, CodEx allows the users to solve the problems in
a standard programming environment, bypassing the need for them to get aquainted with any
special libraries or protocols.
Chapter 1: Introduction 2
Mono 1.2.5.1
C# compiler and MSIL interpreter, available at http://www.mono-project.com/.
Required for C# evaluation. CodEx uses a slightly patched version, the original
version is not compatible with sandbox.
Reader and Wrapper
C# classes that are linked to every evaluated C# program. Released as public
domain.
1.5 Assessment
The major goal of this project was to create a stable application that will be used for the first-
year programming course at the Faculty of Mathematics and Physics, Charles University. These
ambitions were met quite completely, since CodEx has already been used and tested on Summer
School for Teachers of Informatics and will be deployed at the faculty during the next scholar
year.
The main goal has been accomplished, however many issues were left unfinished and will
be attended in the future. GUI ergonomics are insufficient and graphic design is poor. Some
unimportant issues were left undocumented for the time being and there are minor redundancies
in the written code. All these issues were caused by lack of time and will be solved in the nearest
future.
Even though there are some unfinished bits and pieces the application is fully operational
and ready to be used in production. Thanks to huge experience from the previous version of
the CodEx application that was in use on MFF last scholar year, the developement was smooth
and we did not walk into any serious obstacles.
Chapter 2: Web User Interface 4
bonusPoints
A list of bonus points for all users and a simple form that allows granting bonus
points to multiple users at once. Bonus points are arranged in a table where each
row represents one user and columns are bonus points aggregated by their comments
(bonus points with the same comment are displayed in one column).
If the user has no special rights and the group is discreet (see groups.discreet
database field), he/she can only see his/her bonus points. Users with RIGHT_READ
can see all bonus points and users with RIGHT_EDIT may even grant and revoke
them.
Users with RIGHT_EDIT can see the points in text edit boxes so they can edit and
revoke them. There’s also a simple form underneath that allows to create a new
column (comment group) in the table. The new column is created empty and it will
not be saved into database unless some points are entered into it.
submits A list of all submits that the user is allowed to see. Group members with no special
rights can only see their own submits. Users with RIGHT_READ (for the selected task)
can see all submits from all group members, and finally, users with RIGHT_EDIT may
even delete and re-evaluate submits.
If the GET parameter taskId is specified, only submits related to that task are
displayed. Otherwise, all submits for all tasks in the selected group are displayed.
On this page, the user can also change which task is selected by selecting another
task from a pull-down list.
The table of submits is equipped with a filter form, where the selected task may be
changed and other filter restrictions applied. It is possible to restrict the listing just
to submits from a given user, time period or points range.
A checkbox is displayed next to each submit for users with RIGHT_EDIT. These
checkboxes mark submits that are affected by delete and reevaluate buttons be-
neath the form. Both buttons are part of the same form that encapsulates also the
checkboxes. This form is also handled by this page.
submitInfo
More detailed information about one submit. It is visible for all users with RIGHT_
READ for the submit. Users with RIGHT_EDIT may even change attached bonus
points, delete the submit or send it for re-evaluation. Changing the amount of bonus
points is handled by a form component. Re-evaluation and deletion is handled by
the actions reevaluate and delete that are handled by this page.
The page displays summary information (time, points...), the evaluation log and the
submitted source code. A user with RIGHT_EDIT can also see additional information
from eval (such as consumed time and memory for each test, results from judges
etc.) Some data (e.g. the evaluation log) will not be available if the submit has not
been evaluated yet.
This page requires the GET parameter submitId to point to the submit that is
being displayed. If omitted, the browser is redirected to the submits page.
Delegations are displayed in a table and each delegation is equipped with a revoke
button that triggers a revoke action (which is also handled by this page). This is
the only place where delegations can be revoked. The only place where they can be
granted is the users/rights page.
At the bottom of the page, there is an additional form that allows changing the
author of the exercise. This form is visible only to users with RIGHT_ADMIN for the
exercise. When the author is changed and Keep Admin Rights box is checked, admin
rights are delegated to former author. Granter of these rights is implicitly an actor.
If the actor is also the former author, rights are delegated by admin (since nobody
may grant rights to himself/herself).
The properties page is only visible for users with at least RIGHT_READ for the selected
exercise. To edit the properties, however, one needs at least RIGHT_EDIT. Users
with RIGHT_ADMIN can also see the delegations. The Page also requires the GET
parameter exerciseId to hold the ID of the exercise for which the properties are
displayed. If omitted, the browser is redirected to the index page.
specification
The text of the current exercise specification and a list of all specification versions,
identified by their date of creation. The user can also examine the texts of other
versions by clicking on their captions in the list. With RIGHT_EDIT for the selected
exercise the user may also delete versions and change which version is the current
one. Corresponding buttons in the list generate delete and setActual actions that
are handled by this page.
Specification versions can be also be edited. An edit button directs the browser on
the editText page with the proper GET parameters set.
The page requires the GET parameter exerciseId to hold the ID of the exercise
whose specification is being displayed. Also the page may receive the GET parame-
ter textId that holding the ID of the specification version that should be displayed.
If this parameter is omitted, the current version is displayed.
If there are no specifications of the exercise yet, the browser is redirected to the
editText page.
editText A form for editing the selected version of the specification. Modifications submitted
by this form are handled by this page. The form may be submitted either in two
ways: simply a save (modifications are saved into the existing specification version)
or saved as new version (which creates new version of the specification and makes
it the current one). If the exercise has no specification versions yet, the form can
only be saved as a new version.
This page is only visible for users with at least RIGHT_EDIT for the selected exercise.
The page also requires the GET parameters exerciseId and textId that refer to
the exercise and its specification that is being edited. If textId is omitted, the form
is blank and can be only used for creating new text.
attachedFiles
List of files attached to a given specification. Each specification can have its own
directory tree with pictures, files for download etc. These are managed with a file
manager component on this page.
Only users with at least RIGHT_EDIT may modify files in the directory. The page
also requires the GET parameter exerciseId pointing to the exercise and optionally
textId pointing to the specification version to which the displayed directory belongs
to. If textId is not set, the files attached to the current version are displayed. If
the exercise does not have any specification, the page is inaccessible.
Chapter 2: Web User Interface 9
configuration
A form for editing basic test configurations. All general test properties may be mod-
ified here except points and resource limits. Configuration parameters are parsed
directly from eval’s config test file and when editing form is submitted the file is
atomically replaced.
This page is visible for all users (with RIGHT_READ of course) but only users with
at least RIGHT_EDIT may edit parameters and save them. The page also requires
GET the parameter exerciseId which holds the ID of the exercise whose test’s
configuration is being edited.
limits Special form for modifying points per test, time limit and memory limit values. This
page can either edit general limits for all extensions or limits that are designed for
one extension only.
At the top of the page there are text boxes for editing general values for all tests (in
given extension). They are followed by table where individual values for each test
may be defined. These values are combined in following order (ordered from most
to least important:
- Values defined for individual test and individual extension.
- Values defined for individual test and all extensions.
- General values for all tests in individual extension.
- General values for all test and all extensions.
The page also contains special interface that allows experts add and modify extra
(non-standard) parameters to config files.
All values displayed on this page are parsed directly from exercise’s config file and
if the form is submitted, the file is atomically replaced.
Every user with RIGHT_READ has access to this page but only user with RIGHT_
EDIT for given exercise may change its values. Page also requires exerciseId GET
parameter that holds id of an exercise whose config file is being edited and optional
extension parameter that holds the extension (defining programming language) for
which the limits applies. If omitted, general limits are edited.
testFiles
Contents of the directory attached to the exercise. This directory contains files
used for testing submitted solutions of the exercise (input data and corresponding
output). How these files are used is defined by test configuration (see configuration
page).
This page is visible for all users (with RIGHT_READ, of course) but only users with
at least RIGHT_EDIT may modify the files. The page requires the GET parame-
ter exerciseId that specifies the exercise whose test-files are being displayed (or
edited). If omitted, the browser is redirected to the index page.
assignTasks
Assigning exercises (creating tasks) to groups. This page displays some information
about the exercise that might be useful for a group owner who wants to use this
exercise, and a list of all groups to which the user has at least RIGHT_EDIT. The
user may check groups to which he wishes to assign the task (thus, multiple tasks
may be created at a time).
The page also contains a form with basic task parameters (the deadline, points etc.)
that are used as defaults for newly created tasks.
The page requires the GET parameter exerciseId to hold the ID of the exercise
that is being assigned.
Chapter 2: Web User Interface 10
create Page with general form that creates new comments. Data from the form are pro-
cessed by the page and after successfull submit the browser is redirected to the
index page of current module.
Only users with at least RIGHT_EDIT_BASIC for selected exercise may see this page.
edit Page with the very same module as the create page. Except the form is filled by
data from selected comment and when submitted the comment is updated. Sub-
mitted data are also handled by this page. After submit or cancel operation, the
browser is redirected back to index page.
This page requires GET parameter commentId which points to exercise comment
that is being edited.
Access to this page is restricted only for users with RIGHT_EDIT for selected exercise
or for author of the comment.
Also, any user having access to this page (i.e. general RIGHT_READ for users) includ-
ing admin may edit his own properties.
This page requires a GET parameter userId that holds the ID of the user who is
being edited.
rights Overview of general rights and delegations. Rights are displayed in a form where
the actor can select from prepared roles or set general rights manually.
Delegations are displayed in two tables – one for groups and one for exercises. Actor
may see only those delegations he/she may also revoke. Every delegation is equipped
with a check box. A revoke button that removes all selected delegations is placed
beneath the table. It triggers a revokeQuery action that shows query dialog and if
confirmed triggers revoke action. Both actions are handled by this page.
This page is also the only place in the system where delegations can be granted.
There are also two forms (for groups and exercises) where the actor can select a
group/exercise for which he/she has RIGHT_ADMIN and delegate rights for it. Data
from these forms are also handled by this page.
This page is accessible for an actor having RIGHT_EDIT_BASIC. The actor must
have at least RIGHT_EDIT to edit general rights, although he/she may never grant
nor revoke right that he/she does not have. An actor with RIGHT_ADMIN for users
may edit general rights without restrictions.
Nobody can modify his/her own rights.
This page requires a GET parameter userId that holds the ID of the user whose
rights are edited.
$dialog = PageManager::getInstance()->getDialogObject(’query’);
$dialog->initializeDialog($this->createUrl(’’, array(), true, false));
$dialog->setDialogName(tr(’Important Decision’));
$dialog->setMessage(tr(’Do you wish to perform %s action?’), ’Test’);
$dialog->addButton(tr(’Yes’), $this->createUrl(’test’));
$dialog->addButton(tr(’No’), $this->createUrl(’’, array(), false), false);
$dialog->redirect();
ID is passed to the dialog along with fallback page URL via GET parameters dialogQueryId
and fallbackUrl. Both parameters are mandatory since dialog can not work properly without
them.
Described approach brings one severe problem – session growth. Every time new dialog is
created, new session storage is allocated and filled with data. Therefore a mechanism must exist
to unset storages that are no longer needed. This storage is released when user confirmes of
rejectes the dialog.
All buttons are action buttons therefore any user’s decision will invoke a POST request.
Link-like buttons are directed to the redirect action of dialog controller which releases the
session storage and preforms the redirect. Other buttons are slightly modified and URL of
each one is provided with extra GET parameter (_dialogQueryId) that carries ID of the dialog
instance. When action is performed this parameter is intercepted by MVC dispatcher who is
responsible for removing the data storage.
If the user leaves dialog page by other means (e.g. by Back button in his/her browser), the
data will endure until user logs out. This problem is known yet unattended for the time being.
Whole dialog matter has been affected by spaghetti design and code injection pattern. How-
ever re-factorization is not planed since the dialog is functional and quite separated.
• Specification
• Attached Files
• Tests Configuration
• Tests Files
• Assign Tasks
• Solution Database
• Submit Solution
• Users
• Create User
• Properties
• Rights
• Personal Settings
2.2 Components
2.2.1 Component Overview
Since we try to implement every piece of functionality only once, the component system was
introduced. This system is tightly integrated with MVC. Therefore, we recommend reading the
MVC section first. See hundefinedi [MVC], page hundefinedi
Components are very similar to pages. They have a controller class that must be derived from
PageComponentAbstract and a template. Both the controller and the template are stored in
the ‘components/component name ’ directory in the files ‘controller.php’ and ‘template.php’.
Access to these files is managed by the PageManager class.
Each component must be registered in the the controller class of the page where it is sup-
posed to be displayed. Upon registration a unique ID is assigned to the component. Multiple
components of the same type can be placed simultaneously on the page.
2.2.1.1 PageComponentAbstract
The controller of a component must be derived from the PageComponentAbstract class. Much
like the page controller, the component controller is responsible for rendering and handling
actions.
The component can define a list of internal GET parameters and their filtering rules. General
rules are stored in the $getParams member variable and action GET parameter rules are in
$getActionParams. These two fields are formatted the same way as the corresponding fields in
the page controller object. When a component is registered, the GET parameter rules of the
component are merged with GET parameter rules of the page.
The GET parameters live in separate namespace. A simple name-mangling scheme is applied,
composing the final name of the parameter as Ccomponent Id_. I.e.m if the component 42 has
a parameter named ‘foo’, this parameter will have the real name C42_foo). The mangling is
performed automatically by the registerComponent method.
After registration, the initialize method is called. This method does nothing, however it
can be redefined in derived classes. The initialization routine can also hold code that cannot go
into the constructor for some reason (for in the constructor the component is still not registered).
It is strongly recommended to put as much code as possible here instead of the constructor, since
initialization is called only when its clear that the component will really be needed.
The component can also handle actions. Component actions are handled the very same way
as page actions. The only difference is that the action GET parameter should be formatted
Chapter 2: Web User Interface 16
as an array. The key of this array is the component ID and the value is the action name. For
example, a request with the parameter ‘action[42]=delete’ parameter will be dispatched to
the component with ID 42 on which the deleteAction method will be called.
Rendering is performed by the renderView method. This method prepares the view object
and renders it using the component template. Relative path to the template is defined in the
$template member variable. If no template is defined, the default ‘template.php’ is used from
the directory of the component. After the view object is created, the prepareView method is
called. This method does nothing, but descendant classes can use it for additional initialization
of view data.
Each component has its own list of CSS and JavaScript files. They are stored in the css and
js member variables as arrays. When the component is registered, these lists are merged with
lists on the page. Scripts and styles should be written with respect to the independent nature
of components. For example, the CSS selectors should only use general classes (not selectors for
individual IDs).
$dbCols - Seznam databzovch sloupc, kter jsou poteba k renderovn tohoto tabulkovho
sloupce. Kad sloupec je definovn v poli jako alias => definiceSloupce. Pokud je alias vynechn,
pouije se nzev sloupce z SQL. definiceSloupce me bt jednoduch (jen etzec pro SQL), nebo pole
array(aliasTabulky, sloupec), kde alias tabulky je odkaz na nkterou z tabulek definovanou v $de-
faultTable a $joinTables. Pokud je alias tabulky vynechn, bere se automaticky $defaultTable.
SQL alias sloupce (ppadn jeho DB jmno - pokud nem alias) pak lze pout uvnit $template.
$orderBy a $orderByDesc - Ukldaj nastaven poloky ORDER BY, pokud se pouije tdn podle
tohoto sloupce. Nastaven je uloeno ve formtu array(nzevDBSloupce => smr), kde smr me bt 1
(vzestupn), nebo -1 (sestupn). V ppad, e nejsou poloky definovny pi inicializaci, dopln se do nich
automaticky sloupce definovan v $dbCols (ve stejnm poad, v jakm jsou v dbCols definovny).
Vechny doplnn lensk promnn lze inicializovat stejn, jako u rodiovsk tdy. V parametrech se
uvd ve stejnm poad, v jakm jsou popsny zde a a za parametry rodiovsk tdy.
Pklad pole, kter se m pedat konstruktoru: array( ’id’ => array( ’Id’, // popisek ’center’, //
align ’middle’, // valign false, // nezalamovat false, // expandovat false, // tdit ’$id’, // template
pouze zobraz sloupec "id" array(’id’) ), // potebuje sloupec id z vchoz tabulky ’name’ => array(
caption => ’Jmno’, align => ’left’, valign => ’middle’, sorting => true, template => ’<b>$name
$surname</b>’, // slo jmno a pjmen tun dbCols => array( ’surname’ => array(’users’, ’sur-
name’), // users.surname AS surname ’name’ => array(’users’, ’name’) // users.name AS name
) ), );
Filtry: ——- V nkterch ppadech si nevystame pouze s primitivnmi templaty (viz ve), ale
potebujeme sloitj operace nad petenmi daty, kter navc meme udlat efektivn pouze v PHP (nap.
pkn pevod unix-timestampu na datum a as nebo vytvoen odkazu). Od toho jsou tu filtry.
Filtry jsou konverze definovan pmo nad daty vytaenmi z databze, ne se pedaj k zrenderovn
pomoc triviln ablony sloupce.
Definice filtr jsou uloeny v poli $dbColumnFilters. Indexem je nzev sloupce, kter se m
filtrovat, a hodnotou je filtrovac funkce. Filtrovac funkce je pedna bu jako etzec (identifiktor
lensk funkce), nebo jako pole, kde prvn prvek je opt etzec (identifiktor) a nsledujc prvky jsou
dodaten argumenty.
Filtr mus bt lensk funkce modelu (nejlpe s protected pstupem). Prvn dva jej parametry jsou
&$row, $col, kde $row je objekt s daty jednoho dku, kter se prv renderuje a $col je nzev sloupce,
pro kter je funkce urena (tj. kter se m filtrovat). Pochopiteln funkce me teoreticky sahat na
vechna data v dku a modifikovat je, nicmn je dobr dodrovat, e funkce modifikuje pouze sloupec
$col.
Filtr me mt i vce parametr, prvn dva zstvj &$row a $col, ostatn parametry mus korespondovat
s parametry, kter jsou funkci pedny (viz formt zpisu filtr popsan ve).
and size (for files) is displayed. Also there’s a graphical icon indicating the type of the entry.
Files also have a small floppy-disk icon in the rightmost column. Clicking on it will activate a
download link for the file. Clicking on the name of the file will activate a view link (displaying
the contents of a text file in the browser). Clicking on the name of a directory will switch to
that directory.
When inside a directory, a special ’..’ entry is display at the first line for switching to the
parent directory. Also, links to all directories on the active branch (i.e. the branch leading to
the working directory) are displayed for fast switching to any superior directory.
2.3 Security
Security is one of the most delicate issues in every information system. The security model
employed in CodEx consists of three principal parts:
• The Trusted Base and Its Protection
• Authentication
• Authorization
Note that this section does not aim to cover all security-related issues in CodEx. Also, the
considerations that need to be taken into account when operating the system are beyond the
scope of this manual.
2.3.2 Authentication
Authentication is the process of verifying the user’s identity. Unauthenticated users may not
perform any action within the system nor see any relevant data.
Authentication is performed by verifying the user’s login name and password. The user
logs in with his/her login, that is assigned to him by the system upon registration or with
his loginAlias which the user may pick for himself/herself. The password is stored in the
database in hashed form (for details see users.passwd in database description). Even though
the database considered a part of the trusted base, the passwords are stored hashed due to their
high level of confidentiality. Other users’ passwords should be revealed to no one, not even the
administrator. Moreover, this significantly reduces the confidentiality of database backups.
When the user logs in, a session object is created. PHP sessions are protected by a validation
key that is stored in the session and in a cookie at the client side. The key is changed after
every operation, so it is nearly impossible to steal. The session manager also verifies the client’s
IP address and the login information expires after a certain time interval.
Chapter 2: Web User Interface 22
2.3.3 Authorization
The authorization is the process of verifying that the user possesses rights to carry out a par-
ticular action. CodEx applies the concept of minimum rights. Therefore anything that is not
explicitly permitted is forbidden.
The authorization process uses a simple security model based on Bell-LaPadula. Every time
the user needs to perform a sensitive action with a protected object, the application asks the
security model (the monitor) what maximum authorization level (called rights) the user has
for that object. Also, every action has a minimum required authorization level (rights)r. If
the user’s rights ≥ required rights for the action, permission to execute the action is granted
(otherwise it is denied).
Rights need not be bound to a single object. In some other cases the application may ask
security model what rights the user has for all objects of the same kind. Rights to all objects
are called general rights. These are described in detail in the Rights subsection.
Example: The user wants to delete a group. The security model says that the user has
RIGHT_ADMIN for the group and, to delete a group, at least RIGHT_DELETE is required. Since
RIGHT_ADMIN ≥ RIGHT_DELETE, the operation is permitted.
Another example: The user wants to create an exercise. There’s no exercise object yet
(because the application does not know whether the user may create it), so the security model is
asked for general rights that user has for all exercises. Unfortunately the user has only RIGHT_
READ for exercises and since RIGHT_READ < RIGHT_CREATE, the exercise cannot be created.
2.3.3.1 Admin
The system must have one special user account. This account is usually called ‘admin’ (short
for administrator) and it has pretty much the same role as the root account in UNIX systems.
The admin has id == 1 and he/she is automatically granted maximum rights (RIGHT_ADMIN)
for any object in the system. Furthermore, this account cannot be deleted nor modified by any
other user.
The admin also plays a special role of a ’garbage collector’. When a user is deleted, some of
his assets (groups and exercises) must be transferred to another user (since groups and exercises
must have an owner). Typically, these assets are transferred to the user who performed the
deletion. However, sometimes this need not be possible. In this case the assets are transferred
to the admin. Therefore, the the admin account must always exist.
Each object is represented by one row in the corresponding table. Rights are always attached
to one particular object and general rights are attached to object types (tables). There is no
need for keeping rights to user objects, thus only general rights are applied for users (plus some
special rules described later).
Some objects are not independent and instead belong to another object. Specifically, every
submit belongs to a task and every task belongs to a group. Therefore, submits and tasks
are considered to be a part of a group. When the user manipulates with them, rights of the
corresponding group are tested instead. Likewise, the texts and solutions belong to an exercise.
These substitutions of rights may cause some complications, so one has to be careful when
dealing with them. Fortunately, simple logic still works, so it is not so difficult to figure out
which rights should be tested.
For example: The user wants to delete a task. Normally we would test whether the user has
at least RIGHT_DELETE for given task. However, the task does not keep any rights at all and
receives the rights of its group instead. But the rights for deleting a group (with all tasks and
submits) are quite stronger than the rights to remove one tiny task from a group.
We must not be too dogmatic in testing the rights and use common sense in this case.
Removing task from a group should be considered more like a modification of the group since all
tasks are part of some group anyway. Therefore we should not test the task (or more precisely
the group) for RIGHT_DELETE, but for RIGHT_EDIT instead.
Each case must be considered separately. Most common cases are described in the description
of each page. See Section 2.1 [Page Hierarchy], page 4
2.3.3.3 Rights
Effective rights for the given object (that are returned by the security manager) are computed
as the maximum value from:
• General rights are stored directly in the user’s account and they represent rights for all
objects of the specified kind. We recognize general rights for users, groups, exercises and
news.
• Owner’s rights. All objects except users, tasks and texts have an owner. The owner is the
user who (typically) created that object and who administers it. The owner of any object
except a submit has RIGHT_ADMIN for that particular object and the owner of a submit has
RIGHT_READ for that submit.
• Delegated rights – will be described later.
• Substitutional rights are obtained from the object to which the tested object belongs to. See
Section 2.3.3.2 [Protected Objects], page 22 For example, if the security manager examines
the rights for a task, substitutional rights from the group where the task belongs to are
consulted, too.
Rights (authorization levels) can have the following values:
RIGHT_NONE
Means ’no particular rights’. It is default value if no explicit rights are defined (so
everybody possesses this right to every object).
RIGHT_CREATE_PRIVATE
This right only applies to groups and news. A user possessing this right may create
obejects of the corresponding type, but with some restrictions. In case of groups, the
group cannot be made public and in case of news, the news item must be designated
for one group only (i.e. not public).
This right is meaningful only when used as a general right.
Chapter 2: Web User Interface 24
RIGHT_READ
Right to read a given object. What that exactly means depends on the object type.
For example, the right to read an exercise also allows the user to read the test files
and all public submits. However, there are some exceptions from this right. For
example, the general right to read exercises does not permit the user to read private
exercises.
RIGHT_EDIT_BASIC
Right to perform minor modifications on an object. For example, a user with this
right for exercises may submit his/her own solution, but he/she may not edit the
exercise properties nor the specification.
RIGHT_CREATE
The right to create a new instance of an object without any restrictions. This right
is meaningful only when used as a general right.
RIGHT_EDIT
Right to edit any parameter (which is editable) of the given object without any
restrictions. This right, however, does not allow the user to delete the object.
RIGHT_DELETE
Right to delete the object with all related parts (for example, deleting a group with
all tasks and submits that belong in that group). Some objects may not be deleted
despite the user having the right to do so (for example, an exercise may not be
deleted if it has been assigned as a task).
RIGHT_ADMIN
Ultimate rights to the object. Usually, only object owners and the administrator
have such rights. This right permits any action on the object. A user with these
rights may also hand over the object to another user or delegate rights to other
users.
Levels are ordered from minimum to maximum rights. A higher level includes all rights from
the level below. E.g., RIGHT_READ is a subset of RIGHT_EDIT.
rights for it) so she decided to delegate RIGHT_EDIT to Bob (for group G). Bob could manage
the group (create tasks, grant bonus points etc.), but he could not delete the group, change its
owner nor delegate any rights for it to other users.
After a few days Bob had an accident (poor Bob!) and he ended in a hospital. So he
asked Carl to take over for him. Bob could not delegate Carl any rights so he asked the
almighty administrator to do so. Admin used his divine power and blessed Carl with RIGHT_
EDIT delegation for group G, so Carl could perform the same actions as Bob.
When Bob finally got out of the hospital, he saw that Carl is doing just fine, so he decided
to let him continue managing the group G. Therefore, he yielded his delegation for G, because
he did not want to pose a security threat.
When Alice came back, she found out Carl was administering her group. She did not delegate
any rights to Carl, but she had administrator rights for G, so she revoked Carl’s delegation and
invited him to a dinner.
They got married and had a bunch of kids, but that is a completely different story...
2.3.4 Implementation
All security-related methods are implemented by the SecurityManager class. Since these meth-
ods are always required and there is no need for class inheritance it is implemented as a static
class. The security manager requires the session to be initialized before itself, because it uses
the session to store login information. The SecurityManager::intitialize() must be called
before any other method.
Rights are always stored as an 8-bit unsigned integer (0..255) where 0 always stands
for RIGHT_NONE and 255 for RIGHT_ADMIN. Other values are defined as constants in the
SecurityManager class. It is strongly recommended to use these constants, instead of hard-
coded numeric values. Integer representation of rights was chosen so that rights can be easily
compared and the gaps between levels were left so that new rights may be defined in the future.
The security manager also logs important events into a security log. Important events are:
• A user logs in.
• Failed login attempt.
• Delegating rights.
• Revoking delegations.
For more details about the implementation, see the source-code reference.
Chapter 3: Services 26
3 Services
• message - Error message that is ment to be shown to the user or entered into a log. This
message is present only if error has occurred.
• data - Voluntary section that is present only if the service needs to return any data and
the retrieving operation succeeded. Format of this element is service dependent.
5. After the service is implemented and tested, service documentation should be added into
this document. The documentation should contain full specification of query parameters,
service functionality and returned data.
In the implementation you may use all libraries and modules implemented in CodEx, however
it is forbidden to user web-specific code especially the session module.
3.3.1.2 Results
Except for general result codes this service may also return:
• 100 - Given login already exists.
• 101 - Unable to save results into CodEx database.
If the operation succeeds, the service returns data section with single element user_id, which
holds CodEx ID of newly created user.
Chapter 3: Services 29
3.3.2.2 Results
Except for general result codes this service may also return:
• 100 - Target account does not exist. Invalid user ID or login were given.
• 101 - Unable to save results into CodEx database.
The service does not return any additional XML inside data element.
3.3.3.2 Results
This sevice does not have any special result codes of it’s own. All retrieved data are stored in
XML data element in following format.
First all the tasks are listed. Each task is encapsulated in one task element and has id
attribute. This attribute holds the task ID from the database with ‘t’ prefix (see example).
Chapter 3: Services 30
Task contain three obligatory subelements in fixed order: caption and obligatory. Element
caption holds a string with caption of the exercise. Obligatory points is an integer value which
corresponds to tasks.obligatory database column.
List of users follows after the tasks. Every user is encapsulated in user element with id and
login attributes that holds user’s ID and login respectively. User has following subelements
presented in fixed order. The first subelement is name that contains full name (name, middle
name and surname) of the user.
The name is followed by list of task_points elements. Every element holds information
about points that were scored to the user for one specific task. Element has attribute id that
points out to the task in question and optionaly an attribute bonus with amount of task bonus
points scored. Element content is an integer with amount of scored points. Only tasks solved
by the user are listed here. The list is terminated by task_sum element with total sum of all
points and task bonus points from all tasks scored for the user.
After task points the bonus points are listed (meaning external bonus points – not task bonus
points). Format is very similar to task points. Each bonus points item is presented in bonus_
points element. The element has caption attribute that identifies the bonus points. List is
terminated with bonus_sum element that holds total sum of all bonus points scored for the user.
At the end there are elements total holding total sum of both task and bonus points and
done element with boolean flag that signals whether or not the user has meet group requirements.
The bool value is represented by 0 and 1 values.
For more information see the XML Schema for this service and following example of possible
result.
<data>
<task id="t1">
<caption>Find The Minimum</caption>
<obligatory>0</obligatory>
</task>
<task id="t2">
<caption>Hippo’s New Fence</caption>
<obligatory>3</obligatory>
</task>
<user id="1" login="FOX">
<name>Smart Fox</name>
<task_points id="t1">10</task_points>
<task_points id="t2" bonus="3">5</task_points>
<task_sum>15</task_sum>
<bonus_points caption="Extra Homework">4</bonus_points>
<bonus_sum>4</bonus_sum>
<total>19</total>
<done>1</done>
</user>
<user id="19" login="TURTLE">
<name>Slow Turtle</name>
<task_points id="t1">4</task_points>
<task_sum>4</task_sum>
<bonus_sum>0</bonus_sum>
<total>4</total>
<done>0</done>
</user>
<user id="42" login="HIPPO">
Chapter 3: Services 31
<name>Lazy Hippo</name>
<task_sum>0</task_sum>
<bonus_points caption="Overslept">-5</bonus_points>
<bonus_sum>-5</bonus_sum>
<total>-5</total>
<done>0</done>
</user>
</data>
3.3.4.2 Results
Except for general result codes this service may also return:
• 100 - Selected user does not exist.
• 101 - Selected group does not exist.
• 102 - The user is already member of selected group. This error is relevant only when
granting membership.
• 103 - The user is not member of selected group. This error is relevant only when revoking
membership.
• 104 - The user is owner of selected group.
• 110 - Unable to save results into CodEx database.
The service does not return any additional data.
Chapter 4: Libraries 32
4 Libraries
controller. However, it can modify or generate some data itself (e.g. code fragments generated
by HtmlHelper or URLs). The template can also use the tr function for translating literals.
Data for insertion into the template are held in the View class. The View class acts as a
carrier and proxy for the data. When user-defined textual data are stored in the view object,
they are also converted from plain-text form to HTML from (escaped, sanitized). Failing to do
so would have undesirable effects and would make the system prone to XSS (script injection)
attacks.
Pages can use components – standalone parts of code (both PHP and HTML) that are meant
to be used many times. See Section 2.2 [Components], page 15
4.1.2 PageManager
The PageManager is a singleton class which is responsible for managing paths and all things
related to pages and their components. All the belongings of a page are stored in the directory
of that page. Namely controller.php, which contains the controller class of the page and
template.php with its HTML template.
PageManager assembles path to page’s directory from given module and page name according
to internal settings. It also performs the same job for the components Furthermore, the page
manager is able to load the script containing the code of the page controller and create instances
of page controller objects.
components/menu/template.php
Components cannot define their own CSS and JavaScript files. However, they can store these
files under the global style directory. See Section 2.2 [Components], page 15
4.1.2.3 Generics
Generic scripts are stored in the ‘generics’ directory which has two subdirectories:
‘controllers’ and ‘templates’. Generic controllers are controller parent classes that can
aggregate some useful methods used on several pages. Generic templates represent parts of the
page that are often displayed such as a header, a footer, error messages etc.
Access to these scripts is also provided by PageManager, which assembles the path to a given
generic controller or template.
4.1.3 Dispatcher
Dispatcher encapsulates the most important feature of the MVC framework – routing and dis-
patching requests. Requests are processed by page controllers and the dispatcher is responsible
for finding the controller and calling its proper method. Which page should be displayed or
which action should be performed is determined by three GET parameters (which are part of
the URL): ‘module’, ‘page’ and ‘action’.
module Defines the logical part of the application, where the pages belongs to. Modules
are effectively implemented as subdirectories. The module name can only contain
letters, digits and slashes, thus it can refer to subdirectories. For example, the
module ‘groups/tasks’ will have all pages stored in the ‘pages/groups/tasks’
directory.
If the module is not defined, the default module is used. The default module does
not have a name and all its pages are stored directly in the ‘pages’ directory.
page Defines which page in the module will be displayed. The page name can only contain
letters and digits. All source files belonging to a page are stored in a directory named
‘pages/module /_page ’. If the specified page does not exist, the default page called
‘index’ is used. It is presumed that every module has a default page.
action Defines the action which should be performed on the page. Actions are only valid
for POST requests. If the action is empty or the request is a simple GET, the page
is only displayed. Otherwise the proper action method is found and executed. When
an action is completed the script will send an HTTP redirect response (code 302)
to the client so the browser will not cache any POST requests in history.
The action can only contain letters and any method attending an action must be
named after the action with the Action suffix (i.e. for a ‘delete’ action the method
deleteAction will be called).
Since the routing system must be modular, an action can also be dispatched to a
page component. In this case the attribute action must be encoded as an array
with one field. The key of this field is the ID of the component and value is the
name of the action. For example, an action ‘update’ for a component with ID 2 will
be encoded in the URL as ‘action[2]=update’.
Routing is quite simple since it only loads routing parameters described above and verifies
them. In case the values are not valid, the default values are used. After routing, the parameters
can be manually overridden using the methods setModule(), setPage() and setAction().
Dispatching the requests consists of finding the proper page controller (using PageManager),
loading its code and creating an instance of the controller class. After that the page is initialized.
If initialization fails (i.e. because of insufficient rights), the dispatcher tries to load a fallback
Chapter 4: Libraries 35
page. For each page there is another page specified as its fallback page. The dispatcher follows
the hierarchy of fallback pages until it reaches the ‘index’ page in the default module. If this
page does not exist, the dispatching mechanism fails.
If any action is defined, it is dispatched. Otherwise the page template is loaded and the page
is rendered using this template.
4.1.4 PageAbstract
PageAbstract is the default parent class for all page controllers. Each controller must also hold
up to a strict naming policy that is implied by Dispatcher. A controller name is composed as:
Page_<module name>_<page name>
Since the slash character cannot be used in class names, all slashes are replaced with un-
derscores in the module name. For example, the controller class for page ‘index’ in module
‘exercises/solutions’ must have the Page_exercises_solutions_index identifier.
into $getParams. Therefore it is forbidden for common page GET parameters to contain an
underscore character since it may cause a collision with some components.
The filtering is performed by the sweepGetParams method, which is provided with an array of
parameters (usually the $_GET array) name of the current action and a Boolean value defaults.
If the defaults flag is true, it adds the default values for missing parameters. If it is set to false,
it will remove the default values from the list. Otherwise (if not set or if set to null, no such
modifications are performed).
1. Preparation of a View object. This part is handled by the createView method that creates
a view object and initializes its most important member variables. This method should not
be changed by derived classes.
Method prepareView is called at the end of createView. This method is meant to be
redefined by descendants who can initialize additional view attributes.
2. Rendering of page headers. Every page has the member variable $headers, which contains
a list of generic templates and component objects displayed before the main page. Generic
templates are situated in the ‘generics/templates’ directory and rendered using the same
view object as the main page. Components are situated in their own directories and rendered
using their own views. See Section 2.2 [Components], page 15
3. Rendering of the main page. This operation is performed by the render method of the
view object.
4. Rendering of page footers. Every page has the member variable $footers, which contains
a list of generic templates and component objects displayed after the main page. The
principle is the same as with the headers.
4.1.5 ParamFilter
The ParamFilter class provides an engine for filtering and validating parameters passed to the
PHP script via HTTP requests. It operates on an associative array (usually on $_GET or $_POST
superglobals). In the following text the term parameter shall stand for one name-value pair in
an associative array.
Each filter has a set of filtering rules. The rules describe which parameters are allowed and
the constraints on the value of each parameter. The ruleset is stored in an associative array
in which the keys are parameter names and the values are constraints for the value of each
parameter.
Constraints are represented as numbered arrays and each field represents one constraint
attribute. The first attribute (index 0) is always the data type of the parameter (all types
are represented as ParamFilter constants ParamFilter::PARAM_type ). The meaning of other
attributes depends on the data type and will be described below. These attributes are all
optional.
• ParamFilter::PARAM_INT – the parameter must be an integer.
[1] – lower bound (if the value is less than the lower bound, it is clamped to fit).
[2] – upper bound (if the value is greater than upper bound, it is clamped to fit).
[3] – default value (if not defined, ‘0’ is used).
• ParamFilter::PARAM_FLOAT – the parameter must be a floating-point value in decimal
notation.
[1] – lower bound (if the value is less than the lower bound, it is clamped to fit).
[2] – upper bound (if the value is greater than the upper bound it is clamped to fit).
Chapter 4: Libraries 38
$this->getParams = array(
’amount’ => array(ParamFilter::PARAM_INT, 1, 50, 20),
’people’ => array(ParamFilter::PARAM_UNCHECKED, array())
);
Chapter 4: Libraries 39
$this->getActionParams = array(
’delete’ => array(
’id’ => array(ParamFilter::PARAM_OBJECT, ’users’),
’code’ => ParamFilter::PARAM_INT,
’name’ => array(ParamFilter::PARAM_STRING, 64, ’^[a-zA-Z]+$’)
)
);
4.1.7 Session
Since HTTP is a completely stateless protocol, session information must be held somewhere.
CodEx sessions are based on classic PHP sessions and cookies.
• A validator cookie is stored in the client’s browser. It has a random value which is also
stored in the session. Each time the session is re-open, the value of the cookie is compared
with the value stored in the session. Furthermore, the value of this validator changes every
time the user performs a POST request. If the validator does not match, the session is
destroyed.
This cookie may seem redundant, but an attacker could easily forget to steal it along with
the ID cookie.
• The IP address of the client is also stored in the session and verified each time the session
is re-open. However, since we live in an age of NATs and dynamic IPs, this precaution is
not as strong as it could be. If the address does not match, the session is destroyed.
• Session storage has also expiration time limit. If the user does not perform any action
within this time limit, the session is destroyed.
Session verification failure is considered to be a security incident and so it is written into the
security log.
The session also has a versioning system. The current version number is specified directly in
the code of the Session class. This number is also copied into the session when it is created. If
the version does not match version stored in the session, the session is destroyed. This is useful
for complex upgrades which require logging out all active CodEx users.
The default namespace and the security namespace are reserved for internal use. w
Application parameters that are not meant to be changed by the deployer or CodEx admin-
istrator are held in the Constants class. The purpose of this aggregation is to simplify code
tweaking by keeping all important parameters in one place.
4.1.8.3 Translations
CodEx is a multilingual application. Therefore, it must have a concept for text translations.
The default language is English and we have also completed a Czech translation.
The translation API is provided by a Zend_Translate object which loads the message catalog
from CSV files. All string literals in the application are written as arguments of the global
function tr(). (Except for a few spots where this was not possible). We use a global function
since its calling syntax is short and it can be used almost anywhere.
The language of the application is set with the configuration option application.language.
The available values are ‘english’ and ‘czech’. If the value is empty or the configuration is
missing, the default language (English) is used. This setting is global and cannot be overridden
on a per-user basis, since the specifications of exercises and other data in the database are always
in a single language, anyway.
The translations of messages from a PHP source file reside in a file named ‘czech.csv’ (or
possibly ‘<language>.csv’ if there are more translations) in the same directory. The translations
of all messages need not be present, if the messages are already translated elsewhere. Thus, the
translations are spread throughout the source tree and generally located fairly close to the place
where they are used.
The script deploy/lang.php, usually run through the makefile, collects the messages from
all csv files and collects them into a single message catalog for each language in a file named
‘src/lang/<language>.csv’. This file is then processed by the translation engine. Thus, if you
change any translation, you should run ‘make’ to re-build the message catalog(s).
There are also simple tools available for helping with writing and managing translations in
the tools directory. ‘xl <file1.php> [<file2.php> ...]’ extract messages from the specified
source files and appends new messages to the ‘czech.csv’ file in the current directory, ‘xlall’ is
a shorthand for ‘xl *.php’. They both shorthands for ‘xlang’, which is the general tool having
several options to control its behavior.
Chapter 4: Libraries 42
Finally, ‘xspell’ runs a spell-check on the message catalog (that must be built first with
lang.php) using the PHP pspell extension and outputs a list of words that are not in the
dictionary (and not in one of the white-lists) and also words that have been blacklisted. (The
word lists are located in the directory ‘tools/wordlist’.
4.1.8.4 HtmlHelper
HtmlHelper is static class that aggregates methods for rendering XHTML code fragments. It
is meant to be used in templates as well as in other core, where XHTML fragments must be
created (i.e. forms).
Main functions that HtmlHelper provides are:
• Creating URLs for pages, CSS files, pictures etc.
• Formatting UNIX timestamps into strings, points, difficulty levels and other specific at-
tributes.
• Creating hyperlinks and action buttons (trivial forms with one button).
• Creating vertical-oriented texts. Texts are created as <img> tags with reference to general
‘vertical_text.php’ script that renders texts as images.
4.2 CFI
This section describes the Class-based Filesystem Interface, or CFI for short. The CFI is a
file-system-like abstraction designed to allow exposing remote-file access capability to CodEx
users in an elegant, secure and efficient manner. It is primarily employed by the File Manager
component for primary storage, archiving and extracting files. In the more narrow sense CFI
refers just to the set of ICFI xxx interfaces and in the broader sense also to the virtual file-system
drivers and associated classes.
or rolled-back with rolllback. It is also permitted to start in read-only mode and then begin a
transaction. However, no object obtained before starting the transaction may be used afterwards.
In the typical case of versioning, the begin operation typically creates a temporary copy of
the previous file-system version and commit inserts the temporary copy as a new version.
with the new rile. A rename or move operation shall fail if a file or directory with the destination
name exists.
Also, as code using the CFI is likely to use ’/’ as a path-component separator (keep in mind
that CFI does not deal with paths), it is not recommended to allow ’/’ in names.
Implementations are free to define any additional restrictions on allowed operations they see
fit. It is possible, for example, to define quotas, restrictions on filenames or levels of directory
nesting. It is possible to forbid creating directories or even make the file system read-only. The
file system has a chance to give a very rough hint to its caller about which operations are allowed
and which are not through the method CFI_Filesystem::getFlags. This method, defined by
the implementation returns a combination of flags such as CAN_MODIFY (whether the file system
is writable at all), CAN_CREATE_FILES etc.
from outside (through an error in other CodEx module, for example) there’s no way the user
could access any files outside of the virtual file system.
FSFS currently does not impose any additional restrictions (quotas, directory nesting level
etc.)
the remaining bytes, then read(n /2) etc. When ’short read’ is allowed, the number of read
operations will be logn times less.
This optimization is not cricial in CodEx, as read-ahead is acceptable.
based on the solution of the Great Wall Parking Problem from IOI 2000, Beijing. See comments
in the source code for details on the problem and algorithm.
A special case is the so called virtual columns (class VirtualColumn): columns somewhat
related to a table but which are, in fact stored in another table (e.g., the name of an owner
of a group). Virtual columns can be used for better performance, but only when it is really
needed, because they can cause an inconsistency: their values are not updated when the value
of a foreign key changes.
Instances of table gateways are created by the Database class. They are constructed upon
request for the first time and then shared for performance reasons.
Data retrieved from the database are cached in the user’s session to reduce the database load.
This cache is not synchronized between users, co inconsistencies can occur for a short time.
Rows read from a table are returned as an associative array or as entity objects (gateways
work as factories for entity objects, see Section 4.3.4 [Entity Objects], page 49).
Gateways are defined in ‘models/database/gateways.php’.
The garbage collector also checks that all submits that might reference an older version of
an exercise were evaluated. If not, it does not run and informs the administrator.
4.4 Mailing
4.4.1 Generic Mailer Class
4.4.1.1 Email
The Email class is a generic mailing class used by CodEx (indirectly through CodEx_Mail)
to send e-mail messages. It is defined in the file lib/email/email.php, which also contains
the helper class Email_Encode and two transfer classes Email_Funmail and Email_Dump. An
instance of Email represents one message that can be composed part-by-part and then sent.
Email is a fairly standard (although somewhat simplified) mail transfer class. It supports a
plain-text message body and an arbitrary number of attachments. Both the body and address
fields can contain international characters, the default encoding is set to UTF-8.
The class sports a classical interface for adding various address fields (To, Cc, Bcc, Reply-To).
An alternate transfer class can be selected, the default being Email_Funmail. Some advanced
functionality is not supported, however, e.g. multiple sender addresses, HTML message bodies
and related functionality (inlined images etc.).
4.4.1.2 Email_Encode
This is a helper class used internally by mail-transfer classes to encode messages to the Internet
Message Format as specified by RFC 2822, 2045, 2046 and 2047.
Chapter 4: Libraries 50
4.4.1.3 Email_Funmail
This is the default mail-transfer class for Email messages. It encodes the message using Email_
Encode and sends it using the built-in PHP function mail(). This function, in turn, usually
runs sendmail to transfer the message to a mail server.
4.4.1.4 Email_Dump
A ’fake’ transfer class. It does not send the message, instead it converts the message to a textual
(human-readable) form and appends it to a file. This is very useful for debugging.
5 Database Description
• public - A flag determining whether the group is public. Public groups are visible for all
users and any user may join the group. Private (non-public) groups are strictly managed
by the group owner and they are not visible for non-members.
• discreet - A flag indicating whether members may see results of other members. In a
discrete group each member can only see his own results.
• pointLimit - Minimum amount of points a member needs to satisfy the group demands
(i.e. how many points a student needs to obtain credit). If the point limit is zero, the group
will not display nor check this limit.
• comment - Short motivation text introducing the exercise. This text is visible for all users.
• note - Instructions, hints and other important information for group owners that are cre-
ating a task from this exercise.
• taskComment - Default information and hints for users that solve this exercise. When a task
is created, this field is used as the default value for tasks.comment. However, the group
owner (who is creating the task) may redefine it.
• textId - Foreign key referring to the texts table which contains an XHTML specification
of the exercise. There can be more than one version of the specification and the textId
field points to the current (head) version.
• author - Foreign key to the users table, ID of the author of the exercise. The author has
administrative rights to the exercise. If the author is deleted, the administrator (the user
with id == 1) will take over his exercises.
• created - UNIX timestamp of the instant when the exercise was created.
• changed - UNIX timestamp of the instant when the exercise was last modified. time.
• keywords - List of keywords related to the exercise. Keywords are separated with commas so
they look like a standard SQL set. Keywords can contain spaces (they are in fact phrases).
• difficulty - Difficulty level. This field can contain an integer value from 0 to 10. Value 10
stands for an extremely difficult exercise, while 1 stands for a trivial one. Zero value means
that the difficulty of this exercise is not specified.
• public - A flag that indicates whether this exercise is visible for other users (with proper
rights) or only to the author (and administrator).
• locked - A flag that indicates whether this exercise is locked. Locked exercises cannot
be assigned as tasks nor submitted. Exercises that are not finished, broken or are being
modified should be locked.
• extensions - Set of extensions (programming languages) that are allowed for this exercises.
Tasks may restrict this set further.
• acceptThreshold - Default value for tasks.acceptThreshold. See Section 5.7 [Table
tasks], page 55
• version - Version of related data files stored in the file system. This number grows incre-
mentally each time the data are changed.
• tasksCount - Total number of tasks that has been assigned from this exercise. This field is
maintained by triggers on table tasks and should not be modified by application directly.
• submitsCount - Total number of submits (with non-null points) for this exercise. This
field is maintained by triggers on table exercise_ratings and should not be modified by
application directly.
• submitsPoints - Total sum of best points from all users who solved this exercirse. The
value is kept in permille and if divided by submitsUsers, it gives avarage success rate. This
field is maintained by triggers on table exercise_ratings and should not be modified by
application directly.
• submitsUsers - Number of distinct users who have submitted at least one submit (and the
submit has been evaluated) for this exercise. This field is maintained by triggers on table
exercise_ratings and should not be modified by application directly.
• ratings - Total sum of all ratings assigned in exercise_ratings to current exercise. Value
of ratings divided by ratingsCount gives avarage ratings. This field is maintained by
triggers on table exercise_ratings and should not be modified by application directly.
• ratingsCount - Number of non-null ratings from exercise_ratings for current exercise.
This field is maintained by triggers on table exercise_ratings and should not be modified
by application directly.
Chapter 5: Database Description 55
• oldRatings - Total sum of all rating values that have been deleted from exercise_ratings
(therefore are no longer summarized in ratings field). The ratings should be computed as
(ratings + oldRatings) / (ratingsCount + oldRatingsCount). This field is maintained
by delete trigger on table exercise_ratings and should not be modified by application
directly except for complete reset.
• oldRatingsCount - Number of rating values added to oldRatings. This field is maintained
by delete trigger on table exercise_ratings and should not be modified by application
directly except for complete reset.
• submits - Limit for submits. User may not submit more solutions of this task than specified
in this field.
• extensions - List of allowed extensions (programming languages). The user may submit
his/her solutions only in languages on this list.
• obligatory - How many points are obligatory for this task. The user must obtain at least
the number of points specified here in order to satisfy the group requirements.
• acceptThreshold - Minimum permille that any solution must obtain from evaluating sys-
tem. If the solution has not sufficient permille (submits.points, results from this solution
are completely ignored (user does not get any points from it). This precaution can be used
in cases when the user could obtain some points just by guessing correct answers. This
value is taken by default from exercises.acceptThreshold).
• submitted - UNIX timestamp of the instant when this solution was submitted.
• enqueued - UNIX timestamp of the instant when this submit was moved into the eval
queue. If it is null, the submit was not moved into the queue (this may be a signal that
something went wrong). This field is also updated when the submit is re-evaluated.
• evaluated - UNIX timestamp when this submit was taken for evaluation or when the
evaluation finished. The meaning depends on the points field. When points == null, the
submit has not been evaluated yet and this timestamp holds the time when the evaluation
started. Otherwise this field represents the time when the evaluation ended. Also, if this
field is null, the submit is still in the queue waiting for evaluation.
• extension - Extension of the submitted solution. Extension uniquely identifies the pro-
gramming language used.
• comment - User’s internal note.
• points - Points assigned by the evaluating system. If null, the solution was not evaluated
yet. The points representing relative correctness of the solution and are stored in permille.
A value of -1 signifies a compilation error.
• bonusPoints - Additional points assigned by group owner for an excellent (or terrible)
implementation, out-of-the-box solution, etc. Bonus points are represented as absolute
points (not permille) and they can also be negative (negative bonus means a penalty).
5.14 Views
A view is a query stored in the database, which can be used the same way as an ordinary table
(only for reading). The CodEx libraries do not distinguish between tables and views, so, for
example, the Select class supports automatic joining with views.
5.16 Triggers
Triggers maintain data integrity for redundant database fields. These fields were inserted into
the structure in order to reduce time required by complicated join operations (mostly when
result points are retrieved).
• users
• before delete – delete all exercise_ratings of deleted user (this way we ensure that
delete triggers are executed properly)
• groups
• before delete – delete all tasks from deleted group (this way we ensure that delete
triggers are executed properly)
Chapter 6: Data in Files 63
6 Data in Files
should be a text file with UNIX line endings, but some ex-
ercises can use binary files. If the exercise specifies multiple
input files, ‘<ID>.in’ is a directory instead of a file.
‘ID.out’ Reference output for test named ID. This file can actually
contain any data (not necessarily data for comparison) and
is not mandatory. The output can be validated in any other
way, for example, if there are multiple correct answers.
‘submits’ Data directories of the Submits. If contains a subdirectory for every
submit (named with the ID of the submit) which in turn contains the
following files:
‘source.ext ’
Source code submitted by user. Extension of this
file differs, the actual extension is stored in database
(submits.extension or solutions.extension, see
Chapter 5 [Database Description], page 51).
‘metadata’
This file is only present if the submit has already been eval-
uated. It contains a description of the submit for the back-
end and the back-end appends here the results of the tests.
See Section 6.3 [Metadata], page 66.
‘eval.log’
This file is only present if the submit has already been eval-
uated. It contains a log of messages produced by the back-
end during evaluation. (Such as compiler error, a summary
of test results, etc.) The front-end does not process this file
in any way, it just displays it to the user.
‘solutions’
Data directories of the Solutions. The structure is identical to that of
the directory containing the Submits.
‘texts’ Data directories of the Texts. It contains a subdirectory for every exer-
cise text (named with the ID of the text). These directories contain the
attached files for the exercise specification text. They are directly ex-
posed by the web server, so the user’s web browser can access them. The
author of the exercise can put any files (subject to certain limitations)
and reference them from the text of the exercise specification.
All these directories are managed by the Storage class and the associated garbage-
collector script (see Section 4.3.3 [File Storage], page 48) and their contents are
managed through CFI (see Section 4.2 [CFI], page 42) using the CFI_FS_Filesystem
driver.
The CFI driver imposes several limitations on the contents of these directories
in order to prevent possible filesystem-based attacks and other possible problems.
Namely, the name of a directory entry is not allowed to begin with a period (‘.’)
and it can only contain alphanumeric characters, periods, hyphens and underscores.
There can be no symbolic links and also no filenames in the same CFI tree link to
a single file or a file outside of the storage.
On the other hand, the exercise data is versioned. If a file is unchanged between
two versions of the data, it is hardlinked (in order to save space and processing
time). Thus, entries with the same name in the different versions can link to a
Chapter 6: Data in Files 65
single physical file. Thus, you should never modify the contents of any file directly,
unless you are absolutely sure what you are doing.
‘temp’ The CodEx temporary directory. New files or directories are typically created here
and then moved to the Storage or to the Queue. The system-wide temporary di-
rectory ‘/tmp’ is not used, because it could reside on a different file system and
CodEx needs to move directories between the temporary directory and the storage
atomically.
Parameters TIME_LIMIT, MEM_LIMIT and POINTS_PER_TEST may be redefined for every test
and extension. If a limit is specific for a test, the parameter name is prefixed by ‘TEST_<id>_’,
where ‘<id>’ is an identifier of the test. If a limit is specific for an extension, the parame-
ter name is prefixed by ‘EXT_<ext>_’, where ‘<ext>’ is the extension. Extension prefix must
come before test prefix. For example a time limit for test ‘3’ and extension ‘.pas’ will be
‘EXT_pas_TEST_3_TIME_LIMIT’.
If more parameters apply to some combination of a test and an extension, they are considered
in this order (first match is used):
1. Limit specific for this test and this extension.
2. Limit specific for this test for all extensions.
3. Default limit for this extension.
4. Default limit for all extensions.
‘codex_type’
Name of table in the CodEx database, either ‘submits’ or ‘solutions’.
‘codex_id’
ID of a submit or solution.
‘source’ Name of the submitted source file (inlcuding extension, but without path).
‘exec’ Full path to a script that Qman executes when evaluation is finished.
For every test executed, Eval adds a compound ‘test’ attribute with these nested attributes:
‘id’ Test ID. Non-empty string of alphanumeric characters.
‘points’ The number of assigned points (in permille). A non-negative integer.
‘status’ Status code. Two upper-case characters. The possible values and their meanings
are:
‘OK’ test passed
‘CE’ compile error
‘FO’ forbidden operation
‘RE’ runtime error (exitcode is set)
‘SG’ killed by signal (exitsig is set)
‘TO’ time limit exceeded
‘WA’ wrong answer
‘PA’ partial answer
‘PE’ protocol error (for interactive tasks)
‘XX’ internal error
‘message’ Human-readable status message. (In English)
‘time’ [optional] Duration of execution in seconds. Fractional number represented in deci-
mal or scientific notation, as specified by the %g format specifier in C.
‘mem’ [optional] Memory consumed by the tested program in bytes. Non-negative integer.
‘exitcode’
[optional] Exit code of program. Non-negative integer.
‘exitsig’ [optional] Signal the program was killed with. Non-negative integer.
• ‘testdata’ – Contains exact copy of exercise storage directory. That includes test data,
results for comparison and configuration file.
• ‘attachments’ – Directory with attachment files for exercise specification. Each version of
specification has its files in separate subdirectory which has the same name as the value of
id attribute of corresponding text element in XML file.
• ‘solutions’ – Directory with all exported solutions for the exercise. Each solution has its
own subdirectory which has the same name as the value of id attribute of corresponding
solution element in XML file. Each solution usually contains source code file, evaluation
log and metadata file.
Example of package file structure:
[ZIP file]
|--[testdata]
| |--1.in
| |--1.out
| |--2.in
| |--2.out
| ’--config
|--[attachments]
| |--[0]
| | ’--schema.png
| ’--[1]
| |--schema.png
| ’--sample.pas
|--[solutions]
| |--[0]
| | |--source.pas
| | |--metadata
| | ’--eval.log
| ’--[1]
| |--source.cpp
| |--metadata
| ’--eval.log
’--content.xml
Note that some attachment files may have been hardlinked (when specification changes,
attachment files are duplicated by hardlinks), but when loaded to package, this information is
lost. Therefore, when package is imported, every attachment is copied into new separate file
(even if they contain the same data).
<note></note>
<taskComment></taskComment>
<created></created>
<changed></changed>
<keywords>
<item></item>
...
</keywords>
<difficulty></difficulty>
<public></public>
<extensions>
<item></item>
...
</extensions>
<acceptThreshold></acceptThreshold>
<ratings></ratings>
<ratingsCount></ratingsCount>
</data>
<texts>
<text id="" [active="1"]>
<created></created>
<changed></changed>
<content></content>
</text>
</texts>
<solutions>
<solution id="">
<submitted></submitted>
<enqueued></enqueued>
<evaluated></evaluated>
<extension></extension>
<comment></comment>
<points></points>
<public></public>
</solution>
</solutions>
</exercise>
The XML file contains three main sections ‘data’, ‘texts’, and ‘solutions’. The ‘data’
section stores almost all data of the exercise object from the database, except for a few fields.
The ‘textId’ field is filed automatically, when active text object is inserted (and its database ID
is known at last). The ‘author’ is set to current user (i.e. the user who performs the import). The
‘locked’ field is missing since it is always set to true when exercise is imported. The ‘version’
is set to 1, and finally all statistic values (except for ‘oldRatings’ and ‘oldRatingsCount’)
are implicitly 0. Otherwise every element directly corresponds to a field with the same name,
except for ‘ratings’ that corresponds to ‘oldRatings’ and ‘ratingsCount’ that corresponds to
‘oldRatingsCount’. When the exercise is exported, the rating values are stored as ratings plus
oldRatings.
The ‘texts’ section contains all specification versions. The ‘id’ attribute is generated se-
quentially (from 0) and it does not have any relation to original database ID of the text object.
The ‘active’ attribute has implied value of 1 and exactly one text element has this attribute
Chapter 6: Data in Files 70
set. It marks the text object that is selected by ‘textId’ reference of the exercise object. All
subelements correspond directly to their database counterparts.
The ‘solutions’ section contains public solutions and solutions that belong to the user who
performed the export. The ‘id’ attribute is assigned the same way as it was for text objects.
Also all subelements correspond to database columns with the same name.
7 Evaluation
The CodEx web front-end accepts source code to be evaluated from the users. The evaluation
itself is performed asynchronously by the CodEx back-end, which consists of the Queue manager
(Qman) and multiple workers. The Queue manager runs as a daemon, picks up jobs from
the queue and assigns them to workers, which evaluate the jobs as described in Section 7.2
[Evaluation Process], page 72.
The communication between the front-end and the back-end follows the protocol described in
Section 7.1 [Protocol], page 71. In the front-end this protocol is implemented by the EvalQueue
class and by the script ‘hook.php’.
• Text judge, which splits both outputs to tokens using whitespace sequences as delimiters
and compares the tokens
• Float judge, that compares floating-points numbers with a defined error tollerance
• Shuffle judge, that ignores the order of tokens on a line, the order of lines in the output
file or both
If the judge declared the output correct, the test scores the number of points defined in the
exercise configuration. Otherwise no points are awarded.
7.4 Security
The students and other users submitting their programs are NOT trusted, i.e. their programs
are considered potentially harmful to the running system. The evaluation system internally
uses a ptrace-type sandbox to prevent the tested program from harming other processes or the
system.
The sandbox catches every system call the tested program makes and either blocks it (killing
the program in most cases) or allows it. The main blocked actions are file manipulation outside
the permitted (safe) directories, fork(), threading, device manipulation, manipulation with
permissions and networking. The sandbox program also limits the the memory consumption
and the time used either as CPU time or as a real-world (wall) time.
For details please refer to the mo-eval manual and to the box program source, which is well
written and understandable.
Another good (although optional) separation is trough running the sandbox as a separate
non-privileged user with disk quota. This is very easy to set up. For that it is necessary to set
the box program to SUID to the unprivileged user and to change the permissions and ownership
of the ‘box/’ directory in the respective copy of the evaluator.
Chapter 7: Evaluation 74
It is recommended to set a reasonable disk quota for every testing user (as the sandbox
program does not limit the amount of data written) and to use different users for different
instances of the evaluator.
These precautions should be enough to prevent the tested program from harming the system,
but in a system with more strict security more separation layers should be used. These include
running the evaluator on different or virtual machines or in a chroot jail. These methods are
briefly described in Security section in Section 8.1 [Queue Manager Overview], page 75.
Chapter 8: Queue Manager (qman) 75
8.1 Overview
8.1.1 Introduction
For various reasons it is not desirable to call the evaluator of the submitted programs directly.
Direct parallel execution of dozens of submitted programs (think about the last half hour be-
fore the deadline) would overload the evaluation machine. Many parallel executions lead to
many context switches (and cache misses) which, apart from being ineffective, also disrupt time
measurements.
To evaluate the submits sequentially we had to implement a system fetching the submits from
a queue and distributing these to a single worker or multiple workers. We decided to make this
an independent program useful for any general scenario where many similar jobs are submitted
for some sort of evaluation and then the results are handed to some other system (possibly into
another queue) or just stored for later processing.
The jobs should be parametrized (in the case of CodEx this is for example the exercise and
exercise version) and should have some priority based on their type and time of submission. The
workers should be independent and not considered to be reliable - a worker crashing on some job
should not disturb the processing of other jobs. To improve performance, the workers should be
able to run remotely on several machines at once.
All these conditions, along with high customizability, are addressed in this implementation.
The state of the manager can be viewed in a global log, per-worker logs and per-job logs.
We decided to call this utility qman (queue manager).
The program in implemented in plain C for performance and code transparency reasons. The
program uses many of the Linux/UNIX system features and therefore is being developed only
for that platform.
− A hook script called for every job inserted into the output queue.
− A pool of worker processes evaluating individual jobs.
This design was chosen because it satisfied all the necessary conditions:
− It is very simple and therefore can be implemented to be robust, stable and effective.
− The front-end, the queue manager and the evaluator are separate modules and can be used
independently.
− The manager and the worker processes can run on different machines sharing the data over
NFS or they can run in a virtual environment.
− The recovery of a crashed qman consists of just moving all the submits from the working
directory back to the input queue.
− It is very easy to examine the current state of all the queues and to estimate the workload.
This simplifies all administrator tasks and any performance tuning.
The details of the interface and of the storage directories are described in the following
sections.
8.1.2.1 Recovery
After the program crashed, all the workers are restarted by their respective init command, which
should clean up any data left from previous execution and quick-check the worker consistency.
It may even completely rewrite all worker data in the worker directory.
The jobs are either in the input queue (and therefore untouched), in the working directory
and their copy being processed by the worker, or finished either in the output directory or in
the error directory. As the job in the worker queue may only contain additional metadata and
must not change any other previously present files, it is sufficient to move the job directory from
working directory back to the input queue directory.
When a job is processed again for any reason its logfile is appended to or overwritten, de-
pending on the configuration.
case the job is forgotten with a warning), or that the permissions on some of the directories
(especially the input directory) are wrong and in that case the qman dies.
The qman does not analyze the actual reason for the failure. The job is always blamed
and removed from processing. There is no definite way to tell what caused the failure of the
processing and the job should be examined by the administrator. An automatic rescheduling
the job would help only in a very limited number of cases, as at most every failure is caused
either by deformed job or by misconfigured worker.
The ping command may be sent to the worker periodically while idle to keep the connection
alive and to check that the worker is still ready.
8.1.5 Security
A basic stability is attained through timeouts for all worker shell commands. This prevents
misconfigured tasks from blocking the system indefinitely.
The qman system in its basic configuration is not anyhow protected from any damage the
worker processes may cause to it and therefore other measures should be applied depending on
the scenario. Few simple possibilities with complexity beyond the basic distribution package of
CodEx and qman (some of them require root access, configuration of another software and/or
knowledge of the system structure):
A simple yet useful separation measure is to make the shell commands SUID (effective user
change upon execution) to a less privileged user. These users may be different for every worker,
separating the workers.
Even better layer of separation may be easily reached by locking the worker shell into a
chroot jail created for this purpose. This separates the process not only by permissions, but
also by filesystem.
Even stronger solution is to use a remote shell (ie. ssh) to start the actual worker shell on
a different machine - either virtually (by the use of qemu, xen or other virtualization software)
or physically. This kind of separation is practically impenetrable, but may be harder to set up
and may cause small speed reduction.
tories) to prevent multiple qman processes accessing the storages at once. This could break any
job processing and eve lead to data corruption.
To inform the user and the administrator about the history and the progress of the processing,
two facilities are implemented: log files and status files.
Log files are of three kinds - global log file for global information, per-worker log files for
information about one particular worker and its shell, and per-job configuration files recording
the whole processing of a job along with any errors.
All the log files are described in section Log Files in Section 8.2 [Queue Manager Interface],
page 80.
Status files are more user oriented and provide overview of the current state of the relevant
parts of a qman. The status files can be generated in more formats (currently only plain text is
supported, but HTML is in preparation).
The status files are re-generated periodically and also with every relevant state change (but
not too often). The status files are re-generated atomically (by a file move), so their state is
always complete.
The status files include information about every worker (status, job), about every job being
processed, about amount of jobs waiting in the input queue and two short lists of the latest
processed and failed jobs.
Details of the status files are described in the section Status files in Section 8.2 [Queue
Manager Interface], page 80.
8.2 Interface
This section describes the interaction of qman with other applications and with the user.
8.2.1 Configuration
All the configuration can be changed in a configuration file (usually qman.conf) or by command-
line arguments. Most of the options change behavior of qman internals and are preset to sensible
defaults. The semantics of the internal options are described in the config file and in the
Section 8.3 [Queue Manager Implementation], page 86.
Lists support several operations besides adding a new node. You just have to write a colon
immediately after the attribute name, followed by the name of the operation. The following
operations are supported:
List:clear $ removes all nodes
List:append { attr1=value1; ... } $ adds a new node at the end
List:prepend { attr1=value1; ... } $ adds a new node at the beginning
List:remove { attr1=search1 } $ find a node and delete it
List:edit { attr1=search1 } { attr1=value1; ... }
$ find a node and edit it
List:after { attr1=search1 } { ... } $ insert a node after a found node
List:before { attr1=search1 } { ... } $ insert a node before a found node
List:copy { attr1=search1 } { ... } $ duplicate a node and edit the copy
You can specify several attributes in the search condition and the nodes are tested for equality
in all these attributes. In the editing commands, you can either open a second block with
overridden attributes, or specify the new values using the shorter one-line syntax.
The commands :clear, :append, and :prepend are also supported by var-length arrays.
The command :clear can also be used on string values. The following operations can be used
on bitmaps: :set, :remove, :clear, and :all.
jobs.dir-in ’queue/in’
jobs.dir-out ’queue/out’
jobs.dir-error ’queue/error’
jobs.dir-work ’queue/working’
Directories for the individual storages, see the section Submit Storage Design in
Section 8.1 [Queue Manager Overview], page 75.
jobs.metafile ’metadata’
Name of metafile for each job.
jobs.logfile ’job.log’
Name of logfile for each job (” for none).
jobs.no-metafile 2
What to do when there is no job metafile? (0-nothing, 1-warn, 2-error)
jobs.logfile-overwrite 0
Overwrite job logfile when already present (ie. from aborted processing).
jobs.error-hook ’/bin/true’
Command called for failed jobs. It is given only single parameter - full path to copy
of the failed job in dir-out. Use to report failed jobs to user.
inbox.minsize 42
inbox.maxsize 100000
Minimal and maximal size of the inbox priority queue (at least 4).
inbox.check-int-min 300
inbox.check-int-max 60000
Minimal and maximal interval between re-reading the in-dir (msec).
workers.path ’workers’
Directory with all worker subdirectories.
workers.logfile ’worker.log’
Name of logfile of each worker.
workers.ping-timeout 1000
workers.ping-phrase ’PING42PING’
workers.init-timeout 60000
workers.init-phrase ’INIT42INIT’
workers.work-timeout 60000
workers.work-phrase ’WORK42WORK’
Timeouts and phrases for detecting the ending of individual worker phases.
workers.read-buf 2048
workers.write-buf 2048
Buffer lengths for each worker.
workers.worker
List of workers to be used.
workers.worker.name ’eval1’
Name of the worker directory in workers.path.
workers.worker.data-path ’.’
Path to common data storage, from workers view (ie. over NFS). Given to the
worker as parameter.
Chapter 8: Queue Manager (qman) 84
workers.worker.shell-cmd ’/bin/sh’
Shell executed on worker start and receiving all the commands for the worker. Must
be a POSIX shell (ie. sh, bash via ssh, . . . ).
workers.worker.init-cmd ’/bin/true’
workers.worker.work-cmd ’/bin/true’
Commands issued to init the worker and to start every work.
status.file-plain ’qman.status.txt’
status.file-html ’qman.status.html’
File names for different status formats.
status.update-int-min 300
status.update-int-max 60000
Minimal and maximal interval between re-writing the status files.
status.show-out 15
Number of last successfully precessed jobs to show in status.
status.show-error 5
Number of last failed jobs to show in status.
8.2.2 Metadata
Metadata files store information and parameters of incoming jobs and well-formatted results
ofter their processing. The metadata file has a very simple text format consisting of these items:
1. One attribute of type name:value, all the values are arbitrary single-line texts.
2. Single-line comment.
3. Empty line.
4. Named subtree (nested attribute) containing any number of the above items and named
subtrees.
Every attribute is defined on a single line, therefore neither the names nor the values may
contain newlines (’\n’) or NULL characters (’\0’, ASCII code 0).
<indent> = (<sp>|<tab>)*
<name> = (A-Z | a-z | 0-9 | "-" | "_" | "." )+
<value> = <any-character-except-newline-and-NULL>*
Chapter 8: Queue Manager (qman) 85
It is strongly recommended to represent the <value> in UTF-8, however, this is not necessary
and any encoding may be used provided that all the applications using the metadata files use
the same.
Any unknown attributes in the metafile are ignored as these may be used by other compo-
nents. Collisions in naming new attributes should be avoided by using appropriate prefixes.
8.3 Implementation
qman is a program written in plain C (version C99) and uses some specifics of the gcc compiler,
although these are not necessary.
The program is written to use specific functions from the Linux operating system and its
portability to other systems (even POSIX systems) is therefore very limited.
8.3.2 Modules
The individual files cover their respective areas. The major structures, functions and types are
described here.
For a detailed description of the individual functions please refer to the sources. Reading the
source of a short function should be more useful than reading a description actually longer than
the code itself. If in any doubt, please contact the authors.
Some simple functions internal to the modules are omitted in the module descriptions.
8.3.2.1 job
job.c, job.h
This module defines the struct job representing a single job in all its states and provides
functions assigning a job to a worker and a function fetching the job from the worker and calling
the output hook command.
The job structure is defined as follows:
typedef struct job {
char *dirname; /* name of the job directory */
int state; /* JOBSTATE_xxx, state of the job */
struct metanode *meta; /* the metadata read from the metafile */
struct worker *worker; /* the assigned worker, if any */
FILE *log; /* an open per-job logfile (or NULL) */
} job;
The meaning of all the attributes is straightforward. The attributes meta, worker and log
may be null, but both meta and worker are defined in the state JOBSTATE_WORKING.
The dirname and metadata should be allocated by xmalloc as they are xfree’d on job
destruction.
A global hash-table (from libucw) is declared to store all loaded jobs (even those in the input
queue and those remembered by status). This table provides a very fast lookup by the job
directory name.
The job module defines several major functions to work with jobs:
void job_init(void);
Initializes the module (mainly jobs hashtable structure).
void job_to_error(job *j, const char *fmt, ...);
Marks the job as failed (as described in the section Job Flow in Section 8.1 [Queue
Manager Overview], page 75), releases and kills the worker moves the job directory
to the error directory and adds the job to the status error queue.
job* new_job(const char *dirname);
Creates a new job for the given directory, registers it in the job hashtable does NOT
add the job to the inbox heap.
Returns the new job or NULL if a job with the same name is already present present
or on error.
int read_job_metadata(job *j,int filter);
Reads the job metadata. The job directory must be still in the input queue.
May fail and move job to error, returns 1 on success, 0 otherwise.
void destroy_job(job *j);
Frees loaded job metadata (if any), closes the logfile, removes the job from the job
hash-table and deallocates the job structure.
Chapter 8: Queue Manager (qman) 88
Two important functions are provided for the interaction with the assigned worker:
int pickup_job(void);
Picks the job with highest priority from the inbox heap and assigns it to a free
worker. Constructs and writes the worker work command (the worker command
may be customized in the sources).
Return 1 if one job was picked up, 0 if none (no jobs in the inbox heap, no no free
workers or some job error).
int job_finish(job *j);
This is called after the worker reads the work passphrase. Detaches the job from
worker, sends the worker a ping command, moves the job to the out directory and
runs the hook output command on the job.
Returns 0 on success, 1 on any error (job or hook error).
8.3.2.2 worker
worker.c, worker.h
This module defines the struct worker representing a single worker in all its states and
provides functions manipulating and controlling the worker.
The worker structure is defined as follows:
typedef struct worker {
cnode n; /* libucw list element */
char *name; /* worker name */
int state; /* current state, WORKERSTATE_xxx */
struct main_file fin, fout; /* file objects, out goes TO the process */
int inpipe[2],outpipe[2]; /* pipes FROM and TO the worker */
struct main_process proc; /* the worker process */
struct main_timer timeout; /* timeout object for all the actions */
FILE *log; /* worker logfile */
struct job *job; /* assigned job (if any) */
char *write_buf; /* buffer for writing commands */
char *read_buf; /* buffer for reading response */
char *data_dir; /* [*] global data path (relative from the worker) */
char *shell_cmd; /* [*] shell command (bash, ssh, ...) */
char *init_cmd; /* [*] init command - initial cleanup */
char *run_cmd; /* [*] work command - process a job */
} worker;
Note, that fields marked with [*] are NULL after worker_new() and may be set to appro-
priate values before worker start. If unset, start_worker() fills them with defaults (getcwd(),
/bin/bash, . . . ).
The global worker list and worker counters are declared in this module.
The module defines these major functions to manipulate the workers:
void init_workers(void);
Initialize the module and the worker list.
void worker_setstate(worker *w, int state);
Set the state of the worker. This is provided to adjust all the worker counters (busy,
ready).
worker *worker_new(const char *worker_name);
Creates a worker and initializes all its values. Opens the worker logfile, opens the
pipes and registers the file descriptors in the libucw mainloop module. Adds the
worker to the global worker list.
Chapter 8: Queue Manager (qman) 89
8.3.2.3 inbox
inbox.c, inbox.h
This module contains the global inbox heap used as a priority queue and provides functions
for manipulating it and for re-reading the input queue directory. This module also contains the
timer responsible for the periodic re-reading of the input directory (fallback in case inotify
fails for some reason, ie. operation over NFS).
This module also provides an interface to the inotify system, that provides an open file
with a read event every time some directory is moved into the input queue directory.
The inbox heap is a heap in a dynamic-size array from the libucw library.
The major functions defined in this module are the following:
void init_inbox(void);
Initialize the inbox heap and timer.
int inbox_init_inotify(void);
Initialize inotify input directory watching, return 0 on success.
void set_check_inbox(void);
Schedule the inbox re-reading as soon as allowed.
int inboxheap_less(struct job* a, struct job * b);
A function determining the heap order of the jobs, can be redefined for a different
priority measure.
int inboxheap_insert(struct job *j);
Heap insertion with potential heap expansion. Returns 1 on success, 0 on failure
(heap size reached its upper limit).
int reread_inboxdir(void);
Re-read the entire input directory, insert all the unknown jobs, return the amount
of new jobs.
struct job* inboxheap_delmin(void);
Delete and return the job with the highest priority from the inbox heap. Return
NULL in case the heap is empty.
Chapter 8: Queue Manager (qman) 90
8.3.2.4 status
status.c, status.h
The module contains the two job lists (for last successful and failed jobs) and re-generates
the status files (periodically and upon change).
The major functions defined in this module are the following:
void init_status(void);
Init the module and the periodical status timer.
void status_changed(void);
Schedule the status files update as soon as possible.
void status_update(const char *fname, int type);
Atomically update the status file of given type (STATUS_PLAINTEXT or STATUS_
HTML).
void status_add_job_out(job *j);
Add a successful job to status list "last output jobs".
void status_add_job_err(job *j);
Add a failed job to status list "last failed jobs".
8.3.2.5 metadata
metadata.c, metadata.h
The module contains the definition of the metadata tree and routines for loading, printing
and querying them.
Refer to Section 8.2 [Queue Manager Interface], page 80 for the details of metadata structure.
The structure metanode is defined as follows:
typedef struct metanode {
struct cnode m; /* member of a list */
u8 type; /* type of this item, METANODE_xxx */
char *name; /* name of ITEM or TREE */
char *data; /* text of ITEM or COMMENT, (clist*) of TREE */
} metanode;
The major functions defined in this module are the following:
void fprint_metalist(FILE *f, const struct clist* l, int indent, int indshift);
Print all the nodes in the list in the metadata format to the given file. The last two
parameters describe basic indentation and steps for nested levels.
metanode *meta_item_findnext(metanode *list, metanode *from, const char *name);
Find the first METANODE ITEM named name after from (from=NULL for search
from the beginning, name=NULL for any item).
Return NULL on failure (no more such items).
char *meta_item_findnext_data(metanode *list, metanode *from, const char *name,
char *def);
Similar to meta_item_findnext() but return directly the item data pointer (or
def if none found).
metanode *meta_tree_findnext(metanode *list, metanode *from, const char *name);
Find the first METANODE TREE named name after from (from=NULL for search
from the beginning, name=NULL for any item).
Return NULL on failure (no more such items).
The routines for metadata loading are omitted as these are internal and called only from
read_job_metadata() from job.h.
Chapter 8: Queue Manager (qman) 91
8.3.2.6 conf
conf.c, conf-read.h, conf-read.c, generated conf.h
The module contains the global parameters of all the modules and routines to load them
from command line an/or from a config file.
The header file conf.h is automatically generated from conf.c.
All the global variables and their configurations are described in the section List of Parameters
in Section 8.2 [Queue Manager Interface], page 80.
The only relevant function void init_conf(int argc, char *argv[]); reads the parame-
ters from a command line and a config file and initializes the config variables. It also sets up
the list of simple struct worker_conf of workers to be initialized.
8.3.2.7 log
flog.c, flog.h
This module slightly extends the libucw log facility to include logging to any file.
The main provided function is void flog(FILE *f, unsigned int cat, const char *fmt,
...); that logs a formatted message into a (FILE *) with severity and date and time stamp.
See libucw log system for details.
8.3.2.8 qman
qman.c
This module contains the main() function. The function loads the configuration, initializes
all the modules, recovers lost jobs, starts all workers defined in the configuration and enters the
mainloop from libucw.
At this point, all the necessary files, timers, hooks and processes are already configured and
registered in mainloop and the program runs by calling appropriate handlers for all files with
data to be read, processes to be waited for, timers expiring and others.
Appendix A: Glossary 92
Appendix A Glossary
action An operation performed by a page controller, that the page exposes by defining a
public method. For the action foo, this method is named foo Action. It is activated
through an HTTP POST request.
admin A special user account with the database ID 1. The admin is automatically granted
maximum rights to all objects, regardless on the actual values in the rights fields of
his user account. The account is special in that it cannot be modifed or removed.
Any user possessing maximum rights (i.e. any user given the supervisor role) can
do anything that admin can do.
back-end The back-end is responsible for the evaluation of enqueued jobs. It runs asyn-
chronously from the WWW front-end and it consists of Qman and the workers
(MO-Eval etc.).
CFI Class-based Filesystem Interface. An abstraction providing users remote access to
files. Responsible for securing file access and allows versioning.
controller The controller (of a page or component), part of the Model-View-Controller design
pattern. is responsible for responding to user actions and controlling the display of
a page or component.
component
A piece of code that can be inserted into many pages (even several times into the
same page). They are used for frequently repeating page elements such as tables,
forms, menus etc.
config The file named ‘config’ in the exercise directory containing the configuration and
limits of tests. It is usually edited through a form-based interface, but also accessible
directly to the users.
delegation An object bestowing the rights of one user (the granter) upon another user (the
trustee).
driver (CFI)
A virtual-filesystem driver (primarily a class implementing the ICFI_Filesystem
interface). There is a plain filesystem-based driver and archive-based drivers (Tar,
Zip).
entity object
The ultimate abstraction of a database record (or records). In the application,
database is accessed exclusively through these. They are built upon table gateways.
exercise A problem that should be (in the end) solved by the users. An exercise must be first
assigned as a task (to a group) which allows the members of that group to solve it.
An exercise consists of a database record and a directory with configuration and
data. From the point of view of the back-end, it is just a directory.
Eval Short for MO-Eval.
filter (CFI)
A class that provides file-filtering services, mostly used in the file manager. There
are filters available for compression, decompression and newline conversion.
file manager
A component that allows remote access to files through a web-based interface. It is
the primary means for the users to upload test data for exercises and attached files
for exercise specifications.
Appendix A: Glossary 93
front-end The WWW-based user interface written in PHP. Apart for the hook script, it runs
synchronously with the client’s requests.
gateway, table gateway
Abstraction of a database tables. Gateways serve as factories and caches for data-
base entity objects.
granter The user who delegates his rights to another user.
group A group organizes together a set of users (its members) and a set of exercises (the
tasks) they solve.
group membership
A relation describing which users belong to which groups. A user can join a group,
but he cannot leave. He can be added to the group or removed from it by an
operator.
group operator
A user who is managing (operating) a group. More generally, anyone possessing the
rights to a group greater or equal to those defined by the Group Operator role.
job A unit of job for the evaluation back-end. The front-end generates one whenever
it needs a submit or solution evaluated. Physically a job is a directory containing
the source code and a metadata file. It is actually just a copy of the directory of a
submit or solution.
metadata The file named metadata that is used for communication between the front-end and
the various parts of the back-end. These files are generated by the front-end. They
reside in the directories of the submits or solutions (and in the jobs). The parts of
the back-end add the results of the evaluation to the metadata file.
MO-Eval The third-party component of the back-end that handles the evaluation itself. It is
the principal part of the workers.
news, news item
A piece of text created by a user to pass information to other users (the members of
a group, all users). News can be browsed by the other users and they usually have
an expiry date after which they are deleted.
notification
E-mail messages automatically send by CodEx, informing about various events. In
a more narrow sense, these are just the maskable notifications that the user can turn
on or off in his user preferences.
object Short for entity object.
operator Either a group operator or, in general, any user possessing the rights of the roles
Group Operator, Head Operator or higher.
output queue
A directory where Qman (the back-end) puts evaluated jobs. Qman then executes
the front-end’s hook script that picks the evaluated job up from the output queue.
page A unit of the user interface, usually displaying similar information. It is implemented
as a pair of classes/scripts the controller and the template.
Qman A generic application written in C that picks up jobs from a queue and assigns them
to one or several workers which process the jobs one at a time.
queue (evaluation queue, Qman input queue)
A directory where the front-end puts jobs for evaluation. It contains subdirectories
each corresponding to a job. Qman picks these up in lexicographic order and moves
them out of the queue.
Appendix A: Glossary 94
rights In the general sense a permission to do something with an object in CodEx. In the
more narrow sense it is a privilege level, represented as an integer from 0 to 255 (or
as RIGHT NONE through RIGHT ADMIN) that determines the rights the user
has or the rights that are required to perform a certain operation.
role One of the pre-defined templates for setting up the rights of a user. (Common User,
Group Operator, Head Operator, Supervisor).
sandbox A part of MO-Eval that intercepts all system calls of a program being evaluated
and prevents it from performing undesired operations.
service Special entry point that provides access to CodEx services for automated scripts.
Whole chapter Services is dedicated to this topic.
session An object stored on the server that works around the statelessness of the HTTP
protocol. Implemented by the Session class.
solution Created by privileged users (the author of an exercise or a user who wants to assign
it), usually to test the exercise. Similar to a submit, it consists primarily of the
source code that tries to solve an exercise and should be evaluated. A solution
solves an exercise directly, whereas submits solve them indirectly through tasks.
storage
submit Created by common users as an attempt to solve a task. It has a structure similar
to a solution. But whereas solutions solve exercises directly, submits solve them
indirectly, through tasks.
supervisor A pre-defined role having maximum rights to all objects. Also any user having these
rights. There can be any number of supervisors in the system. There is always at
least one, the admin, i.e. the user with ID = 1.
task An exercise assigned to a group, where the group members are supposed to solve it.
It has several attributes that can modify the properties of the exercise from which
it is derived.
template A PHP script consisting mostly of HTML with some PHP fragments. It is used
to compose the contents of a page or component for display, using data stored in a
view object.
There are also e-mail templates which are simpler and only allow variable substitu-
tion.
text The text of an exercise specification. An exercise specification can have several
texts, representing different revisions of the specification. One of them is always
marked as the current one.
trustee The user to whom some rights were delegated by another user (the granter ).
user An object usually representing a physical person registered in the system. For each
user, there are associated preferences, group membership, results etc.
view An object holding data for insertion into a template. Part of the Model-View-
Controller design pattern.
worker A running process (with an associated directory tree where it resides) that sequen-
tially processes jobs. Jobs are handed to workers by Qman.
Appendix B: Database Schema 95
tasks
submits id uint, PK, inc
exercises
groupId uint, FK, U
id uint, PK, inc
exerciseId uint, FK, U id uint, PK, inc
userId uint, FK
fromTime uint, ts name vchar(64), U
taskId uint, FK
toTime uint, ts, N comment vchar(255)
exerciseId uint, FK, T
toTime2 uint, ts, N note text
submitted uint, ts
comment text taskComment text
enqueued uint, ts, N
points usmallint textId uint, FK, N
evaluated uint, ts, N
points2 usmallint author uint, FK
extension char(8)
submits usmallint created uint, ts
comment vchar(32)
extensions set changed uint, ts
points smallint, N, %
obligatory usmallint keywords vchar(255)
bonusPoints smallint
acceptThreshold usmallint, % difficulty utinyint
public bool
locked bool
solutions extensions set
acceptThreshold usmallint, %
id uint, PK, inc version uint
exerciseId uint, FK tasksCount uint, T
exercise_ratings author uint, FK submitsCount uint, T
submitted uint, ts submitsPoints uint, T
id uint, PK, inc enqueued uint, ts, N submitsUsers uint, T
userId uint, FK, U evaluated uint, ts, N ratings uint, T
exerciseId uint, FK, U extension char(8) ratingsCount uint, T
rating usmallint, N, % comment vchar(255) oldRatings uint, T
bestPoints usmallint, N, %, T points smallint, N, % oldRatingsCount uint, T
submitsCount uint, T public bool