headless_lms_server/controllers/cms/
gutenberg.rs1use std::time::Duration;
2
3use headless_lms_utils::url_to_oembed_endpoint::{
4 OEmbedRequest, OEmbedResponse, mentimeter_oembed_response_builder,
5 thinglink_oembed_response_builder, url_to_oembed_endpoint, vimeo_oembed_response_builder,
6};
7use serde::{Deserialize, Serialize};
8
9use crate::prelude::*;
10
11#[derive(Deserialize, Serialize)]
12#[serde(rename_all = "kebab-case")]
13pub struct ThemeSupports {
14 pub responsive_embeds: bool,
15}
16
17#[derive(Deserialize, Serialize)]
18pub struct ThemeResponse {
19 pub theme_supports: ThemeSupports,
20}
21
22static APP_USER_AGENT: &str = concat!("moocfi", "/", "0.1.0",);
24
25#[instrument(skip(pool, app_conf))]
58async fn get_oembed_data_from_provider(
59 query_params: web::Query<OEmbedRequest>,
60 pool: web::Data<PgPool>,
61 user: AuthUser,
62 app_conf: web::Data<ApplicationConfiguration>,
63) -> ControllerResult<web::Json<serde_json::Value>> {
64 let mut conn = pool.acquire().await?;
65 let token = authorize(&mut conn, Act::Teach, Some(user.id), Res::AnyCourse).await?;
66 let endpoint = url_to_oembed_endpoint(
67 query_params.url.to_string(),
68 Some(app_conf.base_url.to_string()),
69 )?;
70 let client = reqwest::Client::builder()
71 .user_agent(APP_USER_AGENT)
72 .build()
73 .map_err(|oe| anyhow::anyhow!(oe.to_string()))?;
74 let res = client
75 .get(endpoint)
76 .timeout(Duration::from_secs(120))
77 .send()
78 .await
79 .map_err(|oe| {
80 ControllerError::new(
81 ControllerErrorType::BadRequest,
82 oe.to_string(),
83 Some(oe.into()),
84 )
85 })?;
86 let status = res.status();
87 if !status.is_success() {
88 let response_url = res.url().to_string();
89 let body = res.text().await.map_err(|oe| {
90 ControllerError::new(
91 ControllerErrorType::BadRequest,
92 oe.to_string(),
93 Some(oe.into()),
94 )
95 })?;
96 warn!(url=?response_url, status=?status, body=?body, "Could not fetch oembed data from provider");
97 return Err(ControllerError::new(
98 ControllerErrorType::BadRequest,
99 "Could not fetch oembed data from provider".to_string(),
100 None,
101 ));
102 }
103 let res = res.json::<serde_json::Value>().await.map_err(|oe| {
104 ControllerError::new(
105 ControllerErrorType::BadRequest,
106 oe.to_string(),
107 Some(oe.into()),
108 )
109 })?;
110 token.authorized_ok(web::Json(res))
111}
112
113#[instrument(skip(pool))]
140async fn get_theme_settings(
141 pool: web::Data<PgPool>,
142 user: AuthUser,
143) -> ControllerResult<web::Json<ThemeResponse>> {
144 let mut conn = pool.acquire().await?;
145 let token = authorize(&mut conn, Act::Teach, Some(user.id), Res::AnyCourse).await?;
146 let response = ThemeResponse {
147 theme_supports: ThemeSupports {
148 responsive_embeds: true,
149 },
150 };
151 token.authorized_ok(web::Json(response))
152}
153
154#[instrument(skip(app_conf))]
155async fn get_mentimeter_oembed_data(
156 query_params: web::Query<OEmbedRequest>,
157 app_conf: web::Data<ApplicationConfiguration>,
158 pool: web::Data<PgPool>,
159) -> ControllerResult<web::Json<OEmbedResponse>> {
160 let token = skip_authorize();
161 let url = query_params.url.to_string();
162 let response = mentimeter_oembed_response_builder(url, app_conf.base_url.to_string())?;
163 token.authorized_ok(web::Json(response))
164}
165
166#[instrument(skip(app_conf))]
167async fn get_thinglink_oembed_data(
168 query_params: web::Query<OEmbedRequest>,
169 app_conf: web::Data<ApplicationConfiguration>,
170 pool: web::Data<PgPool>,
171) -> ControllerResult<web::Json<OEmbedResponse>> {
172 let token = skip_authorize();
173 let url = query_params.url.to_string();
174 let response = thinglink_oembed_response_builder(url, app_conf.base_url.to_string())?;
175 token.authorized_ok(web::Json(response))
176}
177
178#[instrument(skip(app_conf))]
179async fn get_vimeo_oembed_data(
180 query_params: web::Query<OEmbedRequest>,
181 app_conf: web::Data<ApplicationConfiguration>,
182 pool: web::Data<PgPool>,
183) -> ControllerResult<web::Json<OEmbedResponse>> {
184 let token = skip_authorize();
185 let url = query_params.url.to_string();
186 let response = vimeo_oembed_response_builder(url, app_conf.base_url.to_string())?;
187 token.authorized_ok(web::Json(response))
188}
189
190pub fn _add_routes(cfg: &mut ServiceConfig) {
198 cfg.route(
199 "/oembed/preview",
200 web::get().to(get_oembed_data_from_provider),
201 )
202 .route("/themes", web::get().to(get_theme_settings))
203 .route(
204 "/oembed/mentimeter",
205 web::get().to(get_mentimeter_oembed_data),
206 )
207 .route(
208 "/oembed/thinglink",
209 web::get().to(get_thinglink_oembed_data),
210 )
211 .route("/oembed/vimeo", web::get().to(get_vimeo_oembed_data));
212}