UPDATE: We have now rebuilt our system to use NoSQL. The below section no longer reflects the project. To view the updated project model, jump to the AROWF section directly.
The next part of the application after the login system is to build reviewer profile pages. For this task, I ‘ll first have to define what roles a user of the system can play.
I. User Roles
I created a new table in the development database called ‘roles’. It has two roles currently – reviewer and administrator. Although the roles are discrete, they are defined in terms of a combination of permissions.
The ‘roles’ table is defined in the database having the following attributes:
- id (int) – primary key
- name (string)
- default (bool) – set to True only for admin role, False by default
- permissions (int) – bit flag for all tasks where each task gets a bit position (set to 1 or 0)
- reviewers – foreign key, back referencing to the ‘Reviewer’ table
There is a one-to-many relationship from roles to reviewers (users), as one role can belong to multiple users, but a user can have only one role.
As of now, three application permissions have been defined:
- Comment – 0b00000001 (0x01) – comment on flag reviews
- Review – 0b00000010 (0x02) – review flagged items
- Administer – 0b10000000 (0x80) – administrative access to the site
These permissions are added as part of a separate class in ‘app/models.py’. The user roles along with permission flag is given below:
- Anonymous – 0b00000000 (0x00) – User who is not logged in
- Reviewer – 0b00000011 (0x03) – Basic permissions to comment and review flags
- Administrator – 0b11111111 (0xff) – Full access, including permissins to change the role of other users
These addition of roles is defined by a method ‘insert_roles()’ in the Role class. This method defines a dictionary, mapping roles to various permissions. Then for every role in the dictionary, it checks if it’s already present in the table. If not, it adds it, else it updates the preexisting role. The code for this can be referred in the link provided at the end of this section.
This commit is part of the branch ‘roles’. It currently has a few errors during db migrations. The commit consists of the following modifications:
app/manage.py – added a table called ‘roles’, added a class called Permissions to associate flag bits for each permission. Reviewer class has new methods for initializing and checking permissions. A separate AnonymousReviewer class has also been added to deny all permissions.
app/templates/403.html – new template to display the ‘Forbidden’ message for unauthorized access
app/main/errors.py – added an error handler for rendering the 403 template
app/decorators.py – custom decorator for rendering views only for specific permissions
app/main/__init__.py – added a context processor to make permission variables globally availabel to all templates
manage.py – make_shell_context instantiates Role and Permission
tests/test_reviewer_model.py – added tests for checking permissions of a reviewer and anonymous reviewer
The code for this commit is here.
II. Profile Pages
Now, we need to make sure every reviewer has a profile page displaying their basic account information. I added a few more fields in the Reviewer table:
- location (string)
- about_me (text)
- member_since (datetime)
- last_seen (datetime)
Since the last_seen needs to be refreshed each time the user accesses the site, I defined a ping() method in the Reviewer class that must be called each time a request from the user is received. This is done with the help of before_app_request handler in the authorization blueprint. Refer to the code in app/auth/views.py.
For creating a profile page for each reviewer, we need to specify dynamic routes in views.py that takes in the <username> in the url.
For a user named rita, the profile page link will be:
An invalid username will redirect to a 404 page not found error page. Some points worth noting are:
- The user location field is rendered as a link to a Google Maps query
- If the user is an admin, then email addresses of the username are shown as well, rendered as a mailto link i.e. admins can directly mail users
Since most users will want a link to their own profile page from the main site, base.html is accordingly modified to add the ‘Profile’ button, only in case the user is authenticated i.e. it should not be visible to non-logged in viewers.
Coming to the profile editor part, there are two different use cases here. Reviewers need to have access to a page where they can update information about themselves. For the admins, in addition to the above, they will also be given the permission to update information of other reviewers, including their username and