Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/exelearning/mod_exelearning/llms.txt

Use this file to discover all available pages before exploring further.

mod_exelearning_save_track is the web-service counterpart of track.php. It accepts per-iDevice scores and an optional overall SCORM status, re-shapes them into the internal payload format, and delegates entirely to the shared track::ingest() pipeline — so the server-side safeguards are identical to the browser-based track.php path. Only the authenticated user ($USER) can be graded; a client cannot submit scores on behalf of another user.

Function details

FieldValue
Function namemod_exelearning_save_track
Class::methodmod_exelearning\external\save_track::execute
Typewrite
ServiceMOODLE_OFFICIAL_MOBILE_SERVICE
Capabilitymod/exelearning:savetrack

Parameters

exelearningid
int
required
The ID of the exelearning activity instance (the id column in the exelearning table, returned as id by get_exelearnings_by_courses). This is not the course-module ID.
track
object
required
The tracking payload for this submission.

Returns

status
bool
true when track::ingest() accepted and recorded the submission. false when the submission was rejected (e.g. status-only no-op, or maxattempt cap reached). Check warnings for the reason when status is false.
attempt
int
The attempt number that was written (1-based). 0 when the submission was rejected and no attempt was recorded.
score
float
The server-side overall grade after aggregation across all per-iDevice scores. This is the value written to the gradebook — the client’s own overall score value is never trusted.
warnings
array
Contains one warning when maxattempt is hit. Empty on a successful submission.

Server-side safeguards

All of the following are enforced by track::ingest() and apply equally to this function and to the web track.php path:
SafeguardBehaviour
Always grades $USERThe authenticated user is always the target. No parameter can change this.
Unknown objectids ignoredAn objectid not registered for this activity instance is silently discarded — it does not cause an error or a spurious grade column.
Overall recomputed server-sideThe server recalculates the overall score from per-iDevice scores. The client’s scoreraw / scoremax values are used for SCORM CMI bookkeeping only.
Scores clampedScores are clamped to [grademin, grademax] as configured on the instance.
Attempt cap enforcedWhen maxattempt > 0 and the user has already reached that many attempts, the submission is rejected and a maxattemptsreached warning is returned.
Status-only no-opWhen scoreraw is null the submission is a no-op — no 0-score attempt row is created and no attempt slot is consumed.
The web track.php endpoint returns HTTP 409 Conflict when the attempt cap is reached. This function returns status: false with a maxattemptsreached warning in the warnings array instead — it does not throw an exception. Check warnings whenever status is false.

Security model

The function enforces the following checks in order:
  1. validate_parameters() — sanitises all inputs.
  2. validate_context() — establishes the module context.
  3. require_capability('mod/exelearning:savetrack', $context) — the caller must hold the save-track capability.
  4. Preview mode is always disabled for web-service calls — scores are always persisted when the submission is accepted.

Example request — full submission

POST {wwwroot}/webservice/rest/server.php
Content-Type: application/x-www-form-urlencoded

wstoken=<token>
&wsfunction=mod_exelearning_save_track
&moodlewsrestformat=json
&exelearningid=12
&track[session]=abc123xyz
&track[scoreraw]=75
&track[scoremax]=100
&track[status]=passed
&track[itemscores][0][objectid]=idevice-001
&track[itemscores][0][scorepct]=80
&track[itemscores][0][weighted]=50
&track[itemscores][1][objectid]=idevice-002
&track[itemscores][1][scorepct]=70
&track[itemscores][1][weighted]=50

Example response — accepted

{
  "status": true,
  "attempt": 2,
  "score": 75.0,
  "warnings": []
}

Example response — attempt cap reached

{
  "status": false,
  "attempt": 0,
  "score": 0.0,
  "warnings": [
    {
      "item": "exelearning",
      "itemid": 12,
      "warningcode": "maxattemptsreached",
      "message": "The maximum number of attempts has been reached."
    }
  ]
}

Example — status-only commit (no score)

A status-only commit is useful to report completion without submitting a score (e.g. when the content only tracks completion, not a numeric grade). Omit scoreraw or set it to null:
{
  "exelearningid": 12,
  "track": {
    "session": "abc123xyz",
    "status": "completed",
    "itemscores": []
  }
}
This call returns status: false (no attempt was written) and an empty warnings array — the no-op is silent and expected.

Build docs developers (and LLMs) love