CS1999 Project task list

Phases and tasks

You should work on your project in phases, completing every task in each phase before moving on to the next. Apart from phase 0, you can tackle the tasks within each phase in any order you like.

If you're not an experienced programmer, we don't expect you to get much further than phase 3 before you run out of time.

You must implement each phase completely, before moving on to the next.
You're free to implement each task as thoroughly as you require.

Phase 0 tasks

0-GET Get the source code

The starter source code for the buggy editor app you're going to be developing already exits in your GitLab repository: you just need to clone it to a place where you can edit it and run it.

  • If you are working on your own laptop, ensure you have read the CS1999 prerequisites instructions on the CS1999 Moodle page and installed the necessary software. If you are working on a machine in Bedford labs, don't worry, everything is already installed for you.

  • Go to your your GitLab repository and create a new Personal Access Token by clicking on your avatar at the top of the the left hand sidebar, selecting Preferences and then Access Tokens. Keep the default expiry date and tick the checkbox next to write_repository. Keep this browser tab open as you will need to copy your Personal Access Token later on.

  • In a new browser tab, navigate to your GitLab repository again. You should see a repository named buggy-editor. Click on the blue Code button and select Visual Studio Code (HTTPS). This will open the Visual Studio Code application and start cloning the buggy-editor code. Accept any popups that appear.

  • When prompted to select a location for the clone in the Select as Repository Destination window, choose your Home Directory (H:) if you are working on a Bedford lab machine, or choose a directory on your laptop (e.g. your "Documents" folder). Click "Accept" and select "Yes I trust the authors".

  • Close the "Welcome" tab

  • You should see a number of files in the left hand Explorer pane, including a file called app.py. Click on app.py and select to Install the Python extension to VSCode. If a popup appears asking to Allow public, private and domain networks to access the App then select No .

  • When prompted to create a virtual environment say "no"

  • If you are prompted to enter your GitLab credentials, enter them but remember the password will be the token you created at the start of this task (NOT your RHUL password!)

  • Close any further Welcome pages which appear.

  • Well done, you have complete task 0-GET! Now record your notes about how you completed this task by clicking on the "Add text" button next to this task - this will make generating your poster for your final deliverable much easier!

Remember to add a text for 0-GET for your report (you can edit it later).
  • If you're not comfortable finding your way around the file system yet, see the CompSci superbasics.

0-RUN Get app running and view it in a browser

You need to be able to deploy the buggy editor so you can see it running in your web browser. The buggy editor is written in python and runs in the Flask web server. You can see the code for the web server in the file app.py.

The Buggy Editor Python code has dependencies on a number of libraries. The dependencies are documented in the requirements.txt file. If you have developed other Python code on your machine which requires specific versions of libraries to be installed via pip, you may want to do the installation using virtual environments. If you have never used pip before then don't worry, just go straight to the instructions below.

Instructions for Mac Users:

  • Open a terminal window in VSCode by selecting Terminal->New Terminal

  • Install the library dependencies by running pip3 install -r requirements.txt in the terminal.

  • Set up the SQL database needed by the buggy editor app by running python3 init_db.py. This should create an SQLite database in a new file named database.db.

  • Run the Buggy Editor using python3 app.py. The buggy editor will run as a webserver on port 5000 (the default port for Flask apps). You should be able to see it running by typing http://localhost:5000.

Instructions for Windows Users:

  • Open a terminal window in VSCode by selecting Terminal->New Terminal

  • Install the library dependencies by running pip install -r requirements.txt in the terminal.

  • Set up the SQL database needed by the buggy editor app by running python init_db.py. This should create an SQLite database in a new file named database.db.

  • Run the Buggy Editor using python app.py. The buggy editor will run as a webserver on port 5000 (the default port for Flask apps). You should be able to see it running by typing http://localhost:5000.

Remember to add a text for 0-RUN for your report (you can edit it later).
  • If you get an error indicating that something else is running on port 5000, you will need to use a different port (e.g. 5001). To do this, you can specify the alternate port in an environment variable called CS1999_PORT. To do this, create a file called .env in the same directory where app.py lives and add the following to the .env file:

    CS1999_PORT=5001

Understanding environment variables will help you in task 3-ENV where you'll investigate ways to switch from development to production environments.

  • When you first run app.py you'll get the / route. By looking in app.py, you can see it invokes the index.html template.

  • Read more about how Flask work by looking at the tech notes.

  • You can see the webserver's activity in the terminal, and the result of its actions in the browser.

  • When you want to stop the program running, press Control-C in the terminal where the webserver is running. This interrupts the server and halts the execution of the program. If you go to http://localhost:5000 in your web browser now, you'll see a message saying you can't connect to the server. This is because you've killed it: it's no longer there.

0-CHANGE Make a change to a template and see it appear

In Flask, you can use the Jinja templating language to render an HTML page when a user makes a request. Jinja allows you to create templates with static HTML and dynamic features such as if statements and for loops.

In this task must demonstrate that you can change a Flask template so the change appears in the browser.

  • Edit some text in templates/index.html.

  • Confirm you see the changes when you hit the corresponding page in the browser.

  • Record your notes about how you completed this task by clicking on the "Add text" button next to this task - this will make generating your poster for your final deliverable much easier!

Remember to add a text for 0-CHANGE for your report (you can edit it later).
  • Read more about how templates work by looking at the tech notes.

  • If you change the template but the page in the browser does not change when you refresh it... what might be happening? What can go wrong here?

  • Don't underestimate the importance of doing a simple change to the template before adding more complex logic!

Phase 1 tasks

1-TEMPLATE Add a new template and route to the app

Building a buggy is expensive! The cost of buggy components is currently only available on the Race Server.

We need a way to return the cost information to the Buggy Editor user when they request it.

  • Create a new template (templates/info.html) to display the cost information which your app will render when /info is requested. Take a look at the "Helpful hints" below to decide how you will do this. Make sure you extend the "base.html" in info.html as mentioned in the Phase 1 Tech Notes.

  • Your webserver uses routes to choose which function to run to generate a response to a request. You can see that in app.py there are already a number of routes (e.g. @app.route('/buggy')), each of which renders a template, which results in HTML being sent back to the client (browser). Create a new route that matches /info to render the template info.html.

  • Record your notes about how you completed this task by clicking on the "Add text" button next to this task - this will make generating your poster for your final deliverable much easier!

Remember to add a text for 1-TEMPLATE for your report (you can edit it later).

There are a number of options for retrieving the cost data from the Race Server, ranging from simple to more complex. These are described below. Choose whichever option you feel confident with.

  • You could add a link to the specs page on the race server

  • You could copy the information you need from the race server and put it into the template by hand, one part at a time.

  • You could copy and paste the relevant parts of the HTML source code from the specification page on the race server into your template.

  • You could also obtain the data in tabulated form or as JSON and read it from a file on the server. This is a better solution to hard coding values in Python or the template but more tricky. If you do it this way, you need to decide when to read the file; your decision will depend on how efficient you need your program to be. You can use the Python requests library to fetch the JSON from the specs page on the Buggy Race Server.

  • Need more help? We have a video to help you with this task.

1-ADD Add more data to the form and save it to the database

The only data being collected by the buggy-form is the number of wheels. You need to add more fields to allow the user to "power up" their buggy with extra features such as those specified in the Buggy Specifications.

  • Start by adding the flag_color to the buggy-form.html template. Investigate HTML tags for accepting data in forms: in particular, consider how radio and select might help you.

  • Look at how the /new route in app.py retrieves the number of wheels and saves this information to the database, follow this pattern for retrieving and saving the flag_color.

  • The database definition is held in init_db.py. It holds the column name (and type) for each item. We've helped you by including the flag color in the database definition so the column already exists.

  • Make changes to buggy.html to display the flag-color.

  • Once you have successfully saved the flag colour, try adding support for another buggy feature that isn't already in the database. This is more tricky as you will need to add a new column in the database for this item.

  • Record your notes about how you completed this task by clicking on the "Add text" button next to this task - this will make generating your poster for your final deliverable much easier!

Remember to add a text for 1-ADD for your report (you can edit it later).
  • Refer to the Phase 1 Tech Notes for a step by step guide to completing this task

  • If you receive an "Error in update operation", when you try to save data, check the relevant Tech Notes to help you identify the cause of the exception.

  • Need more help? We have a video to help you with this task.

1-VALID Add basic data validation

If you enter "banana" for the number of wheels when making a buggy, you should get an error.

  • Add server-side data validation to the /new route in app.py - your code should check that the data sent by the form for the number of wheels is an integer and reject it with a warning if not.

  • You can also do client-side validation in JavaScript. What's the difference? Why isn't only using client-side JavaScript validation acceptable?

  • Record your notes about how you completed this task by clicking on the "Add text" button next to this task - this will make generating your poster for your final deliverable much easier!

Remember to add a text for 1-VALID for your report (you can edit it later).
  • The incoming data is always a string, so maybe use the isdigit() method.

  • Do you need to "clean" the string first? Python has a strip() method which strips off all leading and trailing spaces

  • What are you going to do if the data is bad?

  • There's more than one way to pass the error back to the user... how are you going to do that? What should appear on the webpage?

1-STYLE Style your editor just how you like it

Your editor looks identical to the basic one. Can you make it look prettier?

  • Use CSS and HTML to make it look beautiful and different from everybody else's. If you haven't used CSS before, don't worry, just choose to do something simple like changing the colour of the text.

  • Record your notes about how you completed this task by clicking on the "Add text" button next to this task - this will make generating your poster for your final deliverable much easier!

Remember to add a text for 1-STYLE for your report (you can edit it later).
  • You can change the HTML as much as you need to get the look/layout you want, but be careful — remember the separation of concerns. This means your HTML should really only be describing the content of your web pages, while the CSS deals with its presentation. It's common to use the class attribute as the bridge between the two.

  • Your editor is already using a style sheet — it's in static/app.css — so you should probably edit that (at least to start with).

  • If you make changes to the stylesheet but your browser doesn't appear to load it (but keeps using the old one) you might need to empty your browser's cache. See the CS1999 tech notes.

  • If you want to add images, those should probably go in the static directory (the same place as the CSS). Make sure the file size of any images is as small as possible. Why?

  • No matter how pretty, how beautiful, how fabulous you make your editor, remember that you must not compromise its usability or accessibility.

  • For example, never put text directly on top of backgrounds that make it hard to read or distinguish. Make sure things the user should interact with look different from things they cannot. Consider how your site works in different form factors.

  • There are guidelines for calculating acceptable contrast between text/background colour combinations.

  • Accessibility is a big topic that is integral to web design. See MDN on accessibility for a good starting point. If you have any aspirations as a web developer, you have professional, ethical, and legal obligations to understand how to do this well.

Phase 2 tasks

2-EDIT Allow for editing of a buggy by preloading its current values into the form

As we only have one buggy, we could use the buggy-form.html template to allow both creation and editing of a buggy. This means we need to display the current values of the buggy when the user navigates to "Make Buggy".

  • When you choose to make a buggy, you should see the existing buggy's current values displayed from the database.

  • Record your notes about how you completed this task by clicking on the "Add text" button next to this task - this will make generating your poster for your final deliverable much easier!

Remember to add a text for 2-EDIT for your report (you can edit it later).
  • This task should be completed in the/new route in app.py.

  • You need to read the values for the existing buggy record out of the database with SQL SELECT. Take a look at the show_buggies() method in app.py, this illustrates how to retrieve the buggy data from the database.

  • Use the HTML input tag's value attribute to display the returned buggy information in the buggy-form.html template.

  • If you have used an HTML select tag for other buggy data such as the flag_color you will need to handle select tags' option values differently: you'll need to use the selected attribute too, combined with Jinja if statements.

  • Be careful about values that might contain characters that break your HTML when you put them inside attributes in your template. How can you protect against problems?

2-COST Calculate and save the game cost of the buggy

The cost of the buggy (worked out using the game rules) affects whether it can be entered in some races. Add the cost to the database and display it in the buggy.html template.

  • Add a new integer column called total_cost to the buggies database table, and store the total cost there.

  • Edit the buggy.html to include the cost of the buggy.

  • Record your notes about how you completed this task by clicking on the "Add text" button next to this task - this will make generating your poster for your final deliverable much easier!

Remember to add a text for 2-COST for your report (you can edit it later).
  • You could choose to calculate the cost by hardcoding the costs of each component in app.py. This is the simplest solution however there are some downsides to this, what do you think these are?

  • Extension Task: You could use the Python requests library to fetch the JSON from the specs page on the Buggy Race Server. This option is more challenging but has the advantage of the data always being up to date. If you choose to do this, you can access individual item costs in a similar manner to the following:

``` buggy_json = requests.get(spec_url).json()

# example of retrieving the cost of the tyres tyres_cost = buggy_json['tyres'][request.form['tyres_type']]['cost'] * int(request.form['qty_tyres']) ```

2-RULES Add validation according to the game rules

There are some configuration options that are not allowed (for example, the quantity of wheels must be even).

  • Add the game rules to your validation

  • Record your notes about how you completed this task by clicking on the "Add text" button next to this task - this will make generating your poster for your final deliverable much easier!

Remember to add a text for 2-RULES for your report (you can edit it later).
  • The game rules are the "must haves" in the "Description/rules" column

  • You'll need to do some validation based on more than one field too (for example the number of tyres cannot be less than the number of wheels).

  • If your buggy editor doesn't yet support some of the items you are applying rules to then you may want to add them in so you can test your rule logic. Use the hints in 1-ADD to help.

  • How and where are you going to report the problems?

  • Do you save the record anyway, even if there are violations?

  • If the game rules changed, what would you need to do to your program?

Phase 3 tasks

3-ENV Switch between development and production environments

When you run your editor, it's always in debug mode (because the keyword argument debug=True is being set when app.run() is called, at the bottom of app.py). Debug mode picks up any changes you make to the code immediately which is very useful for debugging but would not be ideal in a real production environment!

So debug mode should only be enabled when you run your editor in a development environment.

An environment variable is a variable whose value is set on the command line, outside of the running application, typically through functionality built into the operating system. An environment variable consists of a name/value pair, for example FLASK_DEBUG=true.

Change your program to use the environment variable FLASK_DEBUG to switch debug mode on and off, instead of being hard-coded in the source code.

Remember to add a text for 3-ENV for your report (you can edit it later).
  • To create an environment variable for FLASK_DEBUG and set its value to False, stop your Flask server and go to the Terminal window:

  • If you are working on a Mac type export FLASK_DEBUG=False

  • If you are working on a command prompt terminal, type set FLASK_DEBUG=False
  • If you are working on a Powershell terminal type $Env:FLASK_DEBUG = 'False'

  • Now change your app.py code to retrieve the value of this environment variable using os.environ.get('FLASK_DEBUG'). Assign this to a variable and use this variable as the value of debug in the app.run line of code. If everything has worked correctly, when you restartapp.py you should see Debug mode: off.

  • Now stop the Flask server and change the environment variable back to True. When you restart app.py you should see Debug mode: on.

  • This task is really introducing you to the important concept of environment variables — these are settings that are part of the environment in which the program runs instead of being inside the program. All general programming languages provide a mechanism for accessing these from within a program's source code.

  • The main advantage of switching between development and production environments in Flask is that in the development environment the webserver should "notice" (and reload) changes to the files, so you don't need to stop-and-start the webserver every time you make an edit. But it also affects the way errors are displayed in the browser — Flask's debug mode will show a stack trace and detailed diagnostic information, instead of a bare status-code 500 error page.

  • Setting debug=True in the source code is just one example of how some settings should not be hard-coded. Other classic examples, for programs in general, are configuration settings and passwords. This is really about understanding what is the same and what is different when you run different instances of your program. This is especially important when you think about how source code is shared, and what should (and should not) go into version control.

3-AUTOFILL Add auto-fill to the buggy form

In earlier tasks you added items to your buggy form. However, the user may not want to manually input values into each field when creating a buggy. It would be good to auto-populate any empty fields with values to create a buggy.

  • The Buggy Specifications & Race Rules page lists all the possible items on a buggy alongside the set of default and possible values.

  • Add a button that automatically inputs values for any field that has not been filled in by the user in your buggy-form.html. Maybe you will just use the default values defined in the buggy specification page, or perhaps you can ask for a cost limit when the button is pressed, and try to add items so that the buggy's total cost is within that limit. This will be useful when we run races which have a maximum buggy cost limit for entry!

Remember to add a text for 3-AUTOFILL for your report (you can edit it later).
  • You can do this server-side (in app.py) or client-side (with Javascript) - consider the pros and cons of each.

  • If you are doing this client-side with JavaScript, you could create a JavaScript function that uses the getElementById function to retrieve each field in the form individually by its id and set its value. For example: document.getElementById("qty_wheels").value = 4 will populate the field with the id of qty_wheels to 4. Note that the id attribute of an element is different to the name attribute so you will need to ensure that each field in your form also has its id attribute set. You can then add a button to the form that calls this JavaScript function when the button is clicked.

  • If you are doing this server-side in app.py, you can add another button to your HTML form. HTML supports forms having more than one submit button and you can detect which of the two (or more) buttons the user pressed provided you give them different names using the name attribute. This is the same attribute that you are already using to distinguish between other inputs use in the form. Then, in app.py, when the form comes in you can test to see for the presence of those (only one will have data that is not empty) using if request.form.get("name") where name is whatever name you gave the button that was clicked.

  • To generate the random buggy configuration, you might need to randomly choose values: see Python's random library and perhaps its randint function (or JavaScript's Math.random()).

  • If you don't try to make autofill work within a cost, this task is a lot simpler - then it's really just loading a set of pre-defined values. That's not so helpful for the user though.

  • If you try to make autofill work within a specified cost, this can become a very difficult problem. How do you decide what values to pick for each setting? Sometimes it might be impossible to make a legal buggy within the stated cost. How will you know? How will you report that to the user?

3-MULTI Allow different buggies to be created

The default app only lets you save one buggy. You should be able to save different buggies so you can switch between them.

Modify the app to create a new buggy and subsequently update it, and to provide a way to switch between the different buggies you've created.

Remember to add a text for 3-MULTI for your report (you can edit it later).
  • This is part of the classic set of CRUD operations: it is not a small change.

  • Note that we've moved deleting into a separate task (3-DEL).

  • You'll also need to manage a way to select which buggy you are editing or deleting — offer a list to choose from, perhaps?

  • You're going to need to change the operation on the database, because up till now you've been updating the (single) record in the database: now you will sometimes be inserting a (new) record. How will you decide which to do?

  • When you create a new buggy, it will be given a new id because the database assigns an auto-incrementing integer. How do you determine what that id was? Why does it matter?

  • Once you've created a buggy, you'll need to specify which buggy a request relates to... you do that in Flask by incorporating its id into the route.

  • The following videos are very good at explaining how to approach this task: Part 1 (UPDATE to INSERT), Part 2 (Editing the Record), Part 3 (Make vs Edit), Part 3.5 (Make vs Edit Extra), and Part 4 (Hiding the ID).

  • If you need help with the SQL to get the database operation to work, ask for help (SQL is not a one of the core components of this project).

3-DEL Allow buggies to be deleted

You have multiple buggies: you should be able to delete ones you don't want.

Add a delete route to remove a buggy.

Remember to add a text for 3-DEL for your report (you can edit it later).
  • This is one of the CRUD operations: see the mutliple-buggy task (3-MULTI) too.

  • You should put the id of the buggy you're deleting in the route.

  • You almost certainly need to use the WHERE clause in your SQL. What happens if you don't?

  • It's good practice to use the HTTP method DELETE here (or perhaps POST, but DELETE is better).

  • More importantly, you should not use the HTTP method GET for this route. Why not?

  • Have you just made it possible to delete all the buggies? Is that OK? Does your editor still work if you have no buggies in the database?

  • Does this change anything about what init_db.py should do?

3-FLAG Display the pennant graphically

The user's choices for the colours and pattern of the buggy's pennant (flag) is visual information but is probably displayed as text.

Show a graphical representation of the pennant in the browser.

Remember to add a text for 3-FLAG for your report (you can edit it later).
  • There are several of ways of doing this: but you can't simply have pre-prepared graphics for every possible flag because there are too many combinations.

  • Are you going to display the pennant before or after the form is submitted? (Both are OK... but what difference does your decision make? Is this client-side or server-side?)

  • There are number of ways you might go about implementing this without needing to create a separate image file (which we recommend against). Consider using CSS, SVG, or canvas to paint the flag (a small rectangle would be fine). What are the pros and cons of the different approaches?

  • W3Schools have tutorials for both SVG and canvas.

  • Remember that the colours are specified in a very specific way: as CSS colours.

  • What happens if a colour has been badly specified? Is it dangerous to try to display it?

  • The tricky bit is creating the visualisation for each type of pattern. Our advice would be to remember that the patterns are a group of repeating elements.

3-TESTS Write some tests

You should be able to run automatic tests that confirm your app calculates the cost correctly... as well as other things too.

You probably know your app works because you've been running it (and playing with it) as you go along. But you should write some automated tests.

Remember to add a text for 3-TESTS for your report (you can edit it later).
  • Testing is a big topic!

  • The idea is that you can run the same tests repeatedly, and get the same results every time. This way, if you make any changes to your code — adding a new feature, for example — you can be confident it does what you intended it do and it doesn't break anything that is already working.

  • There are two common types of tests: unit tests and integration tests.

  • Unit tests are used to check that single, individual operations do what they should.

  • Integration tests are used to check that things are working together properly.

  • We suggest you start with unit tests. If you haven't already, you will need to refactor your code so you have a separate function for calculating the cost. The advantage of this is that you can then test this function in isolation from the rest of your code.

  • Python has libraries to make it easy to write unit tests, we suggest you use pytest. The documentation describes how you assert that what should happen, is happening.

  • Consider which tests are worth testing: be smart and effective with your choice of tests.

  • If an application contains tests, it is common practice to include instructions in the README which describe how to run them.

  • Testing the front end (i.e., the interface behaviour in the browser) is harder, but it can be done. What tools are available for testing?

Phase 4 tasks

4-API Use the server API for submitting the buggy data

Manually copying the JSON data from the editor to paste into the race server is clunky - use the buggy submission API instead.

Implement an upload to server feature for a selected buggy.

Remember to add a text for 4-API for your report (you can edit it later).
  • You need to supply the API with specific data including a key which you can find in your API settings. Note that the user is your username (in lowercase) that you use to login to the Buggy Race Server.

  • You may want to test the API using curl before you incorporate the code into your buggy editor.

  • You'll need some way of storing your authorisation data; however, you should not hardcode this information into your code. Why should you not do this? What would be a good way to pass the information in to your app?

  • This task can either be done in the frontend (using JavaScript) or in the backend (using Python).

  • If you complete this task in the backend, you'll need to import the requests library in order to construct the POST request used to submit the selected buggy to the server. Note that the requests library is a different library to the request library provided as part of the Flask framework. A Flask request object contains the data that the client (for example, a web browser) has sent to your app's backend. Meanwhile, the requests library allows your app to make HTTP requests to other sites, usually APIs.

4-USERS Add users (and sessions) so you know who is editing a buggy

Anyone can access your app and edit a buggy: ultimately only the person who created it should be able to. Add a login mechanism so you can tell the difference between users.

Add usernames to distinguish between users, and a mechanism for starting and ending a session (such as logging in and logging out).

Remember to add a text for 4-USERS for your report (you can edit it later).
  • This task is really about implementing login sessions. See also make a new user (4-REGISTER) and add passwords (4-PASS), which are related.

  • It is possible to implement user sessions without having any users in the database: just by inviting the user to type any username and keeping that for the session (that is: you could implement this without a database). That is, this is really about starting, maintaining, and ending a session. Here's the official Flask example that implements that.

  • Do not focus on implementing user registration and password checking just yet. These will be done in 4-REGISTER and 4-PASS.

  • The most common way sessions are implemented is with cookies, which are tokens the server can use to recognise when requests are coming from the same client (browser). That's how Flask is doing it too. If you use your browser's developer tools to find the cookies, you can see how they change between requests as you use your app.

  • Remember to provide a way to end a session (i.e. log out) as well as starting it.

  • To get this working with a database, add a table called users and manually create users directly in that (or maybe create them in init_db.py or a script like that). But see the new-user task (4-REGISTER) for doing it from within the app itself.

  • See the new-user task (4-REGISTER) task for more hints about the user table in the database.

  • You should also ensure that users cannot bypass the login mechanism by simply accessing a restricted page by entering an URL in the browser. For example, a user should not be able to go to http://localhost:5000/new and attempt to create a new buggy without logging in first. Instead, the login form should be displayed.

  • Note: there is a library called flask-login that can you can use, but we think that is overkill for this project. It's probably better (and more interesting) to build your own simple login mechanism. To be clear: flask-login can solve this problem, but it comes with quite a lot of extra dependencies and complexities. If you've used it before, you're welcome to dive in with flask-login if you want... but it's certainly not a requirement.

4-REGISTER Make a new user

Make it possible to create a new user to use when logging in with user logins (4-USER).

Make a registration (or sign-in) page with a form for creating new users.

Remember to add a text for 4-REGISTER for your report (you can edit it later).
  • The page presumably needs to collect information needed for the user record. What fields do you need?

  • If you were going to run your editor as a service - that is, genuinely invite people to register as users - you would need to be aware of your responsibilities under the UK GDPR. If you collect information about individuals for any reason other than your own personal, family or household purposes, you need to comply with the GDPR. That basically means you declare what personal data you collect, what you will use it for, and that you must keep it safe.

  • You can register users without any additional authentication. In this case maybe you also grant them a login session as soon as they have submitted?

  • It's common to use a table called users.

  • If you're using SQLite in development mode, you'll probably need SQL to CREATE TABLE users with an auto-incrementing primary key id and string (VARCHAR()) field username

  • What's the advantage of using an id as the primary key instead of the username (after all, you know username has to be unique)?

  • What happens if someone tries to register a user with a username that already exists? You will will need a mechanism to stop this from happening.

  • You could use the UNIQUE keyword for the username and email fields in the users table. This will stop a record from being added if it has a username or email address that is already in the database. How would do you know this has happened?

  • If you're thinking about passwords too, we've added that as a separate task (4-PASS). If you're coding this from scratch, it might be a good idea to implement user and session first and then add passwords (why?).

  • Task 4-USERS only really needed a username field in the login page. Once you have set up logging on with a username and password, you will need to update the login form. You can either do this now or when completing 4-PASS.

4-OWNER A buggy belongs to a user

Any user can edit any buggy. Only the buggy's creator should be able to edit (or delete) it.

Associate buggies with a specific user and only grant access to buggies to the logged-in user.

Remember to add a text for 4-OWNER for your report (you can edit it later).
  • Maybe add a user_id column to the buggies table for the user's id - this is a foreign key.

  • Ensure you use the foreign key in the WHERE clause of SELECT statements.

  • Remember to always set the user_id column when you create new buggy records.

  • Should user_id appear in the HTML form when creating a buggy? What about when editing it? Perhaps you could use a type="hidden"? What's the problem with that?

4-PASS Add password protection to the users

Anyone can login as any user they like... unless there is a password on user accounts.

Set and store a password for each user.

Remember to add a text for 4-PASS for your report (you can edit it later).
  • You need to add password checking to part of the login process.

  • You must not store the password in plain text. Why not?

  • You'll need to hash the password: we recommend using Python's bcrypt library.

  • Login verification means hashing the guess and comparing that with the stored value of the hashed password. If the values are the same, the guess was correct.

  • You should hash your passwords with a salt. What's a salt? Why is it important? What attack is it preventing?

  • Remember: in addition to updating the logging in process, you will also need to update the registration process. The registration process should automatically generate a salt for the new user, hash it and the inputted password, and store the salt and hash in the database.

  • We've required passwords for this task - but there are other ways of implementing access control, and passwords have some weaknesses.

  • What's the difference between authenticating a user or authorising them?

Phase 5 tasks

5-VIZ Visual representation of the buggy

The buggies are just a bunch of numbers and settings!

Construct a visual representation of each buggy that shows its configuration.

Remember to add a text for 5-VIZ for your report (you can edit it later).
  • This is presumably client-side using JavaScript. You can draw shapes natively, but it's a lot of work: there are a number of drawing libraries so we recommend you use one of those.

  • Although it's presumably client-side... could you do this server-side, with Python? How might that work? What are the pros and cons of this approach?

  • The two common ways of drawing in the browser are canvas or SVG.

  • This is potentially - by far - the most complex of the tasks. What are the limits? A 2D rendering of a 3D model? Downloadable files for 3D printing?

5-RESET Password reset

A user who forgets their password can't log in.

There's no email address associated with a user, so to implement a reset password option perhaps you'll need to add that to the user record, and find a way to send an email from within Python. Or use a one-use token system (see hints).

Remember to add a text for 5-RESET for your report (you can edit it later).
  • See also the admin user (5-ADMIN) task, which potentially lets an admin fix this instead. Why have password reset if you have an admin user?

  • In order to send an email, you'll need to connect to an SMTP server. So you'll need to know details for that server (including, probably, some authentication criteria such as username and password). How will you make that information available to your program? Why should you not put it in the code (or any of the files in the Git repo)?

  • If you don't want to implement email - which is a whole subsystem just to reset a password - you could implement a token system instead.

  • A token system lets an admin user (5-ADMIN) add a token to a user's record. The admin then tells the user what the token is. The token should also have a time-limit. If the user goes to the reset password page and enters the token before it has expired, their new password is applied.

5-RACELOG Store a history of race results for the buggies in your app

You don't know how well different buggies did in their races, but you should be able to see which ones have won more races, and how.

Store and present a log of race results for each buggy.

Remember to add a text for 5-RACELOG for your report (you can edit it later).
  • How are you going to get the data? In what format(s) does the race server make this data available? Which would be easiest for you? Why?

  • There's no table in the database for this, so maybe you'll need to add one, perhaps with SQL's CREATE TABLE.

  • But you'll need to design the table too and think carefully about what columns you need.

  • Which columns can be NULL?

  • What's the best data type for storing when the race took place?

  • How are you going to connect the records with the specific buggies?

  • What happens if a buggy is deleted after the race results have been stored in your database? What are the various remedies to that?

5-ADMIN Add admin capabilities to superusers

At least one user should be able to change other users (and admin, or superuser).

Use something like the is_admin setting in the users table and add superuser capability for manipulating buggies and users.

Remember to add a text for 5-ADMIN for your report (you can edit it later).
  • The flask_login library already has the concept of admin users but if you've implemented your own users (which is great!) you need to add a way of determining whether a given user is indeed an administrator.

  • The is_admin column in the users table should be set, so you can check in your python if the current_user has superpowers.

  • The superuser should have CRUD on other buggies... and other users.

  • How do you create a new admin user?

  • How about changing init_db.py so it creates an admin user when the server is first installed? What would you have to do to make this work? What mitigations could you put in place to minimise any risks that might arise from having an initialised admin user in the database?

  • What happens if you delete the only remaining admin user? What's a design solution to this?

Phase 6 tasks

6-FREE Add custom features to the editor

This task is a freestyle placeholder for other developments to the editor once you've done all the others.

Implement your own custom features.

Remember to add a text for 6-FREE for your report (you can edit it later).
  • Limitless :-)