Skip to main content

xapi_rs/lrs/resources/
activities.rs

1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#![allow(non_snake_case)]
4
5//! Activities Resource (/activities)
6//! ----------------------------------
7//! The Activities Resource provides a method to retrieve a full description of
8//! an Activity from the LRS.
9//!
10//! Any deviation from section [4.1.6.4 Activities Resource (/activities)][1]
11//! of the xAPI specification is a bug.
12//!
13//! [1]: https://opensource.ieee.org/xapi/xapi-base-standard-documentation/-/blob/main/9274.1.1%20xAPI%20Base%20Standard%20for%20LRSs.md#4164-activities-resource-activities
14
15use crate::{
16    data::{Activity, Format},
17    db::activity::find_activity_by_iri,
18    emit_response,
19    lrs::{resources::WithResource, Headers, User, DB},
20    DataError, MyError,
21};
22use iri_string::types::IriStr;
23use rocket::{get, http::Status, routes, State};
24use tracing::{debug, warn};
25
26#[doc(hidden)]
27pub fn routes() -> Vec<rocket::Route> {
28    routes![get]
29}
30
31#[get("/?<activityId>")]
32async fn get(
33    c: Headers,
34    activityId: &str,
35    db: &State<DB>,
36    user: User,
37) -> Result<WithResource<Activity>, MyError> {
38    debug!("----- get ----- {}", user);
39    user.can_use_xapi()?;
40
41    let iri = IriStr::new(activityId)
42        .map_err(|x| MyError::Data(DataError::IRI(x)).with_status(Status::BadRequest))?;
43    let format = Format::from(c.languages().to_vec());
44    let x = find_activity_by_iri(db.pool(), iri, &format).await?;
45    let mut resource = match x {
46        Some(x) => x,
47        None => {
48            // NOTE (rsn) 20240805 - section 4.1.6.4 states...
49            // > If an LRS does not have a canonical definition of the Activity
50            // > to return, the LRS shall still return an Activity Object when
51            // > queried.
52            warn!("I know nothing about {}", iri);
53            // if this fails it would've earlier when converting to IRI
54            Activity::from_iri_str(activityId).unwrap()
55        }
56    };
57    // NOTE (rsn) 224116 - the object_type field in the DAO is an Option
58    // meaning it's not always set.  however some conformance tests expect a
59    // fully formed Activity instance.
60    resource.set_object_type();
61
62    emit_response!(c, resource => Activity)
63}