/ backend / src / api / frontend / repositories.rs
repositories.rs
  1  use rocket::{serde::json::Json, State};
  2  use serde::Serialize;
  3  use sqlx::{
  4      types::chrono::{DateTime, Utc},
  5      Pool,
  6  };
  7  
  8  use crate::{
  9      db::DB,
 10      models::repository::ViewableRepository,
 11      services::{
 12          get_all_repositories_service,
 13          get_repository_service::{self, RepositoryInfo},
 14      },
 15  };
 16  
 17  #[derive(Responder, Debug)]
 18  pub enum GetRepositoriesResponse {
 19      #[response(status = 200)]
 20      Success(Json<GetRepositoriesResponseData>),
 21      #[response(status = 500)]
 22      Failure(String),
 23  }
 24  
 25  #[derive(Debug, Clone, Serialize)]
 26  pub struct GetRepositoriesResponseData {
 27      repositories: Vec<Repository>,
 28  }
 29  
 30  #[derive(Debug, Clone, Serialize)]
 31  #[serde(rename_all = "camelCase")]
 32  pub struct Repository {
 33      name: String,
 34      author: String,
 35      last_modified: DateTime<Utc>,
 36  }
 37  
 38  impl From<ViewableRepository> for Repository {
 39      fn from(value: ViewableRepository) -> Self {
 40          Self {
 41              name: value.namespace_name,
 42              author: value.username,
 43              last_modified: value.created_at,
 44          }
 45      }
 46  }
 47  
 48  #[get("/repositories")]
 49  pub async fn get_all_repositories(db_pool: &State<Pool<DB>>) -> GetRepositoriesResponse {
 50      let repos = match get_all_repositories_service::get_all_repositories(db_pool).await {
 51          Ok(repos) => repos,
 52          Err(err) => {
 53              error!("Failed to retrieve all repositories, err: {err:?}");
 54              return GetRepositoriesResponse::Failure("Failed to retrieve repositories".to_string());
 55          }
 56      };
 57  
 58      GetRepositoriesResponse::Success(Json(GetRepositoriesResponseData {
 59          repositories: repos
 60              .into_iter()
 61              .map(|r| r.into())
 62              .collect::<Vec<Repository>>(),
 63      }))
 64  }
 65  
 66  #[derive(Responder, Debug)]
 67  pub enum GetRepositoryResponse {
 68      #[response(status = 200)]
 69      Success(Json<GetRepositoryResponseData>),
 70      #[response(status = 404)]
 71      RepositoryNotFound(String),
 72      #[response(status = 500)]
 73      Failure(String),
 74  }
 75  
 76  #[derive(Debug, Clone, Serialize)]
 77  #[serde(rename_all = "camelCase")]
 78  pub struct GetRepositoryResponseData {
 79      name: String,
 80      author: String,
 81      tags: Vec<Tag>,
 82  }
 83  
 84  impl From<RepositoryInfo> for GetRepositoryResponseData {
 85      fn from(value: RepositoryInfo) -> Self {
 86          Self {
 87              name: value.name,
 88              author: value.owner_username,
 89              tags: value
 90                  .tags
 91                  .into_iter()
 92                  .map(|manifest| Tag {
 93                      name: manifest.tag.unwrap_or("latest".to_string()),
 94                      created_at: manifest.created_at,
 95                  })
 96                  .collect::<Vec<Tag>>(),
 97          }
 98      }
 99  }
100  
101  #[derive(Debug, Clone, Serialize)]
102  #[serde(rename_all = "camelCase")]
103  pub struct Tag {
104      name: String,
105      created_at: DateTime<Utc>,
106  }
107  
108  #[get("/repositories/<repository>")]
109  pub async fn get_repository(db_pool: &State<Pool<DB>>, repository: &str) -> GetRepositoryResponse {
110      let repository = match get_repository_service::get_repository(db_pool, repository).await {
111          Ok(data) => data,
112          Err(err) => {
113              // TODO: Handle not found
114              warn!("Failed to retrieve repository, err: {err:?}");
115              return GetRepositoryResponse::Failure("Failed to retrieve repository".to_string());
116          }
117      };
118  
119      return GetRepositoryResponse::Success(Json(repository.into()));
120  }