|
|
|
@ -1612,7 +1612,7 @@ The Nette framework is an MVP (Model, View, Presenter) framework. It has many
|
|
|
|
|
tools for creating complex websites and we need only a subset of them or we use
|
|
|
|
|
different libraries which suite our purposes better:
|
|
|
|
|
|
|
|
|
|
- **Model** - the model layer is implemented using the Doctrine 2 ORM insead of
|
|
|
|
|
- **Model** - the model layer is implemented using the Doctrine 2 ORM instead of
|
|
|
|
|
Nette Database
|
|
|
|
|
- **View** - the whole view layer of the Nette framework (e.g., the Latte engine
|
|
|
|
|
used for HTML template rendering) is unnecessary since we will return all the
|
|
|
|
@ -3078,6 +3078,10 @@ in the configuration file of the cleaner.
|
|
|
|
|
|
|
|
|
|
## REST API
|
|
|
|
|
|
|
|
|
|
The REST API is a PHP application run in an HTTP server. Its purpose is
|
|
|
|
|
providing controlled access to the evaluation backend and storing the state of
|
|
|
|
|
the application.
|
|
|
|
|
|
|
|
|
|
@todo: what to mention
|
|
|
|
|
- basic - GET, POST, JSON, Header, ...
|
|
|
|
|
- endpoint structure, Swager UI
|
|
|
|
@ -3089,27 +3093,153 @@ in the configuration file of the cleaner.
|
|
|
|
|
|
|
|
|
|
### Used Technologies
|
|
|
|
|
|
|
|
|
|
@todo: PHP7 – how it is used for typehints, Nette framework – how it is
|
|
|
|
|
used for routing, Presenters actions endpoints, exceptions and
|
|
|
|
|
ErrorPresenter, Doctrine 2 – database abstraction, entities and
|
|
|
|
|
repositories + conventions, Communication over ZMQ – describe the
|
|
|
|
|
problem with the extension and how we reported it and how to treat it in
|
|
|
|
|
the future when the bug is solved. Relational database – we use MariaDB,
|
|
|
|
|
Doctine enables us to switch the engine to a different engine if needed
|
|
|
|
|
We chose to use PHP in version 7.0, which was the most recent version at the
|
|
|
|
|
time of starting the project. The most notable new feature is optional static
|
|
|
|
|
typing of function parameters and return values. We use this as much as possible
|
|
|
|
|
to enable easy static analysis with tools like PHPStan. Using static analysis
|
|
|
|
|
leads to less error-prone code that does not need as many tests as code that
|
|
|
|
|
uses duck typing and relies on automatic type conversions. We aim to keep our
|
|
|
|
|
codebase compatible with new releases of PHP.
|
|
|
|
|
|
|
|
|
|
To speed up the development and to make it easier to follow best practices, we
|
|
|
|
|
decided to use the Nette framework. The framework itself is focused on creating
|
|
|
|
|
applications that render HTML output, but a lot of its features can be used in a
|
|
|
|
|
REST application, too.
|
|
|
|
|
|
|
|
|
|
Doctrine 2 ORM is used to provide a layer of abstraction over storing objects in
|
|
|
|
|
a database. This framework also makes it possible to change the database server.
|
|
|
|
|
The current implementation uses MariaDB, an open-source fork of MySQL.
|
|
|
|
|
|
|
|
|
|
To communicate with the evaluation backend, we need to use ZeroMQ. This
|
|
|
|
|
functionality is provided by the `php_zmq` plugin that is shipped with most PHP
|
|
|
|
|
distributions.
|
|
|
|
|
|
|
|
|
|
### Data model
|
|
|
|
|
|
|
|
|
|
@todo: Describe the code-first approach using the Doctrine entities, how
|
|
|
|
|
the entities map onto the database schema (refer to the attached schemas
|
|
|
|
|
of entities and relational database models), describe the logical
|
|
|
|
|
grouping of entities and how they are related:
|
|
|
|
|
|
|
|
|
|
- user + settings + logins + ACL
|
|
|
|
|
- instance + licences + groups + group membership
|
|
|
|
|
- exercise + assignments + localized assignments + runtime
|
|
|
|
|
environments + hardware groups
|
|
|
|
|
- submission + solution + reference solution + solution evaluation
|
|
|
|
|
- comment threads + comments
|
|
|
|
|
We decided to use a code-first approach when designing our data model. This
|
|
|
|
|
approach is greatly aided by the Doctrine 2 ORM framework, which works with
|
|
|
|
|
entities -- PHP classes for which we specify which attributes should be
|
|
|
|
|
persisted in a database. The database schema is generated from the entity
|
|
|
|
|
classes. This way, the exact details of how our data is stored is a secondary
|
|
|
|
|
concern for us and we can focus on the implementation of the business logic
|
|
|
|
|
instead.
|
|
|
|
|
|
|
|
|
|
The rest of this section is a description of our data model and how it relates
|
|
|
|
|
to the real world. All entities are stored in the `App\Model\Entity` namespace.
|
|
|
|
|
There are repository classes that are used to work with entities without calling
|
|
|
|
|
the Doctrine `EntityManager` directly. These are in the `App\Model\Repository`
|
|
|
|
|
namespace.
|
|
|
|
|
|
|
|
|
|
#### User Account Management
|
|
|
|
|
|
|
|
|
|
The `User` entity class contains data about users registered in ReCodEx. To
|
|
|
|
|
allow extending the system with additional authentication methods, login details
|
|
|
|
|
are stored in separate entities. There is the `Login` entity class which
|
|
|
|
|
contains a user name and password for our internal authentication system, and
|
|
|
|
|
the `ExternalLogin` entity class, which contains an identifier for an external login
|
|
|
|
|
service such as LDAP. Currently, each user can only have a single authentication
|
|
|
|
|
method (account type). The entity with login information is created along with
|
|
|
|
|
the `User` entity when a user signs up. If a user requests a password reset, a
|
|
|
|
|
`ForgottenPassword` entity is created for the request.
|
|
|
|
|
|
|
|
|
|
A user needs a way to adjust settings such as their preferred language or theme.
|
|
|
|
|
This is the purpose of the `UserSettings` entity class. Each possible option has
|
|
|
|
|
its own attribute (database column). Current supported options are `darkTheme`,
|
|
|
|
|
`defaultLanguage` and `vimMode`
|
|
|
|
|
|
|
|
|
|
Every user has a role in the system. The basic ones are student, supervisor and
|
|
|
|
|
administrator, but new roles can be created by adding `Role` entities. Roles can
|
|
|
|
|
have permissions associated with them. These associations are represented by
|
|
|
|
|
`Permission` entitites. Each permission consists of a role, resource, action and
|
|
|
|
|
an `isAllowed` flag. If the `isAllowed` flag is set to true, the permission is
|
|
|
|
|
positive (lets the role access the resource), and if it is false, it denies
|
|
|
|
|
access. The `Resource` entity contains just a string identifier of a resource
|
|
|
|
|
(e.g., group, user, exercise). Action is another string that describes what the
|
|
|
|
|
permission allows or denies for the role and resource (e.g., edit, delete,
|
|
|
|
|
view).
|
|
|
|
|
|
|
|
|
|
The `Role` entity can be associated with a parent entity. If this is the case,
|
|
|
|
|
the role inherits all the permissions of its parent.
|
|
|
|
|
|
|
|
|
|
All actions done by a user are logged using the `UserAction` entity for
|
|
|
|
|
debugging purposes.
|
|
|
|
|
|
|
|
|
|
#### Instances and Groups
|
|
|
|
|
|
|
|
|
|
Users of ReCodEx are divided into groups that correspond to school lab groups
|
|
|
|
|
for a single course. Each group has a textual name and description. It can have
|
|
|
|
|
a parent group so that it is possible to create tree hierarchies of groups.
|
|
|
|
|
|
|
|
|
|
Group membership is realized using the `GroupMembership` entity class. It is a
|
|
|
|
|
joining entity for the `Group` and `User` entities, but it also contains
|
|
|
|
|
additional information, most importantly `type`, which helps to distinguish
|
|
|
|
|
students from group supervisors.
|
|
|
|
|
|
|
|
|
|
Groups are organized into instances. Every `Instance` entity corresponds to an
|
|
|
|
|
organization that uses the ReCodEx installation, for example a university or a
|
|
|
|
|
company that organizes programming workshops. Every user and group belong to
|
|
|
|
|
exactly one instance (users choose an instance when they create their account).
|
|
|
|
|
|
|
|
|
|
Every instance can be associated with multiple `Licence` entities. Licences are
|
|
|
|
|
used to determine whether an instance can be currently used (access to those
|
|
|
|
|
without a valid instance will be denied). They can correspond to billing periods
|
|
|
|
|
if needed.
|
|
|
|
|
|
|
|
|
|
#### Exercises
|
|
|
|
|
|
|
|
|
|
The `Exercise` entity class is used to represent exercises -- programming tasks
|
|
|
|
|
that can be assigned to student groups. It contains data that does not relate to
|
|
|
|
|
this "concrete" assignment, such as the name, version and a private description.
|
|
|
|
|
|
|
|
|
|
Some exercise descriptions need to be translated into multiple languages.
|
|
|
|
|
Because of this, the `Exercise` entity is associated with the
|
|
|
|
|
`LocalizedAssignment` entity, one for each translation of the text.
|
|
|
|
|
|
|
|
|
|
An exercise can support multiple programming runtime environments. These
|
|
|
|
|
environments are represented by `RuntimeEnvironment` entities. Apart from a name
|
|
|
|
|
and description, they contain details of the language and operating system that
|
|
|
|
|
is being used. There is also a list of extensions that is used for detecting
|
|
|
|
|
which environment should be used for student submissions.
|
|
|
|
|
|
|
|
|
|
`RuntimeEnvironment` entities are not linked directly to exercises. Instead,
|
|
|
|
|
the `Exercise` entity has an M:N relation with the `SolutionRuntimeConfig`,
|
|
|
|
|
which is associated with `RuntimeEnvironment`. It also contains a path to a job
|
|
|
|
|
configuration file template that will be used to create a job configuration file
|
|
|
|
|
for the worker that processes solutions of the exercise.
|
|
|
|
|
|
|
|
|
|
Resource limits are stored outside the database, in the job configuration file
|
|
|
|
|
template.
|
|
|
|
|
|
|
|
|
|
#### Reference Solutions
|
|
|
|
|
|
|
|
|
|
To make setting resource limits objectively possible for a potentially diverse
|
|
|
|
|
set of worker machines, there should be multiple reference solutions for every
|
|
|
|
|
exercise in all supported languages that can be used to measure resource usage
|
|
|
|
|
of different approaches to the problem on various hardware and platforms.
|
|
|
|
|
|
|
|
|
|
Reference solutions are contained in `ReferenceSolution` entities. These
|
|
|
|
|
entities can have multiple `ReferenceSolutionEvaluation` entities associated
|
|
|
|
|
with them that link to evaluation results (`SolutionEvaluation` entity). Details
|
|
|
|
|
of this structure will be described in the section about student solutions.
|
|
|
|
|
|
|
|
|
|
#### Assignments
|
|
|
|
|
|
|
|
|
|
The `Assignment` entity is created from an `Exercise` entity when an exercise is
|
|
|
|
|
assigned to a group. Most details of the exercise can be overwritten (see the
|
|
|
|
|
reference documentation for a detailed overview). Additional information such as
|
|
|
|
|
deadlines or point values for individual tests is also configured for the
|
|
|
|
|
assignment and not for an exercise.
|
|
|
|
|
|
|
|
|
|
Assignments can also have their own `LocalizedAssignment` entities. If the
|
|
|
|
|
assignment texts are not changed, they are shared between the exercise and its
|
|
|
|
|
assignment.
|
|
|
|
|
|
|
|
|
|
Runtime configurations can be also changed for the assignment. This way, a
|
|
|
|
|
supervisor can for example alter the resource limits for the tests.
|
|
|
|
|
|
|
|
|
|
#### Student Solutions
|
|
|
|
|
|
|
|
|
|
#### Comment threads
|
|
|
|
|
|
|
|
|
|
### Request Handling
|
|
|
|
|
|
|
|
|
|