Category Archives: Projects

Blogs associated with particular development projects,

Free Machine Finder – Draft Design and Implementation Proposal


Provide a way for our students to easily locate free DICE desktops in AT. In addition provide something like the functionality in the student written MAPP demonstration system that helps students find out
which labs their friends are working in.


This is the first draft so likely to see some amendments.

User Interface

We will provide an Android App as the primary user interface. If this is positively accepted we would then look at also providing an iOS equivalent. We will use a REST API so as not to preclude other interfaces, such as desktop web browser and command line, but will not necessarily implement any of these as part of this project.

The App will have a live home screen widget which simply displays the name of the AT lab that currently has the most available free machines. An additional icon will be shown alongside the lab name if there are “friends” logged onto machines in that lab (see details on
the “friends” feature below).

Opening the App will show one main window. This will contain an ordered scrollable list of AT lab names with those at the top of the list having the most available free machines and those at the bottom having the least available. An additional icon will be shown alongside each lab name where there are one or more “friends” logged onto machines in that particular lab.

The status of AT lab machine usage and logged in “friends” presented by the App will be refreshed automatically every minute while the App is running.

There will be a “Refresh” icon on the main App window which can be touched to force a manual refresh.

There will be a “Friends” icon on the main App window. This can be touched to open the  App “friends” window. See details below.

Friends Feature

The “friends” feature is configured in the App “friends” window. At the top of the window will be an on/off “opt-in” slide toggle which will be off by default. Nothing else is shown on the window in this state. When this toggle is off (or switched to off) the users UUN is not available to other users to search for and invite to be a “friend” (and any previously made associations will then be hidden from those users, see below). Also the “friends” icon will no longer be shown alongside the AT lab name, irrespective of whether previously made associations would normally result in the icon being shown.

When the toggle is slid to on the following additional items are shown.

“Enter Friend UUN” which is an entry box where you can enter a UUN. Alongside this is a “Search” icon. Touch this (or touch Return on the onscreen keyboard) to search for the UUN among only those users that have chosen to “opt-in”. If the UUN is not found an error like “UUN not found (invalid) or UUN has not opted-in” will be displayed. If the UUN is found a modal will be shown with the message “UUN (Firstname Lastname) found”. This will have two buttons – “Invite” and “Cancel”.  Touching “Invite” will close the modal and add the UUN to the list underneath (see below) and the “Enter Friend UUN” box will be cleared. Touching “Cancel” will close the prompt modal doing nothing else.

Below the “Enter Friend UUN” entry box will be a list of friends, each shown as “UUN (Firstname)”. For those waiting acceptance alongside is text saying “Invited”. In addition some will be separated at the top of the list which have an “Accept” button alongside. These are requests from other users to this one. Touch the button to confirm.

Swiping any friend item will display a modal with an option to delete the association or cancel. The entry does not have to be a confirmed association, swipe to delete can also reject an invitation or cancel an invitation they have made (in which case an orphaned acceptance would then be discarded on both sides). Once deleted the association will need to be requested again from either side and confirmed. There is no explicit notification on removal for the other user (the corresponding UUN will just  drop off their list on the next refresh).

A “friend” association is always a two way pairing, it does not matter whether A invites and B accepts or B invites and A accepts, after this has happened A will have B listed as a friend and B will have A listed as a friend.

Once friend associations exist (which requires invitation AND acceptance) then when any of the associated UUN’s in the list are logged into machines this will be alerted to the user by displaying the “friends” icon alongside the corresponding AT lab name. This is except where a user has subsequently turned off “friends”, in which case their UUN will (silently) not be included in the search (although they will still be listed on the associated users “friends” window) – possibly with an “offline” status shown.


For ease of use it would be impractical for the user to go through DICE authentication every time they wanted to use the App. So instead, on first opening the App the user will go through some kind of DICE authentication (possibly by just making an authenticated REST/API call although not entirely clear how this will work from  a mobile app yet) for which they receive a unique token (random hash value). The token is stored on their phone and the token/UUN mapping is stored in the back end. Subsequently the App just uses this stored token for authentication (by passing it as an argument in every REST/API call).

Compromise by loss of phone is possible obviously, but if we are informed the relevant token/uun pair can be revoked by deletion of the record at the back end requiring the user to re-authenticate in order to use the App. Deletion of the token/uun pair at the back end would also delete the users “opt-in” status (reverting to the default which is off) and any existing “friend” associations. Increased security is possible, for example by constructing the hash based on UUN and phone UDID, but not sure that is really necessary here (and may cause some users concern over tracking).


Machine Status Collection

Each desktop in the AT student labs will have a cron job that runs a command every minute. This command will make an authenticated REST/API call to update the back end PostgreSQL database with the current status. This updates the corresponding machines record with the current console UUN (or empty if no user logged into the console). It need not wake up the machine to run during sleep – the last reported state should in general indicate no console user (unless they left themselves logged on).

An alternative (maybe preferable) to running the status update command every minute would be to just call the command directly from console login and console logout, this could be done through the PAM stack for example. Although it would be necessary to also run the command on machine reboot and GUI restart for example.

Authentication will use the machine hostclient principal. Using an LCFG spanning map and pgluser we will be able to automatically create a mapping role for each host principal on PostgreSQL for each AT lab machine as and when they go in and out of service. We can also use pgluser to grant the role permission to access the “status” table view (below).

On PostgreSQL these roles will use a view that constrains their access to only the record for the machine corresponding to the host principal. This can be trivially achieved since the SESSION_USER will be the “machine name” (derived from host principal) and by using a view with update rules based on SESSION_USER.

In summary:

  • the client will use hostclient/
  • a spanning map and pgluser will automatically maintain a corresponding “HOSTNAME” user in PostgreSQL for each hostclient principal
  • similarly pgluser will grant suitable access to the “status” table view for each HOSTNAME role (by assigning the relevant access role to each HOSTNAME user role).
  • when the hostclient principal connects the  SESSION_USER will be “HOSTNAME”
  • a “status” table in PostgreSQL will have two columns – “hostname” and “console_uun”
  •  a view will on the “status” table that is “select” and “update” constrained to only rows where “hostname” matches SESSION_USER – hence the given “HOSTNAME” role can only see and change the value of the row in the table which has a matching hostname value. A similar “insert” rule will be defined on the view so that only a row with matching hostname value can be added. The REST/API will use an “UPSERT” to insert or update the row it owns as appropriate.
  • the “status” table will be unique on hostname to avoid any risk of double entry by accident or design flaw.

Obviously status updates will not work during online examinations since the connection will be firewalled. This is reasonable behaviour (all locked down labs will show as fully available during the exam).

Unfortunately it will probably not be possible at present to get a feed of timetabled lab room bookings (for tutorials etc) from the central timetabling system as remote programmatic access to that system was de-scoped in the original project. Consequently this service may show rooms having many free machines that are not actually available to students to use as there is a tutorial happening in the room at that time, for example.

Support Data

A feed of data will populate an “active_user” table from the Informatics School Database with known UUN’s and corresponding names. The known UUN’s will only be those that have a valid account entitlement (effectively the same data as provided via the Prometheus user view) . Once a UUN drops off that feed the authenticated REST/API can no longer be used to retrieve a token for that UUN and any existing token/uun pairing and associated data will be marked for deletion and will be fully purged after a short (glitch handling) delay. By using a FDW and TheonCoupler all the feed management can be done entirely in PostgreSQL and no supporting infrastructure should be required.

An additional feed of data will be required to populate a “room” table. This will contain machine to room mapping data. This data could come from LCFG or the inventory. Directly from the inventory would probably be preferable and can be achieved with a simple REST/API query against that and internalized as an FDW. Alternatively it may be possible this information could be extracted from clientreport or LCFG information on the client itself and returned in the status update along with the console login status.


Initial Authentication and Connection. When the App has no token it will require DICE authentication. It can then make an authenticated connection to the REST/API as that UUN.

An authenticated URI to REST/API can request a token for the authenticated UUN (or a call to the authenticated URI will first bounce the user through an authentication step). Once the App has the token it no longer uses the authenticated URI.

All other connections to REST/API use the unauthenticated URI always passing the token as one of the arguments.

All REST/API calls return JSON.

The authenticated API simply returns the corresponding token. To do so it will perform an “UPSERT” operation on the “user” table. This table contains three columns: “uun”, “token” and “friend_optin”. The upsert will be view limited (for the REST/API credentials) so that it can only set the “uun” value – the token will be generated and set automatically and “friend_optin” will be left as NULL. The authenticated API will use credentials held on the server to perform this operation, but that is all these credentials will be able to do. The table will be unique on “uun”, preventing double entry by accident or design flaw. Note that an attempt to re-authenticate (if the user loses their token by deleting the App or getting a new phone) will update the existing record and re-generate a token.

The unauthenticated REST/API provides the following calls:

  • Get a list of labs and free machines – arguments are “token”. This returns an array of lab objects in order from most free to least free. The app will put the first entry in the homepage widget and display all the entries on the main App window. Each lab object contains the name and a flag indicating if friends are in it. Where the user has not turned on “opt-in” the friends flag will always be false. Where the supplied token does not match a stored token/uun pair the result will always be empty. Where it does the array of lab name objects will be returned. Where it does and the token/uun friend “opt-in” value is true then the relevant “friend” table will be scanned to set the friend flag appropriately. The “friend” table is used for this. It has two “uun” columns (invitor and invitee, although after this point the two are synonymous) and a “status” column which if true indicates the association has been confirmed (the invite has been accepted). When scanned the token/uun is looked for under both columns (i.e. find friends that the user invited and also friends that invited that user). Also has a “timestamp” column set on row creation, used later for automatic expiry of requests. The App makes this API call automatically every minute or when the “refresh” icon is touched.
  • Enable friends – arguments are “token”. This is called to opt-in to the “friends” feature. Sets the relevant flag in the “user” table and returns confirmation message.
  • Get friend – arguments are “token” and “uun”. This is called to return a match for the passed “uun” value. A match is only returned if the UUN matches an entry in the “user” table where “status” is true. The returned match object includes the corresponding firstname and lastname from the “active_user” table.
  • Invite friend (PUT) – arguments are “token” and “uun”. Adds a record in “friend” table with “uun,friend_uun” (where “uun” is that corresponding to the token and “friend_uun” is the “uun” passed directly as argument) and the default for status boolean (cannot be set via add api) which is NULL (meaning “request”). Only a UUN that would be returned as valid in the “get friend” call above will be added. Only one instance can be added (the table is unique on each uun+friend_uun combination).
  • Approve friend request – arguments are “token” and “uun”. Updates the “friend” table by locating the row where “the uun corresponding to the token” = “friend_uun” and “uun” equals the passed “uun” (the requester) and status is NULL and sets status to TRUE.
  • Decline friend (either an invite, a request for approval or a confirmed association) – arguments are “token” and “uun” (of friend). Searches “friend” table and deletes the row where uun corresponding to token equals “uun” and “friend_uun” equals passed “uun” or vice versa.
  • Get friends – arguments are “token”. Returns data from “friend” table where current uun (corresponding to token) equals “friend_uun” or the “uun” columns. An ordered array of objects is returned suitable for direct display on the “friends” App window. Three types will be returned: “requests” where status is NULL and current uun matched the “uun” column; “invites” where status is NULL and current_uun matched the “friend_uun” column; “associated” where status is TRUE and current uun matches either column. Data included in the object will be the names corresponding to the UUN and a type flag. This API call is made when the “friends” App window is opened, every minute while it is open and immediately after the “enable/invite/approve/decline” requests above.

Note that rows in the “friends” table are deleted automatically by purge function from where status is NULL (invites have not been accepted) after a period of time, e.g. 7 days.

To alleviate tracking concerns for “friends” data we could consider (as in the demonstration application) hashing all UUN values (with a random salt value held only on the server) within PostgreSQL so that casual internal support access (and accidental end user remote access by API bug or deliberate hack) reveals no useful information.

All the API functionality is implemented directly in PostgreSQL using
views and appropriate update rules. The REST/API will connect locally as a specific set user (no connections from outside the server for that user). It would be easily implementable with Python/FlaskRestful for example, although the authenticated side might need more work.

The App simply makes the necessary  REST/API URI calls and displays the results, it needs little other logic. It should be simulatable via Curl calls. It holds no state other than its connection token.

Implementation Sequence

Below will probably be done in two discreet stages, each running through some or all of the steps below. First would be to implement the core support for finding free machines (all steps). Second would be to implement support for the “friends” feature (steps 8 through 12).

  1. Create back end PostgreSQL service.
  2. Add LCFG spanning map and pgluser configuration to map hostclient principals to db users.
  3. Create REST/API for client “status” table update.
  4. Create machine client.
  5. Test then deploy onto all student lab machines.
  6. Monitor content on PostgreSQL to confirm functionality.
  7. Implement and test feed for “active_user” table update.
  8. Implement PostgreSQL functionality for REST/API calls including permissions. Test directly in PostgreSQL.
  9. Implement a Python/Flask REST/API interface.
  10. Test REST/API functionality with Curl.
  11. Implement a full test suite using Curl and a simulated data set of some kind.
  12. Write the Android App.

make comments on criteria available

Another (feature creep) request for the new system. It looks likes the mechanism is there and this will be easy to bolt on subsequently in which case it is unlikely to be done with this particular project.

Returning feedback to students wasn’t part of the  original project description, rather a requirement that has arisen in the meantime. But the fact that the reports are now stored is surely a  big step in providing that feedback. When we agreed at Teaching Committee that information from the reports  should be returned to students as feedback, I pointed out that it would probably not be possible to do it in June 2015, but I hope we will have something in place for June 2016.

Achieving this with the new system is probably just a case of Webmark also producing a
reduced version of the form just including the relevant fields students can see and then a specific index page for access by students that shows them that form.

Comment: That would be perfect! The “relevant fields” are:

  • Individual marking form: Comments on the criteria
  • Agreed mark form: nothing
  • Moderator’s form, if any: Comments on the criteria

I guess that an ideal “specific index page for access by students” would  be to include it on but with a time delay so that  it is only accessible once the examiners’ meetings have passed.

Modeling Part Completed

The documentation for TheonModel (managing the physical database schema and related configuration for TheonCoupler, TheonUI and TheonPortal) has been completed and including the illustrations. It is in principle a first draft, but its been through a number of revisions so its a fairly solid first draft. The command toolchain is clearly defined now so we can start implementing that – all the underlying technology has been done already, or at least proven in principle, so its just tidying and wrapping it up properly here to do. The documentation for TheonCoupler is practically done as well now, should be completed within the next few days. Still got architectural documentation to do on TheonUI and TheonPortal to do (bits and pieces on usage and configuration are there already under TheonModel). Need to write the release/package management documentation as well (although the toolchain for that is at least already defined and coded up). Finally the system installation/configuration documentation needs to be done – although that is a little bit in limbo to see whether we can get a viable standalone LCFG config up and running. The remaining documentation will proceed in parallel with getting the TheonModel toolchain implemented as that is really the primary goal of this project.

Started back on Documentation

So after a long break (I think May was the last time this was touched) got back into doing the documentation. It probably took a day just to orientate to where we were. Anyhow the main purpose of doing the documentation before the technical work is complete is to pin down the workflow and hence what the commands and options will need to be provided by the wrapper toolkit. This so far has been quite successful in identifying any gaps in the technical implementation (due to the attempt to reflect real use cases).

Mostly Done

The bulk of this has now been done (the first four goals).

The “Proposal for Submissions” was followed pretty much as-is. The MSc submissions link will now jump to an MSc variant of the UG4 form but using the same underlying mechanism. Both handling flags can be set and materials uploaded at submission time.

The “Proposal for Access to Submissions” was modified slightly. In the end the existing “projsubs/ug4” and “projsubs/msc” folders were retained (rather than new URLs and folders being created) with the modified indexing code. Instead of passing arguments the indexing behaviour is automatically changed based on whether the current year is the same as the year being processed. If not then the old behaviour is retained. If it is then the new behaviour is followed. This new index format for the current (assessment) year is as described, except that to achieve sorting a variation of the “dotable” cgi script is used and a data file is produced instead (mapped to the cgi script by a rule in .htaccess). Some other minor changes were made also to the existing setup (such as indexing in year descending order). The indexing scripts now generate the liveroot files directly (since they have to change the name and extension) rather than via stdout. They also generate a data file into the upload directory which maps the matriculation number to the submitted folder number – this is used by Webmark (see below).

The “Proposal for Webmark Returns” was also modified slightly. The end result is the same though – a PDF for each filled in form and a data file for each mark is copied into the submission upload directory. Instead of using a cc mail alias and remctl a feature was added to Webmark to allow per-output subdirectories in the final file output path, components of which could be literal or set by the value of a form field. An additional source was added which is the data file generated by the indexing scripts above. This allows a “dynamic” output directory (which is the students upload submission directory) to be set against the additional outputs. By this means Webmark can write the files for the indexing scripts directly into their final location (and safely as it is part of the user submission process, which also ensures that the students upload directory is in place before a Webmark submission can be made). A consequence of this though is that it is no longer possible to fill in a blank form for the mark returns – a student must be selected from the drop-down, in practice it would be an error condition if not all the students are listed in the drop-down.

The “Proposal for Public Access” has not been done yet – but will be another modification to the indexing scripts. In this context they will simply produce a list of projects for all years (including the year in the index) with just the student name and project title (which is a link to the copied PDF as at the moment). This list will only include students with distinctions though (as previously described).

To clean everything up the older msc project submissions were moved from their original “infthesis” upload location (where they were mixed up with PhD and MScRes submissions) into the new “mscprojects” location and the indexing scripts re-run for the default three years and then individually all the way back to 2003. The indexing scripts were also manually re run for all the existing UG4 years.

Goals and Proposal


See also the original project descriptor.

  • MSc submission to be the same as UG4 is now, hence to include project materials archive and “handling” flags.
  • Webmark mark return PDFs to be accessible alongside the project PDF and materials.
  • Provide a simple master index page of the current sessions projects with links to the report PDF, materials and showing the project marks (1st marker mark, 2nd marker mark, agreed mark and moderator mark) each with link to actual corresponding Webmark return PDF. The index page should include student name, UUN and project title. It should be sortable by any column, but particularly mark columns.
  • All to be directly accessible to external examiners, however authentication does not need to be constrained down to specific examiner access per-project, controlled access to any is sufficient.
  • Projects of MSc students awarded distinctions (where student has gained a distinction overall) to be published openly. Projects of UG4 students where the projects final mark (as appropriately calculated) is at a distinction grade level to be published openly. In both cases this is however only if the “handling” flags do not indicate that the project was submitted for assessment only.

Proposal for Access to Submissions for Markers

We will create two new project websites. Access will be limited by default to current staff (as is the case for the current project area: and external examiners, e.g.

External examiners will need to obtain an iFriend account which can then be given access to either or both of these areas. Given the small numbers of accounts likely to be involved this process will not be automated – each new iFriend account will require frontline support to make a small configuration change to the ACLs for these URLs for each session.

We already have two indexing scripts which work well (provide access to each students projects PDF, materials and “handling” flags for UG4, and could also do the same for MSC, see below). We propose modifying these to also act as the index page generator for each area above:

  1. Modify “submission_links_common.cgi” so that by optional argument only the most recent submission by each student (by reference to the submission date and time held in the “record” file in the “upload” directory) is listed.
  2. Modify “submission_links_common.cgi” so that by optional argument it will also display per student submission the 1st marker mark, 2nd marker mark, agreed mark and moderator mark. These will have been made available in the “upload” directory (see Webmark Returns proposal below). This option should also include a “COALESCE(moderated,agreed)” and “ABS(1stmark-2ndmark)” calculated column. The four raw marks will be links to each of the four possible Webmark PDF returns from markers (1st, 2nd, Agreed and Moderator) for that students project. These will have been copied into the “upload” directory (see Webmark Returns proposal below).
  3. Modify “submission_links_common.cgi” so that by optional argument the “handling” flags are not shown (these are not relevant to the marking process itself nor do external examiners need to see them).
  4. Modify “submission_links_common.cgi” so that the generated index page includes per-column sort functionality.
  5. Make “submission_links_ug4.cgi” act as “index.html” for “teaching/ug4projects”.
  6. Make “submission_links_msc.cgi” act as “index.html” for “teaching/mscprojects”.

Proposal for Submissions

We already have a submission form for UG4 which works well and does everything we need. The MSc submission form while using similar technology does not collect project materials or the “handling” flags. We propose dropping the current MSc submission form and using a straight clone of the UG4 process.

  1. Copy “” to “”.
  2. Factor out common code in “” and “” into “”. The only effective differences between them are the final “upload” directory path (which will be either “ROOT/ug4projects” as at the moment or “ROOT/mscprojects” for the new MSc version, in place of “ROOT/infthesis” where the MSc submissions are currently held) and a few tags which need to be either UG4 or MSC respectively.  Action script will be either the existing UG4 one or the new MSc one (see next item).
  3. Copy “” (which is the “submit” action of the current “”) to “”.
  4. Factor out common code in “” and “” into “”. Again the only effective differences are the final “upload” directory path and a few tags.

As before these will create a unique directory per-submission. This will contain the project report PDF, the project materials archive file and a “record” file which has relevant metadata – the students name, matriculation number, “handling” flags, date and time of submission. To put the new mechanism in place:

  1.  Update existing references to UG4 and MSc project submission to use the new scripts above.
  2.  Make sure that “” (previously used for MSc project submission) and links to it are marked for PhD Thesis submission only (I am not sure if this mechanism is still used for PhD submission, if not this could just be deleted).

Proposal for Webmark Returns

For various reasons it would be tricky to get Webmark to write its internal copy of the submitted 1st, 2nd, Agreed and Moderator mark forms directly into the “upload” directory. So to achieve this instead we propose the following.

  1. Modify the Webmark config for the project marking forms so a “copy” of the generated PDF (as sent to the marker) is sent into the corresponding students project submission “upload” directory. This will be done by adding a “Cc” to the Webmark email that is to an alias address, e.g. “”. The alias will be defined as a pipe to a “remctl” script on the Webmark server itself (which already has access to the student submission “upload” directories via NFS under an AMD mountpoint). The “remctl” script will strip the PDF attachment from the email and copy it into the most recent submission directory for the corresponding student. The directory matching will be done by reference to the students matriculation number which will be included in the Webmark generated PDF attachment filename and the students matriculation number held in the “record” file in the submission “upload” directory. This will require changing the generated attachment name in Webmark so this additional data is put into the filename. The Webmark PDF attachments will be stored with fixed/known names in the relevant “upload” directory (e.g. 1st.pdf, 2nd.pdf, Agreed.pdf and Moderator.pdf) so that the indexing script needs no additional intelligence to provide links to them.
  2. Also modify the Webmark config so that an additional (hidden) output is produced from the entered form data containing the actual mark awarded. As in item 1 above this will be pushed out via “remctl” script which will identify the appropriate “upload” directory to copy the data into and will be saved into a file with fixed/known name so that the indexing script can include the value as the title text for the link to the actual submitted form PDF.

Proposal for Public Access to Archive of Projects

Part of the submission technology we are continuing to use above includes a notification to the (legacy) School database to collect the submitted papers for further publication (if the “handling” flags give permission and in the case of the MSc that the student in question had been awarded a Distinction). This is currently broken for a few reasons:

  • The “upload” directory path being used by the database scripts seems to be wrong so it is currently looking in the wrong place.
  • The Distinction award is being looked up in the old legacy assessment structures where it is no longer maintained – in fact it was not being maintained in the new system (Theon) either until this session.

It is probably trivial to fix the above – however it is not clear what the long term status of these processes is (being largely tied to the legacy database service) nor what the plan will be with respect to PURE (and integration of reports onto personal pages).

So for now we propose (only for MSc students that got a Distinction Overall and UG4 projects where the final project mark was at a distinction grade level) that there will be a separate public access page, much like the existing “teaching/projsubs” tree, for the published project PDF reports.

The “projsubs” mechanism is basically a cron driven forced processing of the “submission_links_[ug4|msc].cgi” script for multiple sessions to produce a static index page per session of student projects with link (via the cgi) to the actual PDF report and materials, just like the live current session cgi script.

  1. Make a crontab entry derived from that used for “/projsubs” for a new URL, e.g.[ug4|msc]/YYYY.html, where YYYY.html is the relevant session snapshot, 2013.html for this session. Access to this URL tree will be public. This modified crontab entry will use additional arguments to “submission_links_common.cgi” to suitably modify the behaviour (see item 2 and 3 below) and also use the argument to hide “handling” flags (see item 3 in Proposal for Access to Submissions for Markers above).
  2. Modify the “submission_links_common.cgi” script so that by optional argument (given in the crontab entry for this URL) only students that were awarded a distinction and have not indicated in “handling” flags that the project was submitted for assessment only are listed (see item 4 below).
  3. Modify the “submission_links_common.cgi” script so that by optional argument (given in the crontab entry for this URL) each relevant students project PDF file is physically copied into the “teaching/projects” directory tree and that the index points to this rather than via the link script. This means that the public projects contain a separate copy from that held in the “upload” directory (which should be being deleted after the marking process has been completed, or as according to the students preference in the “handling” flags). This also fences access to just the project report PDF and means exposure to any project materials or marking reports will be prevented.
  4. Add a report to Theon that generates a list of MSc student matriculation numbers in each session that were awarded a distinction overall and a list of UG4 student matriculation numbers in each session that achieved a distinction grade for their final project mark. This report will be written into some area that the “submission_links_common.cgi” script can access and will then be used by that script to filter the directory tree of “upload” submissions to make the index a suitable subset (see item 2 above).
  5. Update any links to published projects to refer to the new URL (see item 1).