1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//! API handlers for the the [`proxy`](crate::web::api::v1::contexts::proxy) API
//! context.
use std::sync::Arc;

use axum::extract::{Path, State};
use axum::response::Response;

use super::responses::png_image;
use crate::cache::image::manager::Error;
use crate::common::AppData;
use crate::ui::proxy::map_error_to_image;
use crate::web::api::v1::extractors::bearer_token::Extract;

/// Get the remote image. It uses the cached image if available.
#[allow(clippy::unused_async)]
pub async fn get_proxy_image_handler(
    State(app_data): State<Arc<AppData>>,
    Extract(maybe_bearer_token): Extract,
    Path(url): Path<String>,
) -> Response {
    if maybe_bearer_token.is_none() {
        return png_image(map_error_to_image(&Error::Unauthenticated));
    }

    let Ok(user_id) = app_data.auth.get_user_id_from_bearer_token(&maybe_bearer_token).await else { return png_image(map_error_to_image(&Error::Unauthenticated)) };

    // code-review: Handling status codes in the frontend other tan OK is quite a pain.
    // Return OK for now.

    // todo: it also work for other image types but we are always returning the
    // same content type: `image/png`. If we only support PNG images we should
    // change the documentation and return an error for other image types.

    // Get image URL from URL path parameter.
    let image_url = urlencoding::decode(&url).unwrap_or_default().into_owned();

    match app_data.proxy_service.get_image_by_url(&image_url, &user_id).await {
        Ok(image_bytes) => {
            // Returns the cached image.
            png_image(image_bytes)
        }
        Err(e) => {
            // Returns an error image.
            png_image(map_error_to_image(&e))
        }
    }
}