[contestms-dev] Separate users and tasks from contests

  • From: William Di Luigi <williamdiluigi@xxxxxxxxx>
  • To: contestms-dev@xxxxxxxxxxxxx
  • Date: Mon, 11 Aug 2014 21:48:17 +0200

Hi,
currently, all users and tasks are tied to a single contest. The idea of
separating users from contests seems to be already "accepted", as there are
clear benefits to it. For example, the ITA1 contestant named "A B" having a
particular photo.jpg **should** be the same person across the two contests
(i.e. "IOI day1" and "IOI day2").

However, since I've been involved (along with other people) on
a "training-oriented" CMS fork, I also see benefits in the separation
between tasks and contests. I'd like to allow to (authorized) users to set
up training contests (that is, CWS instances served within the main
website, which is PWS=PracticeWebServer) by simply "choosing" what tasks to
use from the main archive, or by creating some tasks. For example, a user
could create a task and keep it untied from any contest (thus invisible)
until he decides to use it.

I understand that CMS has not the need nor the duty to do that separation,
but I think that it would benefit as well from that.

Once users are separated from contests, the contest importing (or
exporting) process has to be adjusted. When ioi_day1 is imported there are
no users yet in the DB, so you will either:

   1. Import the contest (and create UserContest participations) "forcing"
   the creation of the needed users (not a very nice approach), or...
   2. You will create the users first and then import the contest (or,
   indifferently: import the contest with zero users, then create the users,
   and eventually associate them with the contest).

I think that the latter approach is cleaner (it doesn't enforce an order
between contest creation and user creation) and more maintainable. Overall,
I'd say that it makes sense to separate the "creation of users" phase from
the "creation of contest" phase.

Now, if users gets created independently from the contest, it makes sense
to use a loader to create them (so BaseLoader will be split in two
different interfaces: UserLoader, ContestLoader, each of them specifying a
get_user() or get_contest(), and how to check if the user/contest has
changed). For the **italy_yaml** format, this means that each users will be
stored in its own folder (like contests) with its own user.yaml file
(specifying first_name, last_name, email...) and maybe a profile.jpg.

If the task's importing process becomes independent from contest's as well,
we would simply have one more interface: UserLoader, TaskLoader,
ContestLoader (actually, when you have users and tasks on the DB, there is
no real need for a ContestLoader... for example, an interactive
cmsSetupContest prompting "which of these tasks and users do you want to
associate?" would do).

Also, the current setting for contest dumping (and reimporting dumps) would
have to be changed: it's difficult to export ioi_day1 and ioi_day2 in two
different dumps (since they share their users), so it will be necessary to
either dump Users separately or to just redefine the current meaning of
dump from "dump of a contest" to "dump of a database" (I'd vote for this
one). In both cases, separating Tasks doesn't "add complexity".

The expected outcome that I see is CMS handling user/task/contest creation
processes independently, with some benefits:

   - Easier testing
      - It's easier to mock components if everything is as modular as
      possible
   - Easier contest setup
      - For italy_yaml: it's not compulsory to have tasks as subfolders of
      the contest folder: you can keep them wherever you want because you will
      import them independently; the same thing stands for users
      - For other formats: if you have a TaskLoader but don't have a
      UserLoader because, maybe, you are used to keep only tasks (and create
      users with a different process) you can "borrow" another
format's UserLoader
   - cmsReimporter disappears
      - Why reimport an entire contest when you can reimport exactly what
      you changed? (well, actually **italy_yaml** checks if a task has been
      changed before importing it... this check would still be handy, to "warn"
      contest admins trying to reimport an unchanged task, but would become
      unnecessary). Also, in "my" use-case, even checking if tasks have been
      changed it's still quite annoying (we have about a hundred tasks).

What do you think?

We started working on this here
<https://github.com/wil93/cms/commits/decouple_user_contest>, I added a
cmsAddTask utility (thus completing the "family" of cmsRemoveTask,
cmsAddUser, cmsRemoveUser). I think that we have done almost all the needed
DB changes, apart from Submission (on which we are working now). There are
some things left to do such as finishing to port CWS and AWS to the new DB
(CWS should be already in good state, I think) and decide how to handle
dump export/import.

-- 
William.

Other related posts: