GSoC 2023: Administration System Proposal

Personal Information

Name: Stoican Radu

Email address: radustoican1@gmail.com

University: Politehnica University of Bucharest

Major: Computer Science

Location: Romania, Bucharest

Time Zone: GMT +3

You can also view my proposal at this link (in Google Docs)

Github LeetCode Resume

Project Overview

At present, the BookBrainz website lacks an administration system to grant users
additional privileges and allow them to modify inaccurate or poorly written information.

  1. Implementation

    As advised in the project page, this system will require:

  1. Changing the database schema.

  2. Adding a front end admin panel that allows admins to search for users and give them certain privileges. Also, the admins should also be able to remove those privileges, as well as downgrading or upgrading someone in the hierarchy(in the case where we have multiple privileges).

    *An added page that allows those privileged users to edit and add relationships as well as identifiers. This will require.

    *A public log that lets you see a log of all administration actions.

  3. Changing the middleware file so that specific routes, such as the admin webpage can be accessible only to certain users.

  1. Steps for each part of the implementation

  1. The database will need to be modified such that all roles are defined and attached to the users we want. For that we could create tables that offer information about each of the roles and about all of the user’s roles.

*Also, the action description should be displayed, as well as a reason for it and a provided storage for the time it was made

(as in: Moderation log - CritiqueBrainz)

In the database, there is a table that already handles user information called bookbrainz.editor (located in sql/schemas/bookbrainz.sql), so in order to attach users to roles, we need to reference the id from this table to the id of the bookbrainz.roles table in another table called bookbrainz.users_roles. This way, each privileged user will have a foreign unique key attributed to him.

Here is the table that defines roles

CREATE TABLE bookbrainz.roles (
id SERIAL PRIMARY KEY,
role VARCHAR(20) NOT NULL CHECK (role <> ‘’)
);

The PRIMARY_KEY assures uniqueness of each role, and the role column handles the name of each role. We also need to assure that each role has a value, checking that every column has a non-empty value in every row.

Table that attaches roles to user

CREATE TABLE bookbrainz.users_roles(
user_id INT NOT NULL,
role_id INT NOT NULL,
id SERIAL PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES bookbrainz.editor(id),
FOREIGN KEY (role_id) REFERENCES bookbrainz.roles(id)
);

  • In order to store each user’s role and attach each role to an user, we need to create a new table that references the id of the user and the id of the role. We can do that by using the FOREIGN KEY elements, making sure the user_id/role_id refers to a valid value from the editor/roles table. In this way we can assure that the ids match the ones in the tables that handle roles and users and create a relationship between the users_roles table and the editor and roles tables.

  • Adding a new field to a table could result in the default value being set to NULL, and this could impact the ability to access the user interface. Therefore, it is necessary to perform a bulk update to set the appropriate values for the new field.

  • To ensure that each combination between an user and its role is unique we have to create a PRIMARY KEY, so that each user can have multiple roles, and each role can be assigned to multiple users.

Table that defines all the elements of an admin’s actions in the log menu

CREATE TABLE bookbrainz.admin_log (
id SERIAL PRIMARY KEY,
admin_id INT NOT NULL
affected_user_id INT NOT NULL
action VARCHAR(255),
reason VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (admin_id) REFERENCES bookbrainz.editor(id),
FOREIGN KEY (affected_user_id) REFERENCES bookbrainz.editor(id)
);

  • With the FOREIGN KEY we reference both the admin’s and the user’s id in order to create a relationship between both tables and check if the ids match the values with the ones in the editor table.

  • We need an id for each log to ensure the uniqueness of each element. We cannot obtain the primary key from the ids of the admin and the affected user because the table can be used multiple times with the same values for the admin id and the affected user id.

  • We need to remember data that refers to the action and the time it was made, the user who made it, the affected part, as well as the affected user.

  1. A simple and efficient design for the admin panel is required, that adds the following functions:
  • A search option that allows the ability to find any user in the database. After finding a certain user, the admin should be able to click on his profile and have several options he can choose from, such as blocking an user or making him an editor.

Mockup for the user search functionality (Link)

|592.9999999999998x243.21103857496234

Mockup for the user’s profile Make editor and Block user buttons (Link)

|643x167.3041747389883

  • These privileged users should also be able to add relationships and identifiers. For that a new panel should be created that would allow them to add the type or entity that they consider.
  • A moderation log, accessible to everyone, lists all of the administration actions in a chronologically ordered way, showing the time of the certain action, the name of the actions, the reason for it, as well as the User name and the affected part of its action. If possible, a search option should be available, where you can filter by date, affected user, or username of the admin.

Similar mockup for the admin log (Link)

  1. Certain functions need to be defined in the middleware file, so that only certain users are allowed to access those webpages. For that, we should check the users_roles table to ensure that the user has the necessary privileges in the database and provide the necessary response according to his role.
  • We can make sure that the admin panel and the visibility of buttons for removing or adding privileges can only be accessible by users with certain roles in the database using a function that gets the user’s role and checks if it’s the required one for the action.

Example code for only allowing privileged users to access admin panel page

// Creating a middleware function that checks if user has necessary permissions
function requirePermission(role_id) {
return function(req, res, next) {
// Getting the user identity from request
const userID = req.editor.id;
const userRole = req.users_roles.roles_id;

// Checking if user has the required permission
if (role_id == userRole) {
// User has required role
next();
} else {
// User does not have permission
res.status(403).json({ message: ‘Unauthorized’ });
}
}
}

// Apply middleware function to a specific route
app.get(‘/admin’, requirePermission(‘admin’), function(req, res) {
});

  • The same thing applies for blocking or promoting certain users. The buttons can only be seen if the server recognizes the user’s role to be equal to the role’s requirements.

  • A new page should be created for privileged users only that can allow them to edit the relationships and identifiers of the user. This page could be accessed through the Add+ section, where we can add 2 more elements in the dropdown menu, one for relationship and one for identifiers.

  • The function for triggering the search reindex (located in src/server/routes/search.js) can currently run only when the username corresponds to one of the trustedUsers strings. This should be changed in order for any user who has the corresponding role to be able to reindex the search server. For this we would need to store the needed role in a variable and store in another variable the user’s role from the database table ‘users_roles’ and check if they correspond.

Example of changing the code that enables the privileged user to run the search reindex function

router.get(‘/reindex’, auth.isAuthenticated, (req, res) => {
const { orm } = req.app.locals;
const indexPromise = new Promise((resolve) => {
// TODO: This is hacky, and we should replace it once we switch to SOLR.
const trustedRoles = [‘admin’, ‘editor’];
const NO_MATCH = -1;

// Check if the user has any of the of the trusted roles
const userRoles = req.user.roles.map(role => role.name);
const hasTrustedRole = trustedRoles.some(role => userRoles.indexOf(role) !== NO_MATCH);
if (!hasTrustedRole) {
throw new error.PermissionDeniedError(null, req);
}

resolve();
})
.then(() => search.generateIndex(orm))
.then(() => ({ success: true }));

handler.sendPromiseResult(res, indexPromise);
});

Timeline of the development

The community bonding period will be spent familiarizing myself with the database and the current middleware implementation, as well as completely fixing up the testing suite setup(currently, after solving the linter errors, the command for running the tests can’t recognize the required files).

Week 1

  • Understanding how the data would be accessed by the server and how the user will interact with the server.
  • Changing the database schema, creating the necessary roles and setting the privileges of each.
  • Creating a table that attaches the roles from their table and the user’s ids from the already existing “editor” table
  • If possible, create the admin_log table that handles details about the actions made by admins.

Week 2-3

  • Creating the admin panel page and implementing a search option as well as adding a drop-down element for the option of filtering the search with certain roles. For this we need to create a backend function that handles the user data from the database and handles it to the client.
  • Building the buttons in each user’s profile that handle the block or promote options.
  • Displaying all users with special privileges in an accessible way, in order for admins to easily see all of the editors, by accessing the database tables that handle user’s information and roles.

Week 4-5

Securing the specific routes such that they can only be available for certain users, and providing responses for users that are privileged to access the page as well as for users who are not allowed:

  • Adding the option for privileged editors to trigger the reindex of the search server.
  • Implementing or changing the functions such that only users with certain roles are able to access, see or use the admin page and the block and promote buttons in each user’s profile.

Week 6-7

Implementing the functions that the server would use in order to interact with the database, as well as the functions that would be needed for the front end to connect to the server and send the required changes:

  • Managing the functions that change the roles in the database, in order to be able to block or promote a certain user.
  • Implementing functions that handle the direct change of relationships and identifiers types.

Week 8-9

  • Documenting the added features and pages in the developer docs, writing a guide that would allow the easy understanding of the functionality, as well as a way to implement those in your own local server.
  • Fix any issues regarding the testing suite and checking the coding style as well fixing any linter related errors/warnings.
  • If not done, create the admin_log table in the database and start to create the log page.

Week 10-11

  • Creating the page that would allow editors to edit and add relationships and identifiers. Adding functions that allow these privileged user to change the database directly.
  • Implementing the log page that provides information of all actions made by admins, visible to anyone and ordered chronologically. Also creating functions that handle storing data about an admin’s action in the database using the admin_log table.

Week 12

  • Finishing the documentation on the developer-docs, creating new tests for the added features.
  • Checking coding style is corresponding to the linter standards.

Contributions

I have contributed with 3 merged pull requests. My nickname on github, tickets.metabrainz.org and BookBrainz IRC is stoichy and my username on community.metabrainz is Radulee.

  1. I have solved 85 linter errors that stopped the testing suite from running.

    ( Pull request BookBrainz Ticket BB-732 )

  2. Added reset functionality for multiple optional dropdowns elements

    ( Pull request BookBrainz Ticket BB-690 )

  3. Fix for command in Testing section in BookBrainz Developer Docs

    ( Pull request BookBrainz Ticket BB-716 )

  4. Tell us about the computer(s) you have available for working on your GSoC project!

For my GSoC project, I only use my ultrabook laptop, which I think is suited for running the Docker containers for the server and simultaneously using Google for searching up issues and errors:) (Specs: 8gb Ram, Intel Core I5 8th Gen, Nvidia MX150 2gb and a 256gb SSD).

When did you first start programming?

I first started programming in 8th Grade, when I was 14, after discovering algorithmic problems subjects of the Regional Informatics Olympiad, where I first participated in 9th Grade.

In the summer between 11th and 12th grade I started my web development journey and ended up learning using the React and Socket.IO libraries.

What type of music do you listen to? (Please list a series of as examples.)

I usually listen to progressive rock and old Romanian folk music. To my excitement, I found my favorite folk singer, Gica Petrescu, on my first search on MusicBrainz. Here are some songs I am listening to on a daily basis: Hai să bem un păhărel by Gică Petrescu, Comfortably numb Pink Floyd, Another one bites the dust by Queen, Under pressure by Queen and David Bowie.

If applying for a BookBrainz project: what type of books do you read? (Please list a series of BBIDs as examples. (And feel free to also list music you listen to!))

In terms of book genres, psychological books have always been my favorite, followed closely by thrillers and horror novels. For those interested in these genres, I highly recommend Dostoyevsky’s works, particularly Crime and Punishment, as well as Stephen King’s books, with The Shining being a personal favorite.

While using the BookBrainz website, I was surprised to find that my favorite romanian book was not yet listed, so I added it. The book is Moromeţii by Marin Preda and can be accessed by clicking the name.

What aspects of the project you’re applying for (, MusicBrainz, AcousticBrainz, ) interest you the most?

I believe that all types of literature, publications, and articles should be easily accessible and promoted for people to read. As a result, the BookBrainz website functions as an encyclopedia of all publicly available written works.

It is precisely this aspect that appeals the most to me. Endowing people with the opportunity to contribute to an open community and democratizing access to all available written works makes me feel very impactful and eager to help grow a project that has a big potential in the literature world.

Have you contributed to other Open Source projects? If so, which projects and can we see some of your code?

I have contributed to the Electron framework open source project, specifically on the Electron Fiddle framework, where I fixed an interface problem within the Settings page.

Here is my Pull Request.

  1. What sorts of programming projects have you done on your own time?

  • I finished my first project in 10th grade. I finished a C++ program that would let you play the X and 0 game against an AI opponent that you couldn’t beat. The AI was developed using the Min Max algorithm.
    Github link

  • The second project that I completed, which I worked on between 11th and 12th grade, began with my learning the basics of HTML, CSS, and JavaScript. In summary, I designed and developed a multiplayer Chess website that allows players to compete against each other in a customized manner, with options to set time limits and choose colors. Additionally, the website features a backend timer and a live history of previous moves.

  • By utilizing the React library, I was able to create and manage a simple yet functional user interface that interacts with the backend server.
    Frontend code

  • The server was developed using the NodeJs environment and the Socket.IO library, which enabled me to maintain multiple matches with a functional timer that worked with both players offline, and a history of moves each player made. I also integrated an authentication option called Auth0. As a bonus, I added the StockFish AI engine, where a player can choose to play against it on various difficulties he chooses.
    Backend code

  1. How much time do you have available, and how would you plan to use it?

My weekends are usually spent with my hobbies, so I usually have most of my available time during the week, where I can give in about 7 hours of consistent work.

1 Like