MiniProjectSpec 23 24
MiniProjectSpec 23 24
Specification
1
Training Record Application
1 Introduction
In this coursework you will undertake the implementation of a simple training record application. The
application is a web-based system that consists of two parts. The web server written in python and a
browser-based client that presents the user interface.
1. A complete browser based front-end for the app that makes use of HTML, CSS and Javascript. You
will not need to modify this code. Nor will you need to understand how it operates, other than how
it interacts with the server via the API (Application Programmer Interface). This is described in the
section Web Application Structure.
2. A skeleton backend framework for the app written in Python that provides the core web server
functionality.
1. Maintain the sqlite3 database that will hold all the required data.
2. Extend the skeleton code to complete the app functionality by adding code as required.
This document describes the behaviour required of the app. You will be assessed against this specification.
You will use python for program development and use SQL to interact with the sqlite database. You must
write the SQL queries yourself and not rely on a library such as PANDAS to abstract it for you. The SQL
database will be held in a file called database.db in the current working directory.
Start a web browser. Chrome and Edge have been demonstrated to work, most other modern browsers
should also function. Access http://127.0.0.1:8081 using the browser. This will access the locally running
server and load the index.html page. As you are not yet logged in to the app, the page is expected to re-
direct to the login page.
Where the browser requests html, css or javascript files, these will be returned by the pre- existing code. You
will not need to modify this code. It is contained within the do_GET() method of the http server object.
When the requested file is ‘/action’ the parameter ‘command’ is examined and if it is valid, an appropriate
handler function is invoked. You are expected to complete the code of these handler functions.
When the request file is ‘/create/…’ or ‘/class/…’ the existing code will load a matching HTML file and that
file will invoke the ‘/action’ API as required.
2
3 API
Your primary task in this project is to implement the backend API behaviour. This section provides the details
of the API.
Validating that all parts of an incoming request are present is an important first step in a web application
backend.
You also need to defend against inputs that are deliberately or accidentally bad. What are known as
‘injection’ attacks. This applies to all of the tasks, and you risk not getting all the marks if your code does not
defend against bad inputs. Note that the while the supplied front-end is intended to be well behaved and
does not deliberately provide bad input, the same is not true of the scripted tests that will be used for
assessment. These allow input to be generated that is not in the form the front-end client may usually
generate. This is part of what you need to defend against.
3.1.1 login
Expects username and password, validates these to generate a session token (magic).
{“username”:”…”, “password”:”…”}
You must support the login of the users defined in the database. This is dealt with in handle_login_request().
An attempt to login should be rejected with a suitable error message if the password does not match. If the
password does match, all existing sessions for this user should be ended and be replaced with a new one. A
magic session token should be generated that will be passed to the client via cookies and will be returned
with each /action request. This will be used to validate access to other actions. A reminder that in this and
other tasks you should defend against malicious inputs. Multiple users may be logged in at once. The magic
session token should be unique for each session, for each user.
The client will record the returned session userid and token and supply this with all remaining command
requests. A successful login should return a redirect response to index.html. An unsuccessful login should
return an appropriate message response.
In all other future ‘/action’ requests, the token must be validated and the command must only be
successfully executed when a valid user is identified by a valid session token. Where a valid token is not
present or does not indicate a valid user a redirect response to the /login.html page should be returned for
the request.
3.1.2 logout
Logs the user out of the current session, ending it. No parameters.
When the cookie input matches an existing session, the session should be ended. This is done by deleting the
session record from the session table. A redirect response to the /logout.html page should be returned.
Where the cookie input does not match an existing session a redirect response to the /login.html page
should be returned.
3
3.1.3 get_my_skills
No parameters expected.
This request should return a set of skill responses for the logged in user. For any skills for which the user is an
attendee in a class, the list should begin with one entry for each skill for which the user is marked as ‘passed’
as an attendee. This should be followed by an entry for each skill for which the user is marked as ‘enrolled’
and the start time/date has passed and marked as ‘pending’. This should be followed by the most recent
entry for each skill for which the user is marked as ‘failed’ and does not have an entry for the same skill
marked as ‘passed’ or ‘pending’. Entries recorded as ‘cancelled’ or ‘removed’ should not be included in the
response.
Where a user has an entry in the trainer table for a skill, that skill should not return ‘passed’, but instead
return ‘trainer’.
If the user is not logged in, only a redirect to the login page must be returned.
3.1.4 get_upcoming
This request must return a class response for each class for which the start time and date has not passed.
These should be sent in timestamp order, soonest first. The action should be as follows:
1. Entries for which the user is the trainer should have an action of ‘edit’.
2. Where the user has enrolled in the class and the start time/date has not passed they should have
the option to ‘leave’.
3. Where the user is not currently enrolled in the class and has not been removed from it, they are
permitted to ‘join’ this class. Provided that they do not already attending a class with the same skill
where the state is ‘passed’ or ‘enrolled’. This includes if they have previously cancelled.
4. If the user is already signed up to another class with the same skill as this class should show as
‘unavailable’.
If the user is not logged in, only a redirect to the login page must be returned.
3.1.5 join_class
Parameter object: {”id”: classid}
A user may join a class, so long as there is space and the class is not ‘unavailable’ to them. In which case the
class size will be increased by one. Note that the current class size is not recorded in the database, only the
maximum class size. The current size must be calculated using the attendee table in the database.
The may also only join a class when they are not already recorded as being an attendee for a class for the
same skill, when the state is ‘passed’ or ‘enrolled.’ They may not join this specific class if they have been
removed from it. But are permitted to join another class for the same skill.
If the user is not logged in, only a redirect to the login page should be returned.
3.1.6 leave_class
Parameter object: {”id”: classid}
4
A user may leave a class in which they are ‘enrolled’ if the start time/date has not passed. In which case an
updated class response should be returned.
If the user is not logged in, only a redirect to the login page should be returned.
3.1.7 get_class
Parameter object: {”id”: classid}
If the user is not the trainer for the class an error message should be returned.
If the user is the trainer of the class a class response and all required attendee responses should be sent.
If the user is not logged in, only a redirect to the login page should be returned.
3.1.8 update_attendee
Parameter object: {“id”:attendeeid, “state”:”pass/fail/remove”}
If the user is the trainer for the class indicated by the attendeeid, and the start date/time has passed and the
state is ‘pass’ or ‘fail’, the state should be updated to ‘passed’ or ‘failed’ respectively. An attendee response
will be required to reflect the new state.
If the user is the trainer for the class indicated by the attendeeid, and the start date/time has not passed and
the state is ‘remove’, the state should be updated to ‘removed’. An attendee response will be required to
reflect the new state. As will a class response.
If the user is not logged in, only a redirect to the login page must be returned.
3.1.9 cancel_class
Parameter object: {”id”: classid}
If the user is the trainer for the class indicated and the start time/date has not passed, the class and all
attendees currently shown as ‘enrolled’ should be marked as ‘cancelled’. The max of the class should be set
to zero to indicate a cancelled class. Updated class and attendee responses must be returned. Only for those
attendees whose status has changed.
If the user is not logged in, a redirect to the login page must be returned.
3.1.10 create_class
Parameter object: {“id”: skillid, “note”: “…”, “max”:max, “day”:day, “month”:month, “year”:year,
“hour”:hour, “minute”:minute}
If the user is a trainer for the specified skill, then they are able to create a new class. The components of the
date and time are given as integers and need to be checked for validity. E.g. the 30th of February is not a valid
date. And 03:82 is not a valid time. And must be beyond the current time and date. The maximum class size
must be in the range 1 to 10. Classes must only be created for valid skills.
5
If the class is successfully created, a redirect response should be returned to ‘/class/classid’ where classid is
the newly created database entry for the class.
If the user is not logged in, only a redirect to the login page must be returned.
response = []
response.append(build_response_...(…))
response.append(build_response_...(…))
…
Response: redirect
{“type”:”redirect”, “where”:”…”}
The redirect response indicates the client should load the page specified by the where entry. It is used when
the server wishes to change the page displayed.
Response: message
{“type”:”message”, “code”:…, “message”:”…”}
A message response tells the frontend if the requested action was successful or if not indicates the nature of
the problem using an integer code value. It also returns a human readable text message. The supplied
frontend displays these when a response is processed. Where you are required by this specification to return
a message, you should use codes according to Table 1. Where a range of codes are given, you are free to
choose any value in that range. This may assist you in debugging.
Response: class
{“type”:”class”,”id”:…, ”name”:”…”, “trainer”:”…”, “notes”:”…”, “when”:…, “size”:.., “max”:, “action”:”…” }
This response is provided to the index.html and class pages. It contains the general details about a class. The
action will control the button/label options presented to the user.
6
notes A note added by the trainer when the class was created.
when The start time/date of the class. (Unix timestamp.)
size The current number of attendees in the class (those not cancelled or removed.)
max The maximum permitted number of attendees or the class.
action “join” – This user is permitted to join this class. This includes if they have previously
left, but not if they were removed.
“leave” – The user has enrolled in the class and is permitted to leave it. You cannot
leave a class after it has started.
“pending” – The user is enrolled in the class, and the start time/date has passed.
“cancel” – The user is the trainer and permitted to cancel the class.
“edit” – The user the trainer and permitted to edit the class.
“cancelled” – A class has been cancelled by the trainer or the current user has been
removed from the class and is not permitted to join the class. You cannot re-join a
class once it has started.
Response: attendee
{“type”:”attendee”, “id”:…, “name”:…,”action”:”…”}
The frontend will ask for these when it wishes to display a class details page, ‘/class/…’. The fields should
contain the following information. They will also be supplied by the server when a currently displayed
‘/class/...’ page is updated.
Response:skill
{“type”:”skill”, “id”:…, “name”:”…”, “trainer”:”…”, “gained”:…, “state”:”…”}
The frontend will ask for these when it wishes to display a user skills page. The fields should contain the
following information.
7
“pending” – The user is marked as enrolled in a class and the start time/date has
passed.
“passed” – The user is marked as passed in a class of this skill. This takes precedence
over other options.
“failed” – The user is marked as failed in a class, and there is no other enrolled or
passed entry.
4 Database Schema
The database schema is provided and contains five tables. Your application should maintain these tables.
You cannot alter the definition of these tables or add additional tables as the database will not persist
between tests. Your server should assume the database exists when it starts and will be in database.db in
the current working directory.
To simplify the development and debugging process, the password will not be encrypted. This is bad practice
and is only being done to allow visibility of the passwords in the supplied databases to reduce development
effort of the coursework. If you ever need to write such code in the future, please don’t do this.
Access to the application is controlled by the username/password pairing. Each user is also assigned a
unique integer ID that is used to identify their entries in the other tables. You must not change the contents
of this table during start-up, doing so will likely result in failures during testing.
Each user login session is recorded in the session table described in Figure 3. This records all active sessions.
The magic value should be a unique string that cannot be easily guessed for each session. It is equivalent to a
per-session password and used to ensure only the correct user can access a session. A given user may have
multiple active sessions.
Note, the last statement can be true even if your server never allows two login sessions in the server as the
database may have entries created by other database activity outside the server.
8
4.3 Table: skill
skillid INTEGER PRMARY KEY A unique, non-zero integer that identifies this
record.
name STRING NOT NULL The name of the skill.
Table 4: skill sql table
The skill table provides a mapping between skill names and a unique integer identifier for the skill. You must
not change the contents of this table during start-up, doing so will likely result in failures during testing.
This table holds a record of which skills a user is permitted to teach. You must not change the contents of
this table during start-up, doing so will likely result in failures during testing. Note that this table does not
have a primary key, it is used only to link the user and skill tables together for those users who are allowed
to run classes.
9
5 The Assessment Process
The total marks available for this assignment are 100%.
1. A copy of an sqlite3 database that contains the specified tables and a know state is copied into
the working directory. It will be called database.db and this is the file that should be used by
server.py.
2. The server.py Python program will be run with a port number argument.
3. A python test function will make several requests to the server and check the values returned.
4. The server program will be terminated.
5. Optionally, the database.db file may be checked to ensure it has been updated as expected.
The full test suite contains a series of tests, providing coverage of the API. The tests all have equal weight
and account for 90% of the overall mark.
To assist you in checking that your server operates correctly within this testing framework a version of the
regression test suite has been provided that contains a sample test. This will allow you to ensure you have
not made changes to the way the server is expected to behave that will make it incompatible with the
regression suite. You are encouraged to test your code with this method as well as using the supplied front-
end. You are free to add additional tests to the test script but these will not form part of the assessment and
you are not expected to submit them.
You will provide the following by the initial project submission deadline, uploaded to moodle.
This is the only file needed. Do not upload any other files and you must not submit it within a zip or other file
format. You cannot spread your code across multiple files.
After the initial deadline, a copy of the regression test suite will be released. At the same time as the
lecturers are running you code against the suite, you will have the opportunity to make any corrections
require to your code.
You may then upload the corrected version of your code moodle. This second version of the code will be run
against a second, similar, test suite. Where similar means the test functionality will be the same, but the data
may be different. If your new regression score is larger than the old one, you will gain 20% of the difference.
For example, if your initial submission scored 65% and your revised submission scored 90% then you would
gain 20% of 25% or 5% giving you a final mark of 70% for the tests.
10
7 Supplied Files
The following files are provided for the project phase:
server.py The Python server code. This is the file to which you will add your code.
pages/* All the html pages delivered by the server live in this directory.
index.html The frontend main page (html). You should not modify this. When logged in
it is intended to show upcoming training classes.
skills.html A frontend page (html) that shows the skills for which a user has or is due to
get. You should not modify this.
class.html A frontend page (html) that shows the details of a class. You should not
modify this.
create.html A frontend page (html) that shows the class creation form. You should not
modify this.
login.html The frontend login page (html). You should not modify this.
logout.html The frontend logout page (html). You should not modify this.
menu.html The frontend menu page (html). You should not modify this.
css/* The frontend cascading style sheet for the html pages (css). Uses bootstrap. You should not
modify this.
js/* The frontend javascript code makes AJAX requests to the server and process the responses.
You should not modify this.
db/* A place where databases can be stored. One of these should be copied to database.db in the
parent directory for use. Do not access these files directly from this location in your server.
database.db This version here contains initial sqlite3 tables for reference.
9 Plagiarism
In line with the University expectations on academic integrity, the work you submit for assessment must be
your own. This means that any added or modified code in server.py should be created by you. The nature of
this task is such that you are not likely to find any existing solutions on the web. You can discuss your
coursework with your peers; however, you must be careful that this does not become collusion. This means
that you can discuss the concepts involved but should not be sharing code or co-developing.
Your submitted code will be run through a tool that can perform pairwise comparison of all submissions to
detect sharing of code. This tool does more than compare text. It understands the Python language and is
11
able to detect similarity even when superficial (to the computer) changes such as re-naming variables or re-
formatting/re-ordering of code is performed. Any code flagged as similar will then be reviewed by the
lecturer and where appropriate reported to the Director of Studies.
KMC2023
12