Sockets
There might be rare occasions where you need to extend the existing socket interface; e.g. after adding a new database table to CARE and you want to make this data available to the frontend. In this chapter we outline the steps necessary for either extending an existing socket or creating an entirely new one.
Note
Please also see the code conventions for the socket interface in Code Conventions
Sockets in CARE
The socket architecture is realized in the backend; in the following all paths are provided relative to the
directory backend/webserver including all relevant components.
During start-up of the webserver all sockets specified in the sockets directory that extends the Socket base class are loaded.
Each socket is specified in an individual .js-file exporting a class that extends the Socket base class. Hence, adding
a socket means creating such a new file and overriding the abstract class.
This base class (specified in Socket.js) defines several convenience methods to communicate with the frontend, as
well as attributes and methods to interact with the web server class starting the respective socket. In the following
sections we elaborate which methods and attributes you should use or override to realize your own service.
Conceptually, a socket class encapsulates a socket-io connection established by the webserver, which you can use to listen to certain messages and which you can use to send back messages. For each frontend client that connects to the webserver, all socket classes are instantiated anew having an associated client id. This means, all messages you send and receive via the socket attribute are always specific to this one client connection; in other words, there is no state transfer between different connections or broadcasting possible. However, some of this functionality is made available through the server object – we address these options in the Extending a Socket section below.
See also
For the generic create/update entry point used by the frontend, see AppDataUpdate Socket.
Creating a Socket
Let’s say we want to add a new socket called TestSocket to CARE. First, we add a new file test.js to the
backend/webserver/sockets directory that exports the new socket class:
const Socket = require("../Socket.js");
/**
* <doc>
*/
module.exports = class TestSocket extends Socket {
constructor(server, io, socket) {
super(server, io, socket);
}
}
While this would already add the socket automatically to CARE on restart of the webserver, you should always override
the init() method of the base class. Here, you will add the message listeners; for now, we will just log that the
socket has been initialized.
/**
* HEADER BOILERPLATE...
*/
module.exports = class TestSocket extends Socket {
constructor(server, io, socket) {
super(server, io, socket);
}
init() {
this.logger.debug(`TestSocket was created for client ${this.socket.id}`);
}
}
In the next section we elaborate on how to populate a socket by message listeners and response functionality.
Extending a Socket
Let’s assume we want to extend a socket TestSocket defined in ./backend/webserver/sockets/test.js. Generally,
socket logic should be kept lean and easy. The primary responsibility of a socket is to forward a new client request
to another module for processing (e.g. the database interface), handle possible errors and send the results back to
the client. In the following we explain the possible use-cases for extending a socket
Listening to a New Message Type
Let’s say we want to listen to new message types testIncrement and testReset that provides a data object parameters.
For the sake of brevity we do not interact with the database, but write to a class attribute.
/**
* HEADER BOILERPLATE...
*/
module.exports = class TestSocket extends Socket {
constructor(server, io, socket) {
super(server, io, socket);
this.testVar = 0;
}
/* ... */
// method for updating the variable
updateTestVar(newVal){
this.testVar = newVal;
return this.testVar;
}
init() {
/* ... */
// listen to testIncrement
this.socket.on("testIncrement", (data) => {
try {
this.socket.emit("testResult", {success: true, val: this.updateTestVar(this.testVar + data.inc)});
} catch (e) {
this.logger.error(e);
}
});
// listen to testReset
this.socket.on("testReset", () => {
try {
this.socket.emit("testResult", {success: true, val: this.updateTestVar(0)});
} catch (e) {
this.logger.error(e);
}
});
}
}
Let’s decompose the steps to realize this example. First, we extend the init() method adding event listeners
on the socket using the on(msg, callback) function of the socket.io client. We then call the class method that
allows us to modify the state of the test variable (this.updateTestVar(...)). Finally, we return the resulting
value to the client via emit(msg, data) with the resulting value.
Error and Rights Management
When interacting with the database the key challenge is error handling, marshalling (i.e. the translation of the DB
data representation into a suitable format for the frontend) and rights management.
For now, we assume that we want to call an already defined database a model Test specified in
./backend/db/models/test.js and integrate this call into the above example.
Let’s also assume that only administrators are allowed to change this value.
Note
Please refer to the guide on how to extend the database and add interface methods in Database.
/**
* HEADER BOILERPLATE...
*/
module.exports = class TestSocket extends Socket {
/* ... */
// method for updating the variable
async updateTestVar(newVal){
// use base class method to check for admin rights
if (this.isAdmin()) {
try {
const result = await this.models["test"].updateById("x", {val: newVal});
this.socket.emit("testResult", {success: true, val: result});
} catch (e) {
this.socket.emit("testResult", {success: false, message: "Failed to update test!"});
this.logger.error("DB error while updating test" + JSON.stringify(e));
}
} else {
// respond with a negative message
this.socket.emit("testResult", {success: false, message: "User rights and argument mismatch"});
}
}
init() {
/* ... */
// listen to testIncrement
this.socket.on("testIncrement", async (data) => {
try {
await this.updateTestVar(this.testVar + data.inc);
} catch (e) {
this.logger.error(e);
}
});
// listen to testReset
this.socket.on("testReset", async () => {
try {
await this.updateTestVar(0);
} catch (e) {
this.logger.error(e);
}
}
}
}
Let’s decompose the example again! We first update the updateTestVar to use the dbUpdateTest function interfacing
the database. Before making the actual call to the database, we check whether the user is an admin through the base
class isAdmin() method accessing the backend user information associated with the current connection. Because the
database query might fail, we add a try-catch-block around it. In case of an error at any stage, we send a negative
testResult back to the client.
Note
It is crucial that you do full error handling on the socket level, i.e. at some point all exceptions should have been caught by a catch block. Otherwise, the webserver can crash due to minor errors during database interaction.
Broadcasting Responses
To realize collaboration features, it might be desirable to join clients into rooms and multicast messages to these groups. In exceptional cases, even a broadcast might make sense. You should use these two options very sparingly, because they imply a lot of network traffic.
To join a client to a socketio room, you can simply use the join(name) function on the socket object:
this.socket.join("roomName");
To multicast a message to a room, you need to access the io object of the base class.
this.io.to("roomName").emit("msg", data);
Testing
Please think about how to test your socket. In general, you should test the functionality in isolation. We refer to the section on Tests for more information on how to test your code.
Socket Communication Schema
In order to streamline socket communication, especially when interacting with the database, CARE defines a standardized way to register and handle socket events using the createSocket method provided by ./backend/webserver/Socket.js.
This schema helps to ensure consistent error handling, optional transaction safety, and frontend compatibility.
createSocket: How it works
The createSocket method allows you to define a socket event with built-in support for:
Error handling
Optional transaction wrapping
Automatic frontend success/failure callbacks
Clean backend-to-frontend event emission after database changes
createSocket(eventName, func, options = {}, transaction = false)
- Arguments:
eventName: Name of the socket event to registerfunc: Async function handling the request, with parameters(data, options)options: Object passed through the socket pipeline; can contain any contextual data (e.g., transaction info, user session, metadata)transaction: Iftrue, wraps execution in a Sequelize DB transaction
Warning
If your handler function performs any database write operations (e.g., create, update), you must set transaction = true and use the provided transaction object inside the function. Failing to do so can result in inconsistent or partial data states.
Note
The createSocket function should always be called within the init() method of socket classes located in ./backend/webserver/sockets/*.
The handler function passed to it should be a method of the class itself, not an inline function or a function defined inside init().
See a full example of the usage of createSocket in Example Lifecycle.
See also
How DB writes propagate to the UI (transactions, commit broadcasts, Vuex refresh): Data Transfer — especially Data Flow.
Transaction Usage
- If your socket operation modifies data, set
transaction = true. This will: Open a Sequelize transaction
Pass it to your function via
options.transactionAutomatically commit/rollback
Allow you to define afterCommit() behavior
init() {
this.createSocket("studySaveAsTemplate", this.saveStudyAsTemplate, {}, true);
}
/**
* Save the current study as a template (creates a new study with template: true).
*
* @param {object} data - The input data from the socket call.
* @param {number} data.id - ID of the study to duplicate as a template.
* @param {object} options - Context passed through the socket pipeline.
* @returns {Promise<object>} The newly created template study.
*/
async saveStudyAsTemplate(data, options) {
const study = await this.models["study"].getById(data.id);
if (this.checkUserAccess(study.userId)) {
const template = await this.models["study"].add({
...study,
id: undefined,
hash: undefined,
template: true,
}, {transaction: options.transaction});
// Code executed after transaction commit success (code only, without further DB changes!)
options.transaction.afterCommit(() => {
this.emit("studyRefresh", template);
});
return template; // The value sent back to the frontend via the socket callback
} else {
throw new Error("No permission to save study as template");
}
}
Note
Socket handler functions should always include clear JSDoc-style docstrings describing the expected data parameters, transaction context, and return type. For full documentation standards, refer to: Conventions and Paradigms.
For a detailed explanation of how to notify the frontend after a transaction, including automatic tracking (via
autoTable) and manualafterCommithooks, see: Tracking DB Changes (afterCommit).
See a further example of the transaction usage in Example Lifecycle.
Transaction Failure Handling
If an error is thrown inside a socket using transaction = true, the transaction will be automatically rolled back.
Warning
Do not call transaction.commit() or transaction.rollback() manually when using createSocket.
These are handled automatically, and calling them yourself can lead to runtime errors — they can only be called once per transaction.
Try-Catch Behavior
- Using
createSocketwraps your function call in an automatictry-catchblock. If an error is thrown: The transaction is rolled back (if enabled)
A callback with
success: falseand the error message is sent to the frontend
See the section above on createSocket: How it works for more details.
No need to write:
try {
...
} catch (e) {
...
}
Just throw an error inside your function:
if (!this.checkUserAccess(...)) {
throw new Error("Access denied");
}
Socket Callback Responses
When a socket event completes, a callback function on the frontend receives a standardized response object:
{
success: true, // true if the backend handler completed without errors
data: {...}, // the return value from the backend function (if successful)
message: "..." // an optional error message if an error was thrown
}
This structure is automatically handled by createSocket:
If the backend handler throws an error,
successis set tofalseandmessagecontains the error.If the function returns a value, it is included as
dataandsuccessis set totrue.
The following example uses CARE’s global toast system to display success or failure. For full documentation on toast messages, see ../frontend/toasts.
this.$socket.emit("studySaveAsTemplate", {id: 1}, (result) => {
if (!result.success) {
this.eventBus.emit("toast", {
title: "Template Save Failed",
message: result.message,
variant: "danger",
});
} else {
this.eventBus.emit("toast", {
title: "Success",
message: "Study saved as template",
variant: "success",
});
}
});
Tracking DB Changes (afterCommit)
In most cases, when using models with autoTable = true, CARE will automatically track database changes
and push updates directly to the frontend. This includes creation, updates, and deletions — no need to manually emit a ...Refresh event.
However, in special cases where autoTable is not used or doesn’t apply, you may need to manually notify the frontend after a successful transaction. Examples include:
Writing files to disk
Returning plain objects or custom responses
Using models that do not have autoTable = true
In these cases, you can register a manual afterCommit hook on the transaction object:
const doc = await this.models["document"].add({
name: data.name,
type: data.type,
userId: this.userId
}, {transaction: options.transaction});
fs.writeFileSync(target, data.file);
options.transaction.afterCommit(() => {
this.emit("documentRefresh", doc);
});
Warning
In normal use cases (e.g., with autoTable = true), you do not need to use `afterCommit()` or manually emit refresh events.
CARE tracks database changes automatically and handles frontend updates for you.
See also
When using autoTable models, commit-time change tracking and <table>Refresh emits are automatic.
Details in Store Updates &.
Example Lifecycle
Here is a full example showing how the backend and frontend work together when using createSocket for creating a new document.
Frontend: emit event and handle result with a toast
this.$socket.emit("documentCreate", {
type: 1,
name: this.name,
}, (res) => {
if (res.success) {
this.$refs.createModal.close();
this.eventBus.emit("toast", {
title: "Success",
message: res.data, // This will be: "Document successfully created"
variant: "success",
});
} else {
this.$refs.createModal.waiting = false;
this.eventBus.emit("toast", {
title: "Error",
message: res.message, // This will be: "Missing required fields: name and type"
variant: "danger",
});
}
});
Backend: register the socket
init() {
this.createSocket("documentCreate", this.createDocument, {}, true);
}
Backend: handler function implementation
/**
* Create document (HTML)
* @param data {type: number, name: string}
* @param options
* @returns {Promise<object>}
*/
async createDocument(data, options) {
const doc = await this.models["document"].add({
name: data.name,
type: data.type,
userId: this.userId
}, {transaction: options.transaction});
options.transaction.afterCommit(() => {
// Backend log entry instead of manual frontend emit; frontend is auto-updated via autoTable
this.logger.info(`Document created (id: ${doc.id}) by user ${this.userId}`);
});
return "Document successfully created";
}
What happens internally:
createSocket listens for “documentCreate” on the socket
When the event is triggered from the frontend:
The handler
createDocumentrunsA Sequelize transaction is opened and passed as
options.transaction
If the function completes without error:
The transaction is committed
The afterCommit hook logs a backend info message (no manual frontend emit is needed; updates are handled automatically via autoTable)
The frontend receives
{ success: true, data: "Document successfully created" }A success toast is displayed using that message
If an error is thrown:
The transaction is rolled back
The frontend receives
{ success: false, message: "..." }with the error messageAn error toast is displayed using that message
Socket functions
Annotation Socket Functions (annotation.js)
- class AnnotationSocket()
Handle all annotation through websocket
- AnnotationSocket.embedAnnotationsForDocument(data, options)
Socket Event: annotationEmbed
Embed all annotations into the PDF for a document.
- Arguments:
data (Object) – The data containing the document ID and other parameters.
options (Object) – Additional options for the emmfbedding process.
data.documentId (number) – The ID of the document to embed annotations into.
- Returns:
Promise.<Object> – The response from the PDFRPC embedAnnotations call.
- AnnotationSocket.getAnnotationsByDoc(data, options)
Socket Event: annotationGetByDocument
Returns the annotations for a given document by its id and sends the complete list to the client via an ‘annotationRefresh’ event.
- Arguments:
data – The request data containing the document identifier.
data.documentId (number) – the id of the document to retrieve the annotations for
options – Additional configuration parameters (currently unused).
- Returns:
Promise.<void> – A promise that resolves (with no value) once the annotations have been successfully fetched and sent to the client.
- AnnotationSocket.loadCommentsByAnnotation(annotationId)
Load all comments for a document by annotation. Errors during the database operation are caught and handled internally by logging the error and sending a toast notification to the client.
- Arguments:
annotationId (number) – The ID of the annotation whose comments are to be loaded.
- Returns:
Promise.<void> – A promise that resolves (with no value) once the comments have been sent or an error has been handled.
- AnnotationSocket.sendAnnotation(data, options)
Socket Event: annotationGet
Send an annotation to the client by id. A permission check is performed to ensure the user has access to the document containing the annotation.
- Arguments:
data (Object) – the input data from the frontend
options (Object) – Additional configuration parameters (currently unused).
data.annotationId (number) – the id of the annotation
- Throws:
Error – Throws an error if the user does not have permission to access the document associated with the annotation.
- Returns:
Promise.<*> – A promise that resolves (with no value) once the annotation and its comments have been processed and sent.
- AnnotationSocket.updateAnnotation(data, options)
Socket Event: annotationUpdate
Updates the annotations in the database. If the provided annotation is a new annotation, it will be created in the database otherwise the existing entry is overriden.
- Arguments:
data (Object) – the input data from the frontend
options (Object) – containing transactions
options.transaction – the DB transaction
data.annotationId (number) – the id of the annotation to update
data.documentId (number) – the id of the document to update
data.studySessionId (number) – the id of the study session
data.studyStepId (number) – the id of the study step
data.tagId (number) – the id of the tag
data.selectors (string) – the selectors of the annotation
data.deleted (boolean) – indicates if the data is deleted
data.anonymous (boolean) – indicates if the data is anonymous
- Throws:
Error – Throws an error if a user attempts to modify an annotation they do not have access to.
- Returns:
Promise.<void> – A promise that resolves (with no value) once the annotation has been saved and related events have been emitted.
App Socket Functions (app.js)
- class AppSocket()
Send data for building the frontend app
- AppSocket.sendData(data, options)
Socket Event: appData
Handles the ‘appData’ socket event. It acts as a wrapper to fetch and send filtered data from a specific table to the client.
- Arguments:
data (Object) – The input data from the frontend
data.table (String) – Table to send
data.filter (Object) – Filters
data.include (Object) – What data to include
options (Object) – holds the managed transaction of the database (see createSocket function)
- Returns:
Promise.<void> – Resolves when data is successfully retrieved and emitted to the client.
- AppSocket.sendDataByHash(data, options)
Socket Event: appDataByHash
Fetches and sends a single record from a specified table identified by a hash.
This function also serves as a permission check, ensuring data is only sent if found
- Arguments:
data (Object) – The input data from the frontend
data.hash (String) – The hash value
data.table (String) – Table to send the data from
options (Object) – Additional configuration parameter
options.transaction (Object) – A Sequelize DB transaction object for future use.
- Throws:
Error – Throws error if results is empty (no record found or operation fails)
- Returns:
Promise.<void> – A promise that resolves if the data is found and sent successfully
- AppSocket.sendInit(data, options)
Socket Event: appInit
Send all data needed for the frontend app for initialization.
Creates a series of socket events to provide user details, system tables, configuration settings, and system roles to the client.
- Arguments:
data (Object) – The input data from the frontend
options (Object) – Sequelize transaction options
options.transaction (Object) – Sequelize DB transaction options
- Returns:
Promise.<void> – Resolves once all the initial data has been sent successfully
- AppSocket.sendOverallSetting(data, options)
Socket Event: appSettingSet
Updates a single user-specific setting and then broadcasts the complete, refreshed settings to the client.
Saves the key–value pair for the current user in the database, then triggers an update by emitting the complete set of user settings to the client.
- Arguments:
data (Object) – The input data from the frontend
data.key (String) – The key in the user setting table
data.userId (String) – The user ID to set the setting for, if not provided, it will use the current user
data.value (String) – The value in the user setting table
options (Object) – Additional configuration parameter
- Returns:
Promise.<void> – A promise that resolves after the setting is saved and the new configuration is sent
- AppSocket.sendSettings(sendToAll=false)
Fetches and merges global application settings with user-specific settings, then sends the complete list to the client via a socket event.
- Arguments:
sendToAll (boolean) – [sendToAll=false] - If true, the settings are broadcast to all connected clients. If false, they are sent only to the client that initiated the request.
- Returns:
Promise.<void> – A promise that resolves (with no value) once the settings have been sent or an error has been caught and logged.
- AppSocket.sendSystemRoles()
Sends all the roles CARE has from the DB.
Retrieves role data from the database, including only role IDs and names, and emits it via the appSystemRoles socket event.
- Returns:
Promise.<void> – Resolves after the list of system roles has been successfully sent to the client via a socket event
- AppSocket.sendTables()
Gathers the schema for all models configured for automatic table generation if ‘autoTable = true’.
This structural data is then sent to the client via an ‘appTables’ socket event, allowing the frontend to dynamically generate tables or forms.
- Returns:
Promise.<void> – A promise that resolves (with no value) once the table schemas have been sent.
- AppSocket.sendUser()
Sends the user information for this user loaded from the db.
This includes core user data, associated role IDs, rights derived from those roles, and whether the user has administrative privileges. The data is emitted via the appUser socket event.
- Returns:
Promise.<void> – Resolves after the user information has been successfully sent to the client via a socket event
- AppSocket.subscribeAppData(data, options)
Socket Event: subscribeAppData
Subscribe to app data. Creates and manages a subscription for real-time updates on a specific database table.
Merges filters from all active subscriptions for a table and sends the client the initial data set required for the new subscription
- Arguments:
data (Object) – The configuration for the data subscription
data.table (string) – The name of the database table to subscribe to
data.filter (Array.<Object>) – An optional filter array (e.g., Sequelize ‘where’ conditions) to specify a subset of data
data.inject (Array.<Object>) – Optional instructions for including related data (e.g., Sequelize ‘include’ models)
options (Object) – Additional configuration parameters
options.transaction (Object) – May contain a Sequelize DB transaction for future use
- Throws:
Error – Throws an error if data.table is not provided
- Returns:
Promise.<string> – A promise that resolves with the unique ID for the newly created subscription
- AppSocket.unsubscribeAppData(data, options)
Socket Event: unsubscribeAppData
Unsubscribe from app data, removes a data subscription for the client.
Removes the corresponding data subscription entry from the socket’s internal tracking lists based on the provided identifier.
- Arguments:
data (Object) – The input data from the frontend. The identifier for the subscription to remove
options (Object) – Additional configuration parameter
- Returns:
Promise.<void> – A promise that resolves once the subscription has been removed from the tracking lists
- AppSocket.updateAppData(data, options)
Socket Event: appDataUpdate
Update data for a specific table to the client.
Acts as a wrapper around the underlying updateData method, using a Sequelize transaction if provided, and returns the outcome to the caller.
- Arguments:
data (Object) – The input data from the frontend
options (Object) – Additional configuration parameter
options.transaction (Object) – Sequelize DB transaction options
- Returns:
Promise.<*> – A promise that resolves with the result from the underlying updateData method
- AppSocket.updateData(data, options)
A generic and powerful method to create or update records in a specified database table.
It determines whether to create a new record or update an existing one based on the presence of an id in the data.data payload. The function includes schema-based validation for required fields, handles default values, and supports recursive updates for nested table data.
Note: This works only for autoTable tables (see documentation for more information)
- Arguments:
data (Object) – The input data from the frontend
data.table (String) – The name of the table to update
data.data (Object) – New data to update
options (Object) – holds the managed transaction of the database (see createSocket function)
options.transaction (Object) – Sequelize DB transaction options
- Throws:
Error – Throws an error under several conditions: If a non-admin user attempts to update a record for another user, If a required field (as defined in the model’s schema) is missing from the data.data payload, If the database operation fails to return a new or updated entry after an add/update call.
- Returns:
Promise.<void> – A promise that resolves with the ID of the newly created or updated primary record.
Assignment Socket Functions (assignment.js)
- class AssignmentSocket()
Handle user through websocket
- AssignmentSocket.addReviewer(data, options)
Socket Event: assignmentAdd
Adds new sessions to a study.
If the number of reviewers being added exceeds the current session limit of the study, the session limit is updated accordingly. Each reviewer is added as a new study_session.
- Arguments:
data (Object) – The data for adding reviewers.
data.studyId (number) – The ID of the study to which reviewers are to be added.
data.reviewer (Array.<number>) – An array of user IDs representing the reviewers to be added.
options (Object) – holds the managed transaction of the database (see createSocket function)
- Returns:
Promise.<void> – A promise that resolves when the reviewers have been added to the study.
- AssignmentSocket.createAssignment(data, options)
Socket Event: assignmentCreate
Assigns a peer review task to a list of reviewers based on a given template.
Constructs a study from the provided template and assignment data, assigns it to the specified user, and links it to the given documents. Reviewers are then associated with the study.
- Arguments:
data (Object) – The data for assigning peer reviews.
data.assignment (Object) – The assignment object containing details of the assignment.
data.reviewers (Array) – An array of reviewer IDs who will be assigned to the peer review.
data.template (Object) – The template object containing the configuration for the peer review.
data.documents (Array) – The documents to be reviewed.
options (Object) – holds the managed transaction of the database (see createSocket function)
- Returns:
Promise.<void> – A promise that resolves when the peer review has been assigned.
- AssignmentSocket.createAssignmentBulk(data, options)
Socket Event: assignmentCreateBulk
Creates multiple assignments based on the provided data.
Two assignment modes are supported: - “role”: reviewers are grouped by their roles, and documents are assigned to users in each role. - “reviewer”: reviewers are explicitly selected, and assignments are distributed to them directly.
In both cases, the function ensures: - A reviewer never reviews their own document. - Fair distribution of review tasks. - A fallback swapping mechanism is used if optimal assignment fails.
- Arguments:
data – The data for creating assignments.
data.template (Object) – The template to be used for the assignments.
data.selectedReviewer (Array.<Object>) – An array of reviewer objects to be assigned to the assignments.
data.selectedAssignments (Array.<Object>) – An array of assignment objects to be reviewed.
data.mode (String) – The mode of the assignment creation (i.e, role or reviewer)
data.documents (Array.<Array>) – List of document assignments
data.roleSelection (Object) – If the mode is role, the role selection object
data.reviewerSelection (Object) – If the mode is reviewer, the reviewer selection object
options – holds the managed transaction of the database (see createSocket function), passed down to the individual assignment creation step.
- Throws:
Error – Throws an error under several conditions: If an invalid data.mode is provided, In ‘role’ mode: if no users are found for a selected role, In ‘role’ mode: if there are not enough unique documents to satisfy the assignment requirements for a role or a specific user, In ‘role’ mode: if the algorithm is unable to find a valid assignment for a user, even after attempting to swap, In ‘reviewer’ mode: if the algorithm cannot assign all reviewers after attempting to swap, If the underlying this.createAssignment method fails.
- Returns:
Promise.<void> – A promise that resolves with an object detailing the final assignment distribution.
- AssignmentSocket.getAssignmentInfoFromCourse(data)
Socket Event: assignmentGetInfo
Retrieve all the assignments a course has.
- Arguments:
data (Object) – The data required for getting the relevant assignment info.
data.options (Object) – The options object containing the API key and URL of the Moodle instance.
data.options.courseID (number) – The ID of the course to fetch users from.
data.options.apiKey (string) – The API token for the Moodle instance
data.options.apiUrl (string) – The URL of the Moodle instance.
- Returns:
Promise.<ArrayLike.<T>> – A promise that resolves with an array of assignment objects from Moodle.
- AssignmentSocket.replaceTemplateValues(config, context, options)
Recursively processes template markers in a configuration object and adds appropriate ID properties.
This method processes configuration objects, arrays, and nested structures, identifying template markers (objects with isTemplate === true) and adding the appropriate ID property based on the assignment type. For submission assignments, it adds submissionId; for document assignments, it adds documentId. The original template object properties are preserved.
- Arguments:
config (Object|Array) – The configuration object or array to process. Can contain nested objects and arrays.
context (Object) – The context object containing assignment information.
context.assignmentType (string) – The type of assignment (‘submission’ or ‘document’).
context.documentId (number|null) – The document ID to use when assignmentType is ‘document’.
context.submissionId (number|null) – The submission ID to use when assignmentType is ‘submission’.
options (Object) – The options object (currently unused but kept for API consistency).
- Returns:
Promise.<(Object|Array)> – A promise that resolves with the configuration object with ID properties added to template markers.
Collab Socket Functions (collab.js)
- class CollabSocket()
Handle collaboration through sockets
- CollabSocket.updateCollab(data, options)
Socket Event: collabUpdate
Updates the collaboration status in the database. If there is non existent on the given entity, it will create one, otherwise it will be updated.
- Arguments:
data (Object) – the input collab object
data.collabId (number) – the id of the collaboration if existent
data.documentId (number) – The ID of the document being collaborated on. Required when creating a new record.
options (Object) – Additional configuration, primarily for database transactions.
options.transaction (Object) – A Sequelize DB transaction object to ensure atomicity.
- Throws:
Error – Throws an error if the database updateById or add operations fail.
- Returns:
Promise.<void> – A promise that resolves once the database operation is complete and events have been emitted.
Document Socket Functions (document.js)
- class DocumentSocket()
Handle all document through websocket
Loading the document through websocket
- DocumentSocket.addDocument(data, options)
Uploads the given data object as a document.
Stores the given pdf file in the files path and creates an entry in the database.
- Arguments:
data (Object) – The data object containing the document details.
data.name (string) – The name of the document.
data.file (Buffer) – The binary content of the document.
data.importAnnotations (boolean) – indicates whether to import annotations from the PDF (optional).
data.submissionId (number) – The submission that the document will belong to.
data.userId (number) – The ID of the user who owns the document (optional).
data.projectId (number) – The ID of the project the document belongs to (optional).
data.isUploaded (boolean) – Indicates if the document is uploaded by an admin (optional).
options (Object) – The options object containing the transaction.
- Returns:
Promise.<void>
- DocumentSocket.checkDocumentAccess(documentId)
Check if user has rights to read the document data
The user has access to the document if:
The document is public
The document is owned by the user
The user is an admin
The document is used in a study where the user is a participant
- Arguments:
documentId – The ID of the document for which access is being checked.
- Returns:
Promise.<boolean> – A promise that resolves with true if the user has access, and false otherwise.
- DocumentSocket.checkSubmissionsExist(data, options)
Check a list of submissions if they have already existed in the database by extId
- Arguments:
data – The data object containing the submissions to check at least extId key is required
options – The options object
- Returns:
Promise.<Array.<Object>> – An array of objects containing the status of the submissions
- DocumentSocket.closeDocument(data, options)
Close the document and save it if necessary.
This method saves the document if there is no study session and removes the document from the list of open documents.
- Arguments:
data (object) – The data object containing documentId and studySessionId.
data.documentId (number) – The ID of the document to close.
data.studySessionId (number) – The ID of the study session.
options (object) – Additional configuration parameters.
- Returns:
Promise.<void> – A promise that resolves (with no value) once the document has been processed.
- DocumentSocket.createDocument(data, options)
Creates a new HTML-based document record in the database.
- Arguments:
data (Object) – The data for the new document.
data.name (string) – The name of the new document.
data.type (number) – The type identifier for the document (e.g., HTML, MODAL).
options (Object) – The options object containing the transaction.
- Returns:
Promise.<Object> – A promise that resolves with the newly created document’s database record.
- DocumentSocket.documentGetMoodleSubmissions(data, options)
Get Moodle submissions from an assignment. This function acts as a wrapper, forwarding the request to the MoodleRPC service.
- Arguments:
data (Object) – The data required for fetching the submission information.
data.options (Object) – The configuration object for the Moodle API connection.
data.options.courseID (number) – The ID of the Moodle course.
data.options.assignmentID (number) – The ID of the Moodle assignment.
data.options.apiKey (string) – The Moodle API token required for authentication.
data.options.apiUrl (string) – The base URL of the Moodle instance.
options (Object) – Additional configuration parameters (currently unused).
- Returns:
Promise.<Array.<Object>> – A promise that resolves with an array of submission objects returned from the Moodle service.
- DocumentSocket.downloadMoodleSubmissions(data, options)
Downloads multiple submission files from Moodle URLs, creating a local document record for each one. Each file is processed in its own database transaction to ensure atomicity. Progress is reported to the client via a socket event after each file is processed.
- Arguments:
data (Object) – The input data from the frontend
data.submissions (Array.<Object>) – The submissions from Moodle
data.options (Object) – The configuration options (e.g., API key, URL) passed to the Moodle RPC service
data.progressId (string) – The unique ID used for reporting progress back to the frontend.
data.group (number) – The group number to be assigned to the submissions
data.validationConfigurationId (number) – Configuration ID referring to the validation schema
options (Object) – Additional configuration parameters
options.transaction (Object) – Sequelize DB transaction options
- Throws:
Error –
If the download fails, if the assignment ID is invalid, or if saving to server fails
- Returns:
Promise.<Array.<T>> – - The results of the processed submissions
- DocumentSocket.editDocument(data, options)
Socket Event: documentEdit
Edits the document based on the provided data.
This method is called when the client requests to edit a document. It first checks if the user has access to the document, and if so, it applies the edits to the document and sends the updated document to the client.
- Arguments:
data (Object) – The data payload containing the edits and their context.
data.documentId (number) – The ID of the document being edited.
data.ops (Array.<Object>) – An array of edit operations, where each object represents a single change (e.g., insert, delete).
data.studySessionId (number) – If provided, associates the edits with a study session and suppresses the client-side event emission.
data.studyStepId (number) – If provided, associates the edits with a specific study step.
options (Object) – The options object containing the transaction.
options.transaction (Object) – A Sequelize DB transaction object to ensure all edits are added atomically.
- Returns:
Promise.<void> – A promise that resolves (with no value) once all edits have been processed and saved.
- DocumentSocket.getData(data, options)
Fetches and sends a comprehensive set of data related to a document, with behavior that varies significantly based on the document type and user context.
For HTML documents, it defers to this.getDocument. For other types, it sends annotations, comments, votes, and tags based on the following logic:
If a studySessionId is provided and the study is collaborative, it sends data from ALL participants.
If a studySessionId is provided and the study is NOT collaborative, it sends data for the CURRENT session only.
If no studySessionId is provided, it sends data from closed studies or data not linked to any session.
- Arguments:
data (Object) – The request data specifying the context.
data.documentId (number) – The ID of the document to fetch data for.
data.studySessionId (number) – The ID of the current study session, if applicable.
data.studyStepId (number) – The ID of the current study step, required when a studySessionId is provided.
options (Object) – Additional configuration parameters (passed down to sub-methods).
- Returns:
Promise.<void> – A promise that resolves (with no value) once all relevant data has been fetched and emitted to the client.
- DocumentSocket.getDocument(data, options)
Send a document to the client
This method checks if the user has access to the document and then retrieves and sends the document data. For HTML documents, it fetches and combines draft edits with the existing content before sending.
- Arguments:
data (Object) – The data required to fetch the document and its specific version.
data.documentId (number) – The ID of the document to retrieve.
data.studySessionId (number) – The ID of the study session, used to scope document edits.
data.studyStepId (number) – The ID of the study step, used to scope document edits.
data.history (boolean) – If true, emits the edit history instead of returning composed content.
options (Object) – Additional configuration parameters.
options.transaction (Object) – A Sequelize DB transaction object (passed to underlying functions).
- Throws:
Error – Throws an error under the following conditions: If the user does not have access to the requested document, If the document’s delta file (.delta) for an HTML document is missing from the filesystem, If the document’s PDF file (.pdf) for a PDF document is missing from the filesystem.
- Returns:
Promise.<({document: Document, deltas: Delta}|{document: Document, file: Buffer})> – A promise that resolves with an object containing the document metadata and its content, which is either a Quill Delta object for HTML types or a file Buffer for other types.
- DocumentSocket.getDocumentData(data, options)
Retrieve document data for a particular document/study_session/study_step from the document_data table.
- Arguments:
data (Object) – The data payload containing the retrieval parameters.
data.documentId (number) – The ID of the associated document.
data.studySessionId (number) – The ID of the associated study session.
data.studyStepId (number) – The ID of the associated study step.
data.key (string) – The key for the data being retrieved (e.g., ‘assessment_results’).
options (Object) – Additional configuration for the operation.
options.transaction (Object) – A Sequelize DB transaction object to ensure atomicity.
- Returns:
Promise.<Object> – A promise that resolves with the retrieved document_data record object from the database.
- DocumentSocket.getPreviousStepId(studyStepId)
Helper method to get the previous step ID for a given study step ID
- Arguments:
studyStepId (number) – The ID of the study step
- Returns:
Promise.<(number|null)> – The ID of the previous study step, or null if not found
- DocumentSocket.loadDocument(filePath)
Load document delta from disk (for HTML documents) This method reads the delta file from the disk and returns it as a Delta object.
- Arguments:
filePath (string) – The absolute path to the delta file to be loaded.
- Throws:
Error – Throws an error if the file cannot be read (e.g., file not found, permissions error) or if the file content is not valid JSON.
- Returns:
Promise.<Delta> – A promise that resolves with a new Delta object representing the file’s content.
- DocumentSocket.openDocument(data, documentId, options)
Open the document and track it, if not already tracked
This method adds the document to the list of open documents, being tracked by the socket.
- Arguments:
data (object) – The data object containing the documentId.
documentId (number) – The ID of the document to open and track.
options (object) – Additional configuration parameters
- Returns:
Promise.<void> – A promise that resolves (with no value) once the document is being tracked.
- DocumentSocket.publishDocument(data, options)
Socket Event: documentPublish
Makes a document publicly accessible by setting its ‘public’ flag to true. This operation is only permitted if the current user has access rights to the document’s owner. Upon success, it emits a ‘documentRefresh’ event with the updated document.
- Arguments:
data (object) – The data object containing the document identifier.
data.documentId (number) – The ID of the document to publish.
options (object) – The options object containing the transaction.
- Throws:
Error – Throws an error if the user does not have permission to publish the document, or if any underlying database operation fails.
- Returns:
Promise.<void> – A promise that resolves (with no value) once the document is successfully published and the event is emitted.
- DocumentSocket.publishReviewLinks(data)
Uploads review links to a Moodle assignment as feedback comments.
- Arguments:
data (Object) – The data required for uploading login data.
data.options (Object) – The options object containing the API key and URL of the Moodle instance.
data.options.courseID (number) – The ID of the course to fetch users from.
data.options.assignmentID (number) – The ID of the Moodle assignment.
data.options.apiKey (string) – The API token for the Moodle instance
data.options.apiUrl (string) – The URL of the Moodle instance.
data.feedback (Array.<Object>) – An array of objects containing the feedback to send
- Returns:
Promise.<Object> – A promise that resolves when the passwords have been uploaded.
- DocumentSocket.refreshAllDocuments(data, options)
Refresh all documents. Fetches a list of documents and emits them to the client via a ‘documentRefresh’ event. The scope of the documents sent depends on the user’s administrative rights and the provided parameters.
Non-admins will only receive their own documents.
Admins can receive all documents, or filter for a specific user’s documents.
- Arguments:
data (Object) – The data object containing the request parameters.
data.userId (number) – For administrators only. If provided, fetches documents belonging to this specific user ID. If omitted, all documents are fetched.
options (Object) – Additional configuration parameters (currently unused).
- Returns:
Promise.<void> – A promise that resolves (with no value) once the document list has been successfully fetched and emitted.
- DocumentSocket.saveData(data, options)
Save additional document data for a particular document/study_session/study_step like the nlpResults, links etc., to the document_data table.
- Arguments:
data (Object) – The data payload to be saved.
data.documentId (number) – The ID of the associated document.
data.studySessionId (number) – The ID of the associated study session.
data.studyStepId (number) – The ID of the associated study step.
data.key (string) – The key for the data being stored (e.g., ‘nlpResults’).
data.value (any) – The value to be stored, which can be any serializable type.
options (Object) – Additional configuration for the operation.
options.transaction (Object) – A Sequelize DB transaction object to ensure atomicity.
- Returns:
Promise.<Object> – A promise that resolves with the upserted document_data record object from the database.
- DocumentSocket.saveDocument(documentId)
Save document delta to disk and mark edits as applied (for HTML documents) This method saves the combined delta of the document on the disk and updates the edits in the database to mark them as applied.
- Arguments:
documentId (number) – The ID of the document to save.
- Throws:
Error – Throws an error if: The document is not of a supported type (HTML or MODAL), Reading from or writing to the filesystem fails for reasons other than the initial file not existing, Any of the underlying database operations (getById, findAll, update) fail.
- Returns:
Promise.<void> – A promise that resolves (with no value) upon successful completion. Note: The function returns early without error if the document ID is not found.
- DocumentSocket.sendByHash(data, options)
Socket Event: documentGetByHash
Send document by hash.
Fetches a document by its hash, checks for user access, and then either sends the document or a “toast” error message to the client.
- Arguments:
data (object) – The data object containing the document hash.
data.documentHash (string) – The hash of the document to send.
options (object) – The options object containing the transaction.
- Returns:
Promise.<void> – A promise that resolves (with no value) once the operation (either sending the document or a toast) is complete.
- DocumentSocket.sendDocumentDeltas(data, options)
Send merged deltas (from disk and database) to client (for HTML documents)
- Arguments:
data (object) – The request data containing the document identifier.
data.documentId (number) – The ID of the document to send deltas for.
options (object) – The options for the transaction.
- Throws:
Error – Throws an error if: The user does not have access to the document, The document is not of a supported type (HTML or MODAL).
- Returns:
Promise.<void> – A promise that resolves with the final, composed Delta object representing the document’s current state.
- DocumentSocket.subscribeDocument(data, options)
Subscribe the client’s socket to a document-specific communication channel.
- Arguments:
data (Object) – The data object containing the document identifier.
data.documentId (number) – The ID of the document to subscribe to.
options (Object) – The options object containing the transaction.
- Returns:
Promise.<void> – A promise that resolves (with no value) once the subscription command has been executed.
- DocumentSocket.unsubscribeDocument(data, options)
Unsubscribe from a document
- Arguments:
data (Object)
data.documentId (number) – The ID of the document to unsubscribe from.
options (Object) – The options object containing the transaction.
- Returns:
Promise.<void>
- DocumentSocket.updateDocument(data, options)
Updates a document’s properties after verifying the current user has ownership rights.
- Arguments:
data – The data object containing the new document object.
data.id (number) – The ID of the document to be updated.
options – The options object containing the transaction.
- Returns:
Promise.<void> – A promise that resolves (with no value) once the update operation is complete and the ‘afterCommit’ hook is registered.
- DocumentSocket.uploadSingleSubmission(data, options)
Upload a single submission to the DB.
- Arguments:
data (Object) – The input data from the frontend
data.userId (number) – The ID of the user who owns the submission
data.files (Array.<Object>) – The submissions files
data.group (number) – The group number to be assigned to the submissions
data.validationConfigurationId (number) – Configuration ID referring to the validation schema
options (Object) – Additional configuration parameters
options.transaction (Object) – Sequelize DB transaction options
- Throws:
Error –
If the upload fails, or if saving to server fails
- Returns:
Promise.<Array.<T>> – - The result of the processed submission
Logger Socket Functions (log.js)
- class LoggerSocket()
Handle logs through websocket
- LoggerSocket.getAllLogs(data, options)
Socket Event: logGetAll
Get log messages.
This operation is restricted to users with administrator privileges.
- Arguments:
data – The log entry selection criteria
data.filter – An object defining filters for the log entries (e.g., by level or source).
data.order – An array specifying the order of the results.
data.limit – The maximum number of log entries to return.
data.page – Log entry page
options – Additional configuration parameters.
- Returns:
Promise<void>} A promise that resolves (with no value) once the logs have been sent to the client, or immediately if the user is not an admin.
- LoggerSocket.log(data, options)
Socket Event: log
Log a message received from the client, if frontend logging is enabled via environment variables
- Arguments:
data (Object) – The log entry payload.
data.level (string) – The log level (e.g., ‘info’, ‘warn’, ‘error’).
data.message (string) – The primary message to be logged.
data.meta (Object) – Optional metadata to include with the log entry.
options (Object) – Additional configuration parameters.
- Returns:
Promise.<void> – A promise that resolves (with no value) once the log attempt is complete.
Service Socket Functions (service.js)
- class ServiceSocket()
Handling Services through websockets
- ServiceSocket.connectService(data, options)
Socket Event: serviceConnect
Connects a service to the client
- Arguments:
data (Object) – The input data
data.service (string) – The name of the service to connect
data.data (Object) – Additional data to pass to the service
options (Object) – Additional configuration parameters (currently unused).
- Returns:
Promise.<void> – A promise that resolves (with no value) once the service connection attempt is complete.
- ServiceSocket.disconnectService(data, options)
Socket Event: serviceDisconnect
Disconnects a service from the client
- Arguments:
data (Object) – The input data
data.service (string) – The name of the service to disconnect
data.data (Object) – Additional data to pass to the service
options (Object) – Additional configuration parameters (currently unused).
- Returns:
Promise.<void> – A promise that resolves (with no value) once the service disconnection attempt is complete.
- ServiceSocket.requestService(data, options)
Socket Event: serviceRequest
Request a service (with default command)
- Arguments:
data (Object) – The input data
data.service (string) – The name of the service to disconnect
data.data (Object) – Additional data to pass to the service
options (Object) – Additional configuration parameters (currently unused).
- Returns:
Promise.<void> – A promise that resolves (with no value) once the service request attempt is complete.
- ServiceSocket.serviceCommand(data, options)
Socket Event: serviceCommand
Request a service but with a specific command
- Arguments:
data (Object) – The input data
data.service (string) – The name of the service to disconnect
data.data (Object) – Additional data to pass to the service
options (Object) – Additional configuration parameters (currently unused).
- Returns:
Promise.<void> – A promise that resolves (with no value) once the service command attempt is complete.
Setting Socket Functions (setting.js)
- class SettingSocket()
Handle settings through websocket
- SettingSocket.saveSettings(data, options)
Socket Event: settingSave
Save settings to the database
- Arguments:
data (Array.<{key: string, value: any}>) – List of settings to be saved
options (object) – Context passed through the socket pipeline
options.transaction (Object) – A Sequelize DB transaction object to ensure all settings are saved atomically.
- Throws:
Error – Throws an error if the requesting user is not an administrator.
- Returns:
Promise.<string> – A promise that resolves with a success message once the save operations are queued within the transaction.
- SettingSocket.sendSettings(data, options)
Socket Event: settingGetData
Fetches all system settings from the database. This operation is restricted to users with administrator privileges.
- Arguments:
data (any) – Currently unused.
options (object) – Additional configuration parameters (currently unused).
- Throws:
Error – Throws an error if the requesting user is not an administrator.
- Returns:
Promise.<Array.<{key: string, value: any}>> – All settings in flat key-value format
Statistic Socket Functions (statistic.js)
- class StatisticSocket()
Add statistics about the website usage
Therefore, use in frontend:
this.$socket.emit(“stats”, {action: “action”, data: {}});
The data object can hold additional information!
- StatisticSocket.addStats(data, options)
Socket Event: stats
Adds a new statistic entry to the database for the current user. This function is only performed if the user has consented to statistics collection (acceptStats is true). Errors during the database operation are caught and logged internally.
- Arguments:
data (Object) – The data object containing the userId
data.action (Number) – The type of action (e.g. ‘mouseMove’)
options (Object) – Additional configuration parameters (currently unused).
- Returns:
Promise.<void> – A promise that resolves (with no value) once the statistic has been processed.
- StatisticSocket.getStats(data, options)
Socket Event: statsGet
Fetches system statistics, either for all users or a specific user. This function is restricted to users with administrator privileges.
- Arguments:
data (Object) – The data object containing the userId
data.userId (Number) – The userId to get statistics for (optional)
options (Object) – Additional configuration parameters (currently unused).
- Throws:
Error – Throws an error if the requesting user is not an administrator.
- Returns:
Promise.<Object> – A promise that resolves with an array of statistic record objects from the database.
- StatisticSocket.sendStatsByUser(data, options)
Send statistics to the user This function is restricted to administrators and will only send data if the target user has consented to statistics collection (acceptStats is true).
- Arguments:
data.userId (number) – The ID of the user whose statistics are to be fetched.
options (Object) – Additional configuration parameters (currently unused).
- Returns:
Promise.<void> – A promise that resolves (with no value) after the operation is complete.
Study Session Socket Functions (study_session.js)
- class StudySessionSocket()
Handle all study sessions through websocket
Loading the study sessions through websocket
- StudySessionSocket.sendSessionsByStudyId(studyId)
Send all study sessions to the client If the user has access, it emits a ‘study_sessionRefresh’ event with the session data. If access is denied, it sends a toast notification to the client with an error message.
- Arguments:
studyId – The ID of the study whose sessions are to be fetched and sent.
- Returns:
Promise.<void> – A promise that resolves (with no value) once the sessions have been sent or the access-denied notification has been sent.
- StudySessionSocket.startStudySession(data, options)
Socket Event: studySessionStart
Start a study session by either updating the start time of an existing session or creating a new one.
- Arguments:
data (object) – The data required to start the session.
data.studyId (number) – The ID of the study to create a new session for. Required if studySessionId is not provided.
data.studySessionId (number) – The ID of an existing study session to update. If omitted, a new session is created.
options (object) – Configuration for the database operation.
options.transaction (Object) – A Sequelize DB transaction object to ensure atomicity.
- Returns:
Promise.<void> – A promise that resolves with the newly created or updated study session object from the database.
- StudySessionSocket.subscribeToStudySession(data, options)
Socket Event: studySessionSubscribe
Subscribes the client to a study-specific communication channel and sends the initial list of sessions. This allows the client to receive real-time events for the study and get the current state.
- Arguments:
data (object) – The data object containing the study identifier.
data.studyId (number) – The ID of the study to subscribe to.
options (object) – Additional configuration parameters (currently unused).
- Returns:
Promise.<void> – A promise that resolves (with no value) once the client has subscribed and the initial session data has been sent.
- StudySessionSocket.unsubscribeFromStudySession(data, options)
Socket Event: studySessionUnsubscribe
Unsubscribes the client’s socket from a study-specific communication channel. This stops the client from receiving real-time events for that study.
- Arguments:
data (object) – The data object containing the study identifier.
data.studyId (number) – The study id
options (object) – Additional configuration parameters (currently unused).
- Returns:
Promise.<void> – This function does not return a value.
Study Socket Functions (study.js)
- class StudySocket()
Handle all studies through websocket
Loading the studies through websocket
- StudySocket.closeBulk(data, options)
Socket Event: studyCloseBulk
Closes all studies associated with a given project ID in a loop. Each study is updated in its own database transaction. Progress is reported to the client after each study is processed.
- Arguments:
data – The data required for the bulk close operation.
data.projectId – the project ID of the studies to close
data.ignoreClosedState – if true, also close studies that are already closed
data.progressId – the ID of the progress bar to update
options – Additional configuration parameters (currently unused).
- Returns:
Promise.<void> – A promise that resolves (with no value) once all studies in the project have been processed.
- StudySocket.saveStudyAsTemplate(data, options)
Socket Event: studySaveAsTemplate
Creates a new study template based on an existing study or directly from data. This operation is restricted to the owner of the original study or an administrator.
- Arguments:
data (object) – The data object containing the identifier for the source study or template data.
data.id (number) – the ID of the study to save as template (required if onlyTemplate is false)
data.onlyTemplate (boolean) – if true, creates template directly from provided data without creating a study
data.templateData (object) – the template data when onlyTemplate is true
options (object) – Configuration for the database operation.
options.transaction (Object) – A Sequelize DB transaction object.
- Throws:
Error – Throws an error if the user does not have permission to access the source study.
- Returns:
Promise.<*> – A promise that resolves with the newly created study template object from the database.
User Socket Functions (user.js)
- class UserSocket()
Handle user through websocket
- UserSocket.bulkCreateUsers(data, users, roleMap)
Socket Event: userBulkCreate
Creates or updates a list of users in bulk. Each user is processed in an isolated database transaction. Errors for individual users are caught, logged, and added to an error array without halting the entire process. Progress is reported to the client.
- Arguments:
data (Object) – The data object containing the users and role map
users – Users to be created or updated
roleMap (Object) – A role map that maps an external platform roles to CARE roles
- Returns:
Promise.<{createdUsers: Array, errors: Array}> – An object containing the created users and errors
- UserSocket.checkUsersExists(data, options)
Socket Event: userCheckExistsByMail
Check a list of users if they already exist in the database by email
- Arguments:
data – The data object containing the users to check at least email key is required
options – The options object
- Returns:
- UserSocket.createUser(data, options)
Socket Event: userCreate
Adds a new user to the database. This operation is restricted to users with administrator privileges.
- Arguments:
data – An object containing the properties for the new user record
options – Configuration for the database operation.
- Throws:
Error – Throws an error if the requesting user is not an administrator.
- Returns:
Promise.<*> – A promise that resolves with the newly created user object from the database.
- UserSocket.getUsers(role)
Get users by their role.status === “duplicate”
- Arguments:
role (string) – The role of the users to fetch. Possible values: “student”, “mentor”, “all”
- Returns:
Promise.<(Array.<Object>|void)> – A promise that resolves with an array of user objects if successful, or with no value if the user lacks permission or an error occurs.
- UserSocket.getUsersByRole(data, options)
Socket Event: userGetByRole
Get users by their role
- Arguments:
data (Object) – The input data from the frontend
data.role (string) – The role of the user
options (Object) – Additional configuration parameter
options.transaction (Object) – Sequelize DB transaction options
- Throws:
Error – If the user does not have right
- Returns:
Promise.<void> – A promise that resolves (with no value) once the data or an error message has been emitted.
- UserSocket.getUsersFromCourse(options)
Socket Event: userMoodleUserGetAll
Retrieves a list of users from a Moodle course via an RPC call. The returned user data is then augmented with an external ID and checked for local existence in the database. The external moodle API is called here through Moodle RPC
- Arguments:
options (Object) – The data object containing the course ID, Moodle URL and the API token.
options.courseID (number) – The ID of the course to fetch users from.
options.options.apiKey (string) – The API token for the Moodle instance
options.options.apiUrl (string) – The URL of the Moodle instance.
- Returns:
Promise.<*> – The response from the RPC service
- UserSocket.minimalFields(user)
Filters a user object to include only a predefined set of essential fields. This is useful for sending minimal, non-sensitive user information to clients.
- Arguments:
user (object) – The user object
- Returns:
Object – A new object containing only the allowed fields (e.g., ‘id’, ‘userName’) from the original user object.
- UserSocket.resetUserPwd(data, options)
Socket Event: userResetPwd
Reset user’s password A user can only reset their own password unless they are an administrator.
- Arguments:
data (Object) – The input data from the frontend
data.userId (number) – The ID of the user
data.password (string) – The new password
options (Object) – Additional configuration parameter
options.transaction (Object) – Sequelize DB transaction options
- Throws:
Error – If the user is not an admin or the user tries to reset other’s password
- Returns:
Promise.<void> – A promise that resolves (with no value) once the password has been successfully reset.
- UserSocket.updateCreatorName(data, key="userId", targetName="creator_name")
Adds the username as creator_name of a database entry with column creator
Accepts data as a list of objects or a single object Note: Always returns a list of objects
- Arguments:
data (object|Array.<object>) – The data to update
key (string) – The key of the user ID field
targetName (string) – The name of the target field
- Returns:
- UserSocket.updateUserConsent(data, options)
Socket Event: userConsentUpdate
Update user’s consent data It first verifies the user exists before proceeding with the update.
- Arguments:
data (Object) – The consent data object
data.acceptTerms (boolean) – Indicates whether the user has consented to the terms of service
data.acceptStats (boolean) – Indicates whether the user has agreed to tracking
data.acceptDataSharing (boolean) – Indicates whether the user has agreed to donate their annotation data
data.acceptedAt (string) – Time when the user made the consent
options (Object) – Sequelize transaction options
options.transaction (Object) – A Sequelize DB transaction object.
- Throws:
Error – Throws an error if the current user cannot be found in the database.
- Returns:
Promise.<Object> – A promise that resolves with the updated user object, excluding sensitive and timestamp fields.
- UserSocket.userPublishMoodle(data)
Socket Event: userPublishMoodle
Uploads login data to a Moodle assignment as feedback comments through Moodle RPC.
- Arguments:
data (Object) – The data required for uploading login data.
data.options (Object) – The options object containing the API key and URL of the Moodle instance.
data.options.courseID (number) – The ID of the course to fetch users from.
data.options.assignmentID (number) – The ID of the Moodle assignment.
data.options.apiKey (string) – The API token for the Moodle instance
data.options.apiUrl (string) – The URL of the Moodle instance.
data.users (Array.<Object>) – An array of objects containing the uploaded users.
- Returns:
Promise.<Object> – A promise that resolves when the passwords have been uploaded.
Comment Socket Functions (comment.js)
Loading the comments through websocket
Adds a new comment to the database after verifying user permissions.
data (Object) – The data required to create the new comment.
data.documentId (number) – The ID of the document the comment belongs to.
data.studySessionId (number) – The ID of the study session associated with the comment.
data.studyStepId (number) – The ID of the study step associated with the comment.
data.text (string) – The content of the comment.
data.userId (number|string) – The ID or name of the user creating the comment. Defaults to the current user if omitted.
data.draft (boolean) – Whether the comment is a draft (defaults to true if not provided).
data.annotationId (number) – The ID of the associated annotation, if any.
data.parentCommentId (number) – The ID of the parent comment, if this is a reply.
data.anonymous (boolean) – Whether the comment should be anonymous (defaults to false).
options (Object) – Additional configuration parameters.
Error – Throws an error if the user is not authorized to add the comment (permission check failure), or if any database operation fails.
Promise.<void> – A promise that resolves (with no value) once the comment is successfully added and the event is emitted.
Socket Event: commentUpdate
Add or update a comment if it has already existed.
Calls either addComment or updateComment based on the presence of commentId.
data (object) – The input data from the frontend
data.commentId (number) – The id of the comment
options (object) – holds the transaction
Error – Throws an error if the underlying updateComment or addComment function fails. This can be due to permission violations or database-level errors.
Promise.<void> – A promise that resolves (with no value) once the underlying add or update operation is complete.
Socket Event: commentGetByDocument
Retrieve all comments associated with a specific document.
Fetches comments by document ID and sends them to the client.
data (object) – The input data from the frontend
data.documentId (number) – The ID of the document whose comments are to be fetched.
options (object) – Additional configuration parameters, not used
Error – Throws an error if the database operation to fetch the comments fails.
Promise.<void> – A promise that resolves (with no value) once the comments have been successfully fetched and sent to the client.
Socket Event: commentGet
Send a comment to the client.
Fetches a single comment by its ID and sends it to the client after verifying access rights.
data (object) – The input data from the frontend
data.commentId (number) – The id of the comment
options (object) – not used
Error – Throws an error if the user does not have access to the document the comment is on, or if the comment ID does not exist in the database.
Promise.<void> – A promise that resolves after the comment has been successfully sent to the client.
Update comments in the database after verifying the user has permission to edit it.
data (Object) – containing the inputs
data.commentId (number) – the id of the comment
data.comment (object) – the comment object
options (object) – containing transaction
Error – Throws an error if the user is not allowed to edit the comment, or if any database operation fails.
Promise.<void> – A promise that resolves once the comment has been updated and the notification has been sent.