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}