Documentation for developers - learnweb/moodle-block_townsquare GitHub Wiki

Documentation for developer of Townsquare:

This documentation should help you to fully understand the structure and components of townsquare. Goal is to make issue-solving and the development of new feature easy and that the changes fit in the rest of the programs logic, so that townsquare stays coherent and understandable for the future.

1. Overall structure

Townsquare is designed as a lightweight dashboard plugin, that collects information that is already stored in the database. The plugin has 3 parts: Data collection and representation, interaction with the user and miscellaneous.

A typical townsquare site looks like this:

townsquare

The data collection is the job of townsquareevents class. The contentcontroller builds "letter"-objects, that are then rendered and shown to the user. These two classes are the core of the townsquare plugin. Letter objects represent a single notification. All notifications are rendered at once in an infinite scroll list. The core structure looks like this:

klassendiagram_simple

For the interaction with the user the plugin uses javascript. Every user has the ability to filter the content by 3 categories: courses, time span and letter type. The course filter lists all courses that show notifications. With checkboxes the user can select the courses from where he wants to see notifications. The time filter works similar, only that the user selects a timespans with preset buttons:

image

With the letter filter the user chooses with checkboxes, which kind of notifications are shown:

image

User have the ability to store the time and the letter filter setting for future sessions. The filter settings are stored in the database. For more information see "Database structure". The execution is done with javascript and an own moodle web-service.

Administrators can choose in the plugin settings the colors of the letter colors. The rest of the plugin files are the standard moodle files like the version file, the language strings and the privacy provider.


2. How data is processed

When loading a page with townsquare in it, townsquare calls the build_content() function of the controller. The controller then calls the get_all_events_sorted() function of the events class. This function retrieves events from 3 origins:

  • Events and activity completions from core modules. These events are stored in the mdl_event datatable. Core modules are all modules that are included in the basic installation of moodle.
  • Posts from the core module mod_forum. A difference from townsquare to other event-showing blocks like the timeline is the support of forum posts. Forum posts messages are shown in the plugin with a link to original post in the forum.
  • Other events and activity completions from other, non-core plugins. The local plugin townsquaresupport supports the use of subplugins. A subplugin for townsquare expands the plugins by retrieving events from one plugin. For more information, see point 4. of the documentation and the documentation of the townsquaresupport plugin

The retrieved events are then sorted and filtered. The filter ensure that the user only sees events that he or she should see (e.g. an event to remind the teacher to grade an assignment should not be shown to the student). The contentcontroller takes the finished events and categorizes them in 3 different letter categories:

  • "basic" letters, that are for all kind of events that are not specialized
  • "completion" letters, that are for activity completions
  • "post" letters for the forum posts

Each event is then transformed to a letter object. The letter class is responsible for adding urls and information for the mustache template. Every letter has an export function that has all information right formatted for the template. The contentcontroller puts every exported letter in an array. This array is then used by the townsquare main function (blocks_tonsquare::get_content()) and given to the template that renders the content.

Here is a visualization of the process:

townsquare communication


3. Detailed explanation of single components

Contentcontroller and townsquareevents class

These two classes are the core of the plugin. The controller is one of the smallest files and acts as an interface between the main function and the townsquareevents class. The build_content() only function is to assign every event an appropriate letter class and set the orientation marker at the right position.

The townsquareevents class gathers all the important data and processes it. The main job is to make sure, that the right data is retrieved and then filtered out. After the call of get_all_events_sorted() the amount of events does not changed and data is only formatted added to an event/letter. The collection is divided in 2 steps. In the first step, records from the database are called. In the sql-query the function makes sure that an event is for the current user, that is in the right timespan (townsquare searches only for events in a specific timespan) and a few other things like that the related plugin is available/installed. In a second step, every record is checked again with checks that were not possible to include in the sql-query. When all events from subplugins, core modules and forum posts are ready, a mergesort function sorts in descending time order (the newest event comes first).

Datatable and privacy provider

As mentioned before, townsquare can save the settings of the time and the letter filter in the moodle database. Townsquare defines a datatable "block_townsquare_preferences" with the following scheme:
Datatable column Description
id Unique identification of the row
userid User that stores the setting. Also unique as every user only uses 1 row, that is updated when needed
timerfilterpast Timestamp of how many seconds in the past notifications are shown
timerfilterfuture Timestamp of how many seconds in the future notifications are shown
basicletter Integer of 0/1 if basic letters are shown
completionletter Integer of 0/1 if activity completion letters are shown
postletter Integer of 0/1 if post letters are shown

A row is only created when a user wants to save the current settings. After then, the users row is updated when the user changes the settings and saves them again.

The privacy provider exports the complete users row if wanted (except for the unique table id)

Lib and locallib

These Lib is the central file for functions, that are needed to be accessible moodle-wide. It defines the constants for the letter colors as well as functions that are used by townsquare and for subplugins. These are functions for filtering events after the database call, a mergesort to sort the events and getter for central variables like the search timespan and the courses that will be searched for events.

The locallib has functions to shorten the logic of the townsquareevents class and for functions that do not fit in any other file. The check_coreevent() and get_open_close_message() functions are to determine what language string is used for basic letters of core module events.

Mustache templates and CSS

CSS Styling

In General, townsquare uses mainly bootstrap 5 and core moodle styles to style the closes. That ensures a unified impression of the plugin in the moodle enviroment and makes it more adaptable to different moodle themes. Townsquare uses own classes only for microstyling and adaptation of bootstrap styles.

Mustache templates

For the html-representation townsquare calls it's main mustache template file, the blockcontent.mustache. The anchor div-container has the ID "townsquare_root", which is unique in the block. The block is structured in 2 pieces. On the left is the side panel with the filter the user can interact with. The sidepanel is outsourced in an own template. On the right is the content of townsquare. The blockcontent template receives from the block_townsquare file an array with letters and based on an attribute that each letter has ($isbasic, $isactivitycompletion,...) the template uses the right template to render the notification with the data of the letter.

Sidepanel template

The user filters and the save button on the sidepanel are build in an "akkordion", that ensures that the outer elemts stay together. The filters itself are collapsable cards (the same elements as the letters) and only one filter at a time is set. Letter and course filters are designed as checkboxes, as a variable count of elements can be active at the same time. Notable is, that the checkboxes of the course filter is build dynamically, as the amount of courses changes. In the time filter, the user can only selected between "see all notifications" and a combination of "past" and "future" notifications. To visualize this, the buttons of the filter change their background to a darker one, when selected:

ts_timefilter_alltime ts_timefilter_combi

The last element of the side panel is the button, that saves the settings of the filters. For more information about this button, see the "Javascript and external service" chapter.

Letter templates

Every letter type has an own template file. Altough the basic structure is the same, different templates are needed to give each letter unique id's and class namings. Letter are designed ase bootstrap "cards" and in the card root class an unique "contentid" is stored, to make individual access possible. The card header shows course origin and date. The card body content depends on the letter type. Basic and activity completion letters show a same-style message each:

basic-completion letter

The post letter has the most complex structure. As the templates supports moodleoverflows anonymous message system (for more information, see learnwebs moodleoverflow plugin ) and the private reply system from the forum plugin, additional data is processed. If a post is anonymous, the post author is cleared. For private replys an informational text is placed under the post message. Townsquare shows the whole post message, which can be a problem when a message is very long. For that, a javascript function shrinks long messages and uses a "show more/show less button". This button is part of the template and only shown, when a post has a long message:

showmore1 showmore2

Letter classes and orientation marker

The letter classes are responsible for preparing data for the mustache template like formatting data, getting the letter color and adding urls. Basic letter and activity completion letter class are very simple, as they only add the missing urls. The post letter class needs to format the data, as a post can be anonymous (moodleoverflow plugin) or a private reply (forum plugin).

Javascript and external services

To offer a good user experience the plugin uses javascript for all user interaction. Javascript is used in 3 features:

  • Management of the content filters
  • Saving the user settings in the database
  • Management of long post messages

Management of the content filters

4 javascript files manage the right work of the filters:

javascript_filter

The filtercontroller is the main component, that actually shows or hides a letter. The controller does not remove any of the filters but hides them by changing their css "display" attribute. Every filter "approves" a letter by adding or removing a class name to the root container of the letter. The classes work similar like a mark, that is removed or put on. A letter is only showed if all filter individually approve a letter. That is very important, as the filters work independent from each other. In the implementation every letter has an observer, that detects when a filter removes/adds their "approved" mark. The observer triggers then the function that decides wether the letter is showed or not.

The course and letter filter files work very similar. They add event listener on their respected checkboxes and check the approval on every letter when a checkbox is clicked. The time filter is a little more complex, due to the button groups and the more dynamically time span. When the "All notification" button is clicked, a selection in the other to button groups needs to be removed and vice versa. Additionally, the time span of a button is saved as a string and needs to be converted to an integer to be compared to the letters creation time. Because of that, every button group (all notifications, past notifications, future notifications) has a function that manages their event listener. The central function executefilter approves the letters.

Saving the user settings in the database (use of external service)

The usersettings_save.js file has 2 jobs: execute existing user settings from the database to the filters and saving current filter settings in the database.

The trail database to townsquare is pretty simple. When loading townsquare, the main php class block_townsquare reads the databse and gives the setting of the user that calls townsquare to the javascript file. executeusersettings reads the array and triggers the right checkboxes or buttons if needed to execute the settings. Initially all letters are shown and the executeusersettings triggers the letters that should not be shown.

The other way (townsquare to database) is way more complex as a javascript function can not make an sql-call to the database directly. The usersettingssave file makes an AJAX call to a php function at townsquare/classes/external/external.php. For more information about how external services work, see the moodle documentation. The external function receives an array of the usersettings, puts them in a record and creates or updates the record in the database. The saveusersettings function reads the state of the letter and time filter and puts and creates the array.

Management of long post messages

At last, the postletter.js checks every post letter and by counting the number of chars. If the chars reach a number of 250, the "show more" button that is always a part of the mustache template is showed an the string is cut at this point. For picture please look at the chapter "mustache templates and css" of this documentation

Tests

To ensure that all plugin features work he plugin has unit and behat tests. The unit tests checks the main php components that retrieves events and checks, if the components work correctly. The behat tests runs through all javascript features.

4. Subplugins

As mentioned before, townsquare does not support notifications from all plugins but core plugins. To make it possible that other plugins can show content on townsquare, an additional local plugin townsquaresupport is supported. Townsquaresupport can host subplugins, that retrieves events similar to the townsquareevents class.

connection_to_subplugin

Subplugins must be programmed manually, as every module can have different events and rules for when an event can be showed to an user. A subplugin events is accessed by a single function from the townsquaresupport and the townsquareevents class access that function, if the local plugin is installed. For more information about the exact procedure, please see the townsquaresupport documentation. Most important for development: events from subplugins are sorted with other events by the townsquareevents class and transformed to "basic" letters by the contentcontroller.


5. Miscellaneous:

Moodleoverflow's special treatment

Perhaps you noticed that moodleoverflow is a plugin, that is natively supported by townsquare. The decision to support other plugins in outsourced subplugins was made, when the moodleoverflow notifications were already integrated in townsquare (especially the postletter class). As subplugins should only extract the events make them ready for basic letters, moodleoverflow could not fit in there. Because of that, only the event extraction was outsourced and the data formatting and the rest still remain integrated in townsquare. Reason for that decision was the similarity between moodleoverflow and forum posts and the fact that moodleoverflow is a Learnweb own plugin. This is important because unexpected behavior from moodleoverflow notifications is less expectable and easier to solve.

Branch naming

It is recommended to not name the branches randomly when creating. A simple guideline:

Branchname Description
feature/branchname Branch with a new functionality
improve/branchname Branch that improves a functionality that already exist, without changing the main structure
fix/branchname Branch that solves an existing bug
update/branchname Branch that adapts the repository for a new release due to a new Moodle version
redesign/branchname Branch that redesigns or restructures an existing functionality. Changes a logic structure (e.g. new class structure)
clean/branchname Branch for code cleaning/beautifying (e. g. clear codechecker warning etc.)

It is also recommended to add labels to issues/Pull request and to assign them to an user.

⚠️ **GitHub.com Fallback** ⚠️