xapi_rs/lrs/resources/agents.rs
1// SPDX-License-Identifier: GPL-3.0-or-later
2
3//! Agents Resource (/agents)
4//! --------------------------
5//! Provides a method to retrieve a [Person] Object with combined information
6//! about an [Agent] derived from an outside service, such as a directory
7//! service. This object is called a "Person Object". This [Person] Object is
8//! very similar to an [Agent] Object, but instead of each attribute having a
9//! single value, each attribute has an array value. In addition it's legal
10//! to include multiple identifying properties.
11//!
12//! Any deviation from section [4.1.6.3 Agents Resource (/activities/state)][1]
13//! of the xAPI specification is a bug.
14//!
15//! [1]: https://opensource.ieee.org/xapi/xapi-base-standard-documentation/-/blob/main/9274.1.1%20xAPI%20Base%20Standard%20for%20LRSs.md#4163-agents-resource-agents
16
17use crate::{
18 data::{Agent, Person},
19 db::actor::find_person,
20 emit_response,
21 lrs::{headers::Headers, resources::WithResource, User, DB},
22 MyError,
23};
24use rocket::{get, http::Status, routes, State};
25use sqlx::PgPool;
26use std::str::FromStr;
27use tracing::{debug, info};
28
29#[doc(hidden)]
30pub fn routes() -> Vec<rocket::Route> {
31 routes![get]
32}
33
34#[get("/?<agent>")]
35async fn get(
36 c: Headers,
37 agent: &str,
38 db: &State<DB>,
39 user: User,
40) -> Result<WithResource<Person>, MyError> {
41 debug!("----- get ----- {}", user);
42 user.can_use_xapi()?;
43
44 let agent =
45 Agent::from_str(agent).map_err(|x| MyError::Data(x).with_status(Status::BadRequest))?;
46 debug!("agent = {}", agent);
47 let resource = get_resource(db.pool(), &agent).await?;
48 debug!("resource = {}", resource);
49 emit_response!(c, resource => Person)
50}
51
52async fn get_resource(conn: &PgPool, agent: &Agent) -> Result<Person, MyError> {
53 let x = find_person(conn, agent).await?;
54 match x {
55 None => {
56 // NOTE (rsn) 20241103 - CTS expects a Person object even when none
57 // was found. the spec only states "Returns: 200 OK, Person Object"
58 // how clear is that :/
59 info!("No known Person");
60 Ok(Person::unknown())
61 }
62 Some(x) => Ok(x),
63 }
64}