shared workspace at a distance
# Plugins and web service Antonio Cañas Vargas, 1999-2015
- - ## Plugins It is possible to develop plugins for SWAD. In this context, a plugin is a program external to SWAD, that interacts with it to provide some functions not provided by SWAD. Currently, there is only a plugin available: the SWADroid app for Android mobile devices, and other plugins are under development. SWAD has a form that allows administrators to add new plugins or edit the existing plugins. Each plugin is specified by the following elements: Code (internal number that identifies the plugin in database). Name. Description. Logo or icon. App key. URL (optional). IP (optional). ## Web service The plugins interact with the program SWAD through a web service with several operations or functions. A web service is a software system that allows the interaction between two computers connected to Internet. In our case, SWAD is the server or host that offers the web service, and the plugin is the client that request one or several functions from the web service. There are two possible ways to access to a SWAD plugin: Directly from the external application: The user logs in directly using a form in the external application. The external application calls SWAD by using the function `loginByUserPasswordKey`. From SWAD: The user logs in SWAD. SWAD provides a listing of the available plugins in the option System > List of plugins. When the user clicks on the link to a plugin, the web address resulting of concatenate the URL of that plugin with the identifier of the current session is used. For example, if the URL specified in the plugin is `http://my.url.com/index.php?mode=session&id=` and the session identifier is `cY_kAutNT5HzF3MbflcuXgXFlv00Wmqq9QKeD1aaaRc`, the following address is called: `http://my.url.com/index.php?mode=session&id=cY_kAutNT5HzF3MbflcuXgXFlv00Wmqq9QKeD1aaaRc`. The external application then calls SWAD using the function `loginBySessionKey`. ## SOAP The exchange of informationn between the SWAD web service (server) and a plugin (client) is performed through XML (Extensible Markup Language) messages using the protocol SOAP (Simple Object Access Protocol). The client sends a SOAP message to the server with the operation or function that it wants to invoque and a number of parameters. The server returns an XML document with the resulting data (users, courses, etc.). The main core of SWAD, written in C, uses the tool gSOAP to implement the SOAP server protocol. The plugins can be written in any programming language, so they will use the available libraries in that language to implement the SOAP client protocol. ## WSDL The interface of a web service is given in a format automatically processable written in WSDL (Web Services Description Language). The SWAD server provides to the clientes several operations or functions indicated in the WSDL file: http://openswad.org/ws/swad.wsdl http://swad.ugr.es/ws/swad.wsdl http://www.cevuna.una.py/swad/ws/swad.wsdl At the end of the WSDL file you can find the URL to call the SWAD web service. The CGI executed as answer detects that a call to the web service (and not a normal web request) is performed if the variable `CONTENT_TYPE` is set to `text/xml`. In this case, it responds to the client with the XML output of the SOAP protocol. ## Operations or functions provided by this web service The SWAD web service provides the following operations: `createAccount` `loginByUserPasswordKey` `loginBySessionKey` `getNewPassword` `getCourses` `getCourseInfo` `getGroupTypes` `getGroups` `sendMyGroups` `getDirectoryTree` `getFile` `getMarks` `getTestConfig` `getTests` `getTrivialQuestion` `getUsers` `getAttendanceEvents` `sendAttendanceEvent` `getAttendanceUsers` `sendAttendanceUsers` `getNotifications` `markNotificationsAsRead` `sendNotice` `sendMessage` ### `createAccount` Create a new user account. Call parameters: userNickname: string starting by @ (@nickname of the user). userEmail: string (email of the user). userPassword: string, plain password. appKey: string, key used by the application. Returns a data structure with the following fields: userCode: integer, unique identifier of the user. If <= 0, an error has happened, the account has not been created. -1 → nickname not valid -2 → nickname registered by another user -3 → e-mail not valid -4 → e-mail registered by another user -5 → password not valid (too short, too trivial...) If > 0, the account has been successfully created and this unique identifier has been assigned to the new user. wsKey: string, identifier used in the calls to other operations. Use only when userCode > 0. ### `loginByUserPasswordKey` Returns data of the user, given an identifier of the user (DNI/passport, @nickname or email), a password and an application key. Call parameters: userID: string (DNI/passport, @nickname or email of the user). userPassword: string, password encrypted with the algoritthm SHA-512 and in format base64url. appKey: string, key used by the application. Returns a data structure with the following fields: userCode: integer, unique identifier of the user. wsKey: string, identifier used in the calls to other operations. userNickname: string, user's nickname (without @). userID: string, DNI/passport of the user. userSurname1: string. userSurname2: string. userFirstname: string. userPhoto: string with the full URL of a JPG image of size 150 (width) × 200 (height). If it is an empty string, the user has no photo or it can not be shown. userBirthday: string, in YYYYMMDD format. userRole: integer, maximum role of the user, with one of the following 4 values: 0: unknown, an error has occurred. 1: invited, not enrolled in any course. 2: student in all his/her courses. 3: teacher in at aleast one of his/her courses. ### `loginBySessionKey` Returns data of the user and course of a session, given an identifier of session passed to the plugin from SWAD. Call parameters: sessionID: string passed as parameter to the plugin from SWAD. appKey: string, key used by the application. Returns a data structure with the following fields: userCode: integer, unique identifier of the user. degreeCode: integer. courseCode: integer. wsKey: string, identifier used in the calls to other operations. userNickname: string, user's nickname (without @). userID: string, DNI/passport of the user. userSurname1: string. userSurname2: string. userFirstname: string. userPhoto: string with the full URL of a JPG image of size 150 (width) × 200 (height). If it is an empty string, the user has no photo or it can not be shown. userBirthday: string, in YYYYMMDD format. userRole: integer, maximum role of the user, with one of the following 4 values: 0: unknown, an error has occurred. 1: invited, not enrolled in any course. 2: student in all his/her courses. 3: teacher in at aleast one of his/her courses. degreeName: string. courseName: string. ### `getNewPassword` Sends a new password by e-mail. Call parameters: userID: string (DNI/passport, @nickname or email of the user). appKey: string, key used by the application. Returns a data structure with the following fields: success: integer. For compatibility with other functions, this function returns a number > 0 (currently 1) on success, and a number <= 0 (currently 0) on error. ### `getCourses` Returns the list of courses to which the user belongs. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. Returns a data structure with the following fields: numCourses: integer, number of courses. coursesArray: list of elements, where each element is a data structure with the following fields: courseCode: integer, unique identifier for each course. userRole: integer, role of the user in the course, with one of the following 3 values: 0: unknown, an error has occurred. 2: student in this course. 3: teacher in this course. courseShortName: string. courseFullName: string. ### `getCourseInfo` Returns information about the course. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. courseCode: integer. infoType: string, with one of the following 7 values: "introduction": introduction to the course. "guide": teaching guide of the course. "lectures": lectures syllabus. "practicals": practicals (laboratory) syllabus. "bibliography": bibliography. "FAQ": FAQ. "links": links. "assessment": info on assessment system. Returns a data structure with the following fields: infoSrc: string, with one of the following 6 values: "none": no info. infoTxt will be empty. "editor": internal editor. infoTxt will contain a full XHTML page. "plainText": plain text. infoTxt will contain a full XHTML page. "richText": rich text. infoTxt will contain a full XHTML page. "page": web page, in HTML format. infoTxt will contain a full HTML page. If the page contain images or other archives, the result will be incomplete, because only the main page is returned. "URL": URL address. infoTxt will contain the URL in plain text. infoTxt: string with the information. ### `getGroupTypes` Returns the list of types of group of a course. Before consulting the list of types of group, this function opens automatically the groups of the course that should be open. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. courseCode: integer. Returns a data structure with the following fields: numGroupTypes: integer, number of types of group. groupTypesArray: list of elements, where each element is a data structure with the following fields: groupTypeCode: integer, identifier of the type of group. groupTypeName: string with the name of the type of group (for example: "Theory", "Lab"). mandatory: integer. If not 0 ⇒ the enrollment in group(s) of this type is mandatory for students of the course, if there is at least a group of that type open and with vacancies. multiple: integer. If not 0 ⇒ the students of the course can enroll in more than a group of this type. openTime: integer of 32 bits with sign, Unix time. If 0 ⇒ the teachers have not set a time to open automatically the groups of this type. If not 0 and it corresponds to a future time ⇒ the groups of this type will be opened automatically at that time. ### `getGroups` Returns the list of all the groups of a course. Before consulting the list of types of group, this function opens automatically the groups of the course that should be open. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. courseCode: integer. Returns a data structure with the following fields: numGroups: integer, number of groups. groupsArray: list of elements, where each element is a data structure with the following fields: groupCode: integer, unique identifier for each group. groupName: string with the name of the group (for example: "A", "B", "Morning", "Afternoon"). groupTypeCode: integer, identifier of the type of group to which this group belongs. groupTypeName: string with the name of the type of group (for example: "Theory", "Lab"). open: integer. If not 0 ⇒ the group is open, meaning that the students can enroll in or remove from the group. maxStudents: integer, maximum number of students in the group. If < 0 ⇒ there is no limit of students in the group. numStudents: integer, current number of students in the group. fileZones: integer. If not 0 ⇒ the file zones for this group are enabled. member: integer. If not 0 ⇒ the logged user belongs to this group. ### `sendMyGroups` It sends to the server a list with all the groups in a course to which the logged user wants to belong. It tries to enroll the user in those groups if possible, and remove from the groups not in the list. If all the changes are not possible, no change is performed. Returns the updated list of all the groups of the course after the changes performed. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. courseCode: integer. myGroups: string. List of codes of groups (each code is an integer number) to which the user wants to belong, separated by commas. Returns a data structure with the following fields: success: integer. If 0 ⇒ it was impossible to satisfy all the requested changes, no change performed. If not 0 ⇒ all the requested changes have been performed with success. numGroups: integer, number of groups. groupsArray: list of elements, with identical format to that of the list groupsArray returned by the function `getGroups`. ### `getDirectoryTree` Returns the full tree of a file zone (documents, shared files or marks) in a course or a group. The logged user must belong to the course or the group. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. courseCode: integer. groupCode: integer, if <= 0 ⇒ no group specified, the zone corresponds to the whole course. treeCode: integer, with one of the following 3 values: 1: documents zone. To download a file, call `getFile`. 2: shared files zone. To download a file, call `getFile`. 3: marks zone. To view marks, call `getMarks` or `getFile`: if the logged user is a student in the course/group, the client should call `getMarks` to view the student's specific marks. if the logged user is a teacher in the course/group, the client should call `getFile` to download the HTML file with the marks of several students. Returns a data structure with the following fields: tree: string with the full tree in XML format. Example:
        <tree>
        	<dir name="Logos">
        		<file name="prado48x48.gif">
        			<code>103482</code>
        			<size>2026</size>
        			<time>1334483747</time>
        			<license>CC by-nc-sa</license>
        			<publisher>Antonio Cañas Vargas</publisher>
        			<photo>http://openswad.org/swad/photo/nQwJwD6jYd.jpg</photo>
        		</file>
        		<file name="swad48x48.gif">
        			<code>103491</code>
        			<size>1982</size>
        			<time>1334483747</time>
        			<license>CC by-nc-sa</license>
        			<publisher>Antonio Cañas Vargas</publisher>
        			<photo>http://openswad.org/swad/photo/nQwJwD6jYd.jpg</photo>
        		</file>
        	</dir>
        	<file name="Mejoras futuras.pdf">
        		<code>97910</code>
        		<size>224595</size>
        		<time>1334483747</time>
        		<license>CC by-nc-sa</license>
        		<publisher>Antonio Cañas Vargas</publisher>
        		<photo>http://openswad.org/swad/photo/nQwJwD6jYd.jpg</photo>
        	</file>
        </tree>
### `getFile` This function must be called each time the user wants to download a file from a documents zone or a shared files zone in a course or a group. The logged user must belong to the course or group. The function counts the access as a visit to the file and returns information about the file. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. fileCode: integer, corresponding to an element `<code>` of the XML tree returned by `getDirectoryTree`. If the file code corresponds to an HTML file of marks (`treeCode` = 3 in `getDirectoryTree`, the requester should be a student in the course/group. If the logged user is a teacher, the client should call `getMarks` instead `getFile`. Returns a data structure with the following fields: fileName: string, name of the file. Example: `doc.pdf` URL: string, full URL for downloading the file. Example: `http://openswad.org/swad/tmp/1ACaVfIj_GT768AqLBxHNKyl9iRW688ntqPW86I8FZU/doc.pdf` size: integer, size in bytes. time: integer of 32 bits with sign, Unix time. license: string, license. Example: "CC by-nc-sa" publisherName: string, first name and surnames of the user who uploaded the file. publisherPhoto: string with the full URL of a JPG image (of the user who uploaded the file) with size 150 (width) × 200 (height). If is a string empty, the user has no photo or it can not be shown. ### `getMarks` Returns information about the marks (qualifications, scores) of the logged user (requester) from a given HTML file of marks. This function is allowed only for students. The requester must be a student in the course/group. If the logged user is a teacher, the client should call `getFile` instead of `getMarks`. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. fileCode: integer, corresponding to an element `<code>` of the XML tree returned by `getDirectoryTree`. Returns a data structure with the following fields: content: string with a full HTML page containing the marks of the requester. It's the same content returned in `content` by `getNotifications`. ### `getTestConfig` Returns the configuration of the tests of a course. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. courseCode: integer. Returns a data structure with the following fields: pluggable: integer. If 0 ⇒ the tests can not be downloaded from the client application and if this calls the function `getTests` it will get an empty list of questions; if not 0 ⇒ the tests of the course with all the tags visible can be downloaded from the client application using the function `getTests`. numQuestions: integer, number total of questions of test visible and available for download. If the course does not allow to export tests (pluggable = 0) ⇒ numQuestions = 0. If the course has no visible tests questions ⇒ numQuestions = 0. minQuestions: integer, minimum number of questions in an exam. defQuestions: integer, default number of questions in an exam. maxQuestions: integer, maximum number of questions in an exam. feedback: string with the type of feedback for the user, with one of the following 5 values: "nothing": no feedback. "totalResult": minimum feedback: only total score. "eachResult": medium feedback: score of each question. "eachGoodBad": high feedback: correct answer in each question. "fullFeedback": maximum feedback: text of feedback. ### `getTests` Returns the self-assessment tests of a course. This function should not be callled if the download of tests is not allowed in this course (if the function `getTestConfig` returns pluggable = 0). If in this case you call `getTests`, the four returned lists devueltas will be empty. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. courseCode integer. beginTime: integer of 32 bits with sign, Unix time. All the tags not hidden are returned without taking into account beginTime, but only the questions (and answers) with an edition/change time later than or equal to beginTime will be returned. With this parameter, each time the client application requests a test update, you can send the time of the prior update (or 0 if it is the first update), minimizing the volume of data to be transferred. Returns a data structure with the following fields: tags: list of all the tags not hidden, without having into account beginTime, where each tag is a data structure with the following fields: tagCode: integer, unique identifier for each tag. tagText: string. questions: list of questions with an edition/change time later than or equal to beginTime, where each question is a data structure with the following fields: questionCode: integer, unique identifier for the question. answerType: string, with one of the following 6 values: "int": integer number. "float": floating point number. "TF": true / false. "uniqueChoice": choice of a unique answer between several options. "multipleChoice": choice of several answers between several options. "text": string. shuffle: integer. If not 0 ⇒ the answers can be shuffled. stem: string with the stem of the question. feedback: string with the feedback of the question. answers: list of answers of the returned questions, where each answer is a data structure with the following fields: questionCode: integer. answerIndex: integer, index or position (0, 1, 2,...) of the answer inside the question. correct: integer. If not 0 ⇒ the answer is correct. answerText: string with the text of the answer. answerFeedback: string with the feedback for this answer (only when answerType is "uniqueChoice", "multipleChoice" or "text"). questionTags: list of tags of the returned questions: questionCode: integer. tagCode: integer. tagIndex: integer, index or position (0, 1, 2,...) of the tag inside the question. ### `getTrivialQuestion` Returns a random test question, selected from the "uniqueChoice" questions in the courses of a given list of degrees, and with a score in the interval [`lowerScore`, `upperScore`]. Call parameters: wsKey: string, identifier returned by loginByUserPasswordKey or loginBySessionKey. degrees: string. It can contain one or more degree codes, separated by commas. lowerScore: float. lower limit of the question score between -1.0 and 1.0 upperScore: float. upper limit of the question score between -1.0 and 1.0 Returns a data structure with the following fields: question: data structure with the following fields: questionCode: integer, unique identifier for the question, > 0. If no question found ⇒ a questionCode value <= 0 will be returned. answerType: string, currently only the following value is returned: "uniqueChoice": choice of a unique answer between several options. shuffle: integer. If not 0 ⇒ the answers can be shuffled. stem: string with the stem of the question. feedback: string with the feedback of the question. answers: list of answers of the returned question, where each answer is a data structure with the following fields: questionCode: integer. answerIndex: integer, index or position (0, 1, 2,...) of the answer inside the question. correct: integer. If not 0 ⇒ the answer is correct. answerText: string with the text of the answer. answerFeedback: string with the feedback for this answer. ### `getUsers` Returns the list of users of a given type (students or teachers) enrolled in a course and group (code of group <= 0 means the whole course). Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. courseCode: integer. groupCode: integer (<= 0 means the whole course). userRole: integer, role of the users to be listed (2=students; 3=teachers) Returns a data structure with the following fields: numUsers: integer, number of users. usersArray: list of elements, where each element is a data structure with the following fields: userCode: integer, unique identifier for each user. userNickname: string, user's nickname (without @). userID: string, DNI/passport of the user. If the requester is a teacher in the selected course, the ID is shown. If the requester is a student in the selected course, the ID is hidden. userSurname1: string. userSurname2: string. userFirstname: string. userPhoto: string with the full URL of a JPG image of size 150 (width) × 200 (height). If it is an empty string, the user has no photo or it can not be shown. ### `getAttendanceEvents` Returns the list of the attendance events in a course available for the logged user (associated to the whole course or to the groups to which the logged user belongs). Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. courseCode: integer. Returns a data structure with the following fields: numEvents: integer, number of attendance events. eventsArray: list of elements, where each element is a data structure with the following fields: attendanceEventCode: integer, unique identifier for each attendance event. hidden: integer. If not 0 ⇒ this attendance event is hidden for students. userSurname1: string. userSurname2: string. userFirstname: string. userPhoto: string with the full URL of a JPG image of size 150 (width) × 200 (height). If it is a string empty, the user has no photo or it can not be shown. startTime: integer of 32 bits with sign, Unix time. endTime: integer of 32 bits with sign, Unix time. commentsTeachersVisible: integer. If not 0 ⇒ the comments made by teachers are visible by the students. title: string. text: string. groups: string. List of codes of groups (each code is an integer number) to which this attendance event is applicable. If this list of group codes is empty ⇒ this attendance event is applicable to the whole course. ### `sendAttendanceEvent` Sends an attendance event. The logged user must be a teacher in the course. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. attendanceEventCode: integer, unique identifier for each attendance event. If <= 0 ⇒ this is a new attendance event. If > 0 ⇒ this is an existing attendance event returned by `getAttendanceEvents`. courseCode: integer. hidden: integer. If not 0 ⇒ this attendance event is hidden for students. startTime: integer of 32 bits with sign, Unix time. endTime: integer of 32 bits with sign, Unix time. commentsTeachersVisible: integer. If not 0 ⇒ the comments made by teachers are visible by the students. title: string. text: string. groups: string. List of codes of groups (each code is an integer number) to which this attendance event is applicable. If this list of group codes is empty ⇒ this attendance event is applicable to the whole course. Returns a data structure with the following fields: attendanceEventCode: integer, unique identifier of the attendance event, > 0 on success. On error, this code will be <= 0. ### `getAttendanceUsers` Returns the list of users (students) in an attendance event. The logged user must be teacher in the selected course. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. attendanceEventCode: integer, one of the codes returned by `getAttendanceEvents` or `sendAttendanceEvent`. Returns a data structure with the following fields: numUsers: integer, number of users. usersArray: list of elements, where each element is a data structure with the following fields: userCode: integer, unique identifier for each user. userNickname: string, user's nickname (without @). userID: string, DNI/passport of the user. userSurname1: string. userSurname2: string. userFirstname: string. userPhoto: string with the full URL of a JPG image of size 150 (width) × 200 (height). If it is an empty string, the user has no photo or it can not be shown. present: integer. If not 0 ⇒ this user has attended the event. ### `sendAttendanceUsers` Send the list of users (students) who have attended to an attendance event. All users in this list will be marked as present; other users formerly marked as present will be marked as absent when `setOthersAsAbsent` = 1. The logged user must be teacher in the selected course. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. attendanceEventCode: integer, one of the codes returned by `getAttendanceEvents` or `sendAttendanceEvent`. users: string, list of numbers separated by commas. Each number is the user's code (previously returned by `getAttendanceUsers`) of a student who attended this event. setOthersAsAbsent: integer: 0 ⇒ users from list `users` will be added to list of presents and other users formerly marked as present will not be affected 1 ⇒ users from list `users` will be marked as present and other users formerly marked as present will be marked as absent Returns a data structure with the following fields: success: integer. 1 on success, 0 on error (for example, if the event does not exist). numUsers: integer, number of users found in list and marked as present in the event. ### `getNotifications` Returns the list of recent notifications for the logged user. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. beginTime: integer of 32 bits with sign, Unix time. Only the notifications with time later than or equal to this parameter will be shown. With this parameter, each time the application client requests an update of the notifications, you can send the time of the former update (or 0 if it is the first update), minimizing the volume of data to be transferred. Returns a data structure with the following fields: numNotifications: integer, number of notifications. notificationsArray: list of elements, where each element is a data structure with the following fields: notifCode: integer. Unique identifier for a notification. When a user opens this notification, you should call `markNotificationsAsRead` with this value. eventType: string, with one of the following 13 values: "documentFile": document. "sharedFile": shared file. "assignment": assignment. "examAnnouncement": exam announcement. "marksFile": marks/grades file. "enrollmentStudent": enrollment in a course as a student. "enrollmentTeacher": enrollment in a course as a teacher. "enrollmentRequest": enrollment request. "notice": notice (yellow note). "forumPostCourse": new message in a forum of a course. "forumReply": reply to a message in a forum. "message": message received from another user. "survey": survey. eventCode: integer. A non-unique code associated to some notifications. It corresponds to the code of the document, message, assignment, etc., depending on `eventType`. eventTime: integer of 32 bits with sign, Unix time. userNickname: string, user's nickname (without @). userSurname1: string. userSurname2: string. userFirstname: string. userPhoto: string with the full URL of a JPG image of size 150 (width) × 200 (height). If it is a string empty, the user has no photo or it can not be shown. location: string. status: integer, with the following meaning for each bit: Bit 0 = 1 ⇒ the user wants to receive by email notifications of this event type. Bit 1 = 1 ⇒ the email has been sent. Bit 2 = 1 ⇒ the user has read the event that caused the notification. Bit 3 = 1 ⇒ the event that caused the notification was removed (the notification should be displayed as hidden). The following combinations are possible: X000: No email will be sent, event not read. X001: Email pending, event not read. X010: (impossible). X011: Email sent, event not read. X100: No email will be sent, event read. X101: Email cancelled because the event has been read before to send it. X110: (impossible). X111: Email sent, event read. summary: string with a brief description of the notification, for example the subject of a message. content: string with the full content of the notification, for example the text of a message. If `eventType` is "marksFile", `content` will be HTML code with information about the marks (qualifications, scores) of the logged student from an HTML file of marks. ### `markNotificationsAsRead` It marks several notifications as read. You should call this function when one or more notifications have been open / read by the user. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. notifications: string. List of unique notification codes to be marked as read, separated by commas. Each code is an integer, a unique identifier of the notification returned as `notifCode` (not `eventCode`/`notificationCode`) by `getNotifications`. Returns a data structure with the following fields: numNotifications: integer, number of notifications found in list and marked as read. ### `sendNotice` Sends a public notice (yellow note) to a course. The logged user must be a teacher in the course. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. courseCode: integer. body: string, body of the message. Returns a data structure with the following fields: noticeCode: integer, unique identifier of the notice, > 0 on success. On error, this code will be <= 0. ### `sendMessage` It sends a message to one or more users. Call parameters: wsKey: string, identifier returned by `loginByUserPasswordKey` or `loginBySessionKey`. messageCode: integer. If `messageCode` is 0, this message will be not considered a reply of another message, and `to` should contain at least one recipient. If `messageCode` is not 0, this message will be considered a reply to a message received in notifications. In that case it must contain the code returned by `getNotifications` in `eventCode` (for safety, the server will check that this code of message corresponds really to a message received previously by the user logged by `wsKey`). to: string. It can contain one or more IDs, @nicknames or emails of the recipients of the message, separated by commas. If `messageCode` is 0, `to` must have at least an ID, @nickname or email. If `messageCode` is distinct of 0, `to` can be empty. subject: string, subject of the message. body: string, body of the message. Returns a data structure with the following fields: numUsers: integer, number of recipients. usersArray: list of elements, where each element is a data structure, corresponding to a recipient, with the following fields: userCode: integer, unique identifier of the recipient. userNickname: string, nickname of the recipient (without @). userID: string, DNI/passport of the user, really this function returns a hidden `userID`, so you should not use this field. userSurname1: string, first surname of the recipient. userSurname2: string, second surname of the recipient. userFirstname: string, name of the recipient. userPhoto: string with the full URL of a JPG image of size 150 (width) × 200 (height). If it is a string empty, the user does not have photo or it can not be shown.