Skip to content

Commit ce6578f

Browse files
authored
Api: Get one movie/package/extra (#15)
2 parents a525578 + b779ab1 commit ce6578f

26 files changed

+384
-37
lines changed

api/api/src/controllers/extras.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
use crate::dto::extra::NewExtra;
2-
use crate::error_handling::{ApiError, ApiRawResult};
3-
use crate::responses::extra_creation::ExtraCreationResponse;
2+
use crate::error_handling::{ApiError, ApiRawResult, ApiResult};
3+
use crate::responses::extra::{ExtraCreationResponse, ExtraResponse};
44
use crate::services;
55
use diesel::Connection;
66
use domain::models::artist::Artist;
77
use infrastructure::Database;
88
use rocket::response::status;
9+
use rocket::serde::uuid::Uuid;
910
use rocket::{post, serde::json::Json};
1011
use rocket_okapi::okapi::openapi3::OpenApi;
1112
use rocket_okapi::settings::OpenApiSettings;
1213
use rocket_okapi::{openapi, openapi_get_routes_spec};
1314

1415
pub fn get_routes_and_docs(settings: &OpenApiSettings) -> (Vec<rocket::Route>, OpenApi) {
15-
openapi_get_routes_spec![settings: new_extra]
16+
openapi_get_routes_spec![settings: new_extra, get_extra]
1617
}
1718

1819
/// Create a new extra
@@ -75,3 +76,12 @@ async fn new_extra(
7576
|v| Ok(status::Created::new("").body(Json(v))),
7677
)
7778
}
79+
80+
/// Get a Single extra
81+
#[openapi(tag = "Extras")]
82+
#[get("/<uuid>")]
83+
async fn get_extra(db: Database, uuid: Uuid) -> ApiResult<ExtraResponse> {
84+
db.run(move |conn| services::extra::find(&uuid, conn))
85+
.await
86+
.map_or_else(|e| Err(ApiError::from(e)), |v| Ok(Json(v)))
87+
}

api/api/src/controllers/files.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use crate::error_handling::{ApiError, ApiResult};
2+
use crate::services;
3+
use domain::models::file::File;
4+
use infrastructure::Database;
5+
use rocket::serde::json::Json;
6+
use rocket::serde::uuid::Uuid;
7+
use rocket_okapi::okapi::openapi3::OpenApi;
8+
use rocket_okapi::settings::OpenApiSettings;
9+
use rocket_okapi::{openapi, openapi_get_routes_spec};
10+
11+
pub fn get_routes_and_docs(settings: &OpenApiSettings) -> (Vec<rocket::Route>, OpenApi) {
12+
openapi_get_routes_spec![settings: get_file]
13+
}
14+
15+
/// Get a Single File
16+
#[openapi(tag = "Files")]
17+
#[get("/<uuid>")]
18+
async fn get_file(db: Database, uuid: Uuid) -> ApiResult<File> {
19+
db.run(move |conn| services::file::find(&uuid, conn))
20+
.await
21+
.map_or_else(|e| Err(ApiError::from(e)), |v| Ok(Json(v)))
22+
}

api/api/src/controllers/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
pub mod artists;
22
pub mod extras;
3+
pub mod files;
34
pub mod images;
45
pub mod index;
56
pub mod movies;
7+
pub mod packages;

api/api/src/controllers/movies.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
use crate::dto::movie::NewMovie;
2-
use crate::error_handling::{ApiError, ApiRawResult};
3-
use crate::responses::movie_creation::MovieCreationResponse;
2+
use crate::error_handling::{ApiError, ApiRawResult, ApiResult};
3+
use crate::responses::chapter::ChapterResponse;
4+
use crate::responses::movie::{MovieCreationResponse, MovieResponse};
45
use crate::services;
56
use diesel::Connection;
67
use domain::models::artist::Artist;
78
use infrastructure::Database;
89
use rocket::response::status;
10+
use rocket::serde::uuid::Uuid;
911
use rocket::{post, serde::json::Json};
1012
use rocket_okapi::okapi::openapi3::OpenApi;
1113
use rocket_okapi::settings::OpenApiSettings;
1214
use rocket_okapi::{openapi, openapi_get_routes_spec};
1315

1416
pub fn get_routes_and_docs(settings: &OpenApiSettings) -> (Vec<rocket::Route>, OpenApi) {
15-
openapi_get_routes_spec![settings: new_movie]
17+
openapi_get_routes_spec![settings: new_movie, get_movie, get_movie_chapters]
1618
}
1719

1820
/// Create a new movie with its chapters
@@ -77,3 +79,21 @@ async fn new_movie(
7779
|v| Ok(status::Created::new("").body(Json(v))),
7880
)
7981
}
82+
83+
/// Get a Single Movie
84+
#[openapi(tag = "Movies")]
85+
#[get("/<slug_or_uuid>")]
86+
async fn get_movie(db: Database, slug_or_uuid: String) -> ApiResult<MovieResponse> {
87+
db.run(move |conn| services::movie::find(&slug_or_uuid, conn))
88+
.await
89+
.map_or_else(|e| Err(ApiError::from(e)), |v| Ok(Json(v)))
90+
}
91+
92+
/// Get a Movie's Chapters
93+
#[openapi(tag = "Movies")]
94+
#[get("/<uuid>/chapters")]
95+
async fn get_movie_chapters(db: Database, uuid: Uuid) -> ApiResult<Vec<ChapterResponse>> {
96+
db.run(move |conn| services::chapters::find_by_movie(&uuid, conn))
97+
.await
98+
.map_or_else(|e| Err(ApiError::from(e)), |v| Ok(Json(v)))
99+
}

api/api/src/controllers/packages.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use crate::error_handling::{ApiError, ApiResult};
2+
use crate::responses::package::PackageResponse;
3+
use crate::services;
4+
use infrastructure::Database;
5+
use rocket::serde::json::Json;
6+
use rocket_okapi::okapi::openapi3::OpenApi;
7+
use rocket_okapi::settings::OpenApiSettings;
8+
use rocket_okapi::{openapi, openapi_get_routes_spec};
9+
10+
pub fn get_routes_and_docs(settings: &OpenApiSettings) -> (Vec<rocket::Route>, OpenApi) {
11+
openapi_get_routes_spec![settings: get_package]
12+
}
13+
14+
/// Get a Single Package
15+
#[openapi(tag = "Package")]
16+
#[get("/<slug_or_uuid>")]
17+
async fn get_package(db: Database, slug_or_uuid: String) -> ApiResult<PackageResponse> {
18+
db.run(move |conn| services::package::find(&slug_or_uuid, conn))
19+
.await
20+
.map_or_else(|e| Err(ApiError::from(e)), |v| Ok(Json(v)))
21+
}

api/api/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,10 @@ fn create_server() -> Rocket<Build> {
6666
building_rocket, "/".to_owned(), openapi_settings,
6767
"/artists" => controllers::artists::get_routes_and_docs(&openapi_settings),
6868
"/extras" => controllers::extras::get_routes_and_docs(&openapi_settings),
69+
"/files" => controllers::files::get_routes_and_docs(&openapi_settings),
6970
"/images" => controllers::images::get_routes_and_docs(&openapi_settings),
7071
"/movies" => controllers::movies::get_routes_and_docs(&openapi_settings),
72+
"/packages" => controllers::packages::get_routes_and_docs(&openapi_settings),
7173
"/swagger" => (vec![], custom_openapi_spec()),
7274
};
7375

api/api/src/responses/chapter.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use domain::models::chapter::Chapter;
2+
use domain::models::image::Image;
3+
use rocket_okapi::okapi::schemars;
4+
use rocket_okapi::okapi::schemars::JsonSchema;
5+
use serde::Serialize;
6+
7+
#[derive(Serialize, JsonSchema)]
8+
pub struct ChapterResponse {
9+
#[serde(flatten)]
10+
pub chapter: Chapter,
11+
pub thumbnail: Option<Image>,
12+
}

api/api/src/responses/extra_creation.rs renamed to api/api/src/responses/extra.rs

+19
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
use crate::swagger_examples::*;
2+
use domain::models::{extra::Extra, file::File, image::Image, package::Package};
23
use rocket::serde::uuid::Uuid;
34
use rocket_okapi::okapi::schemars;
45
use rocket_okapi::okapi::schemars::JsonSchema;
56
use serde::{Deserialize, Serialize};
67

8+
use super::artist::ArtistResponse;
9+
710
#[derive(Serialize, Deserialize, JsonSchema, Debug)]
811
#[serde(crate = "rocket::serde")]
912
pub struct ExtraCreationResponse {
@@ -18,3 +21,19 @@ pub struct ExtraCreationResponse {
1821
#[schemars(example = "example_uuid")]
1922
pub file_id: Uuid,
2023
}
24+
25+
#[derive(Serialize, JsonSchema)]
26+
pub struct ExtraResponse {
27+
#[serde(flatten)]
28+
pub extra: Extra,
29+
pub thumbnail: Option<Image>,
30+
#[schemars(skip)]
31+
#[serde(skip_serializing_if = "Option::is_none")]
32+
pub package: Option<Package>,
33+
#[schemars(skip)]
34+
#[serde(skip_serializing_if = "Option::is_none")]
35+
pub artist: Option<ArtistResponse>,
36+
#[schemars(skip)]
37+
#[serde(skip_serializing_if = "Option::is_none")]
38+
pub file: Option<File>,
39+
}

api/api/src/responses/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
pub mod artist;
2-
pub mod extra_creation;
3-
pub mod movie_creation;
2+
pub mod chapter;
3+
pub mod extra;
4+
pub mod movie;
5+
pub mod package;

api/api/src/responses/movie_creation.rs renamed to api/api/src/responses/movie.rs

+19
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
use crate::swagger_examples::*;
2+
use domain::models::{file::File, image::Image, movie::Movie, package::Package};
23
use rocket::serde::uuid::Uuid;
34
use rocket_okapi::okapi::schemars;
45
use rocket_okapi::okapi::schemars::JsonSchema;
56
use serde::{Deserialize, Serialize};
67

8+
use super::artist::ArtistResponse;
9+
710
#[derive(Serialize, Deserialize, JsonSchema, Debug)]
811
#[serde(crate = "rocket::serde")]
912
pub struct MovieCreationResponse {
@@ -19,3 +22,19 @@ pub struct MovieCreationResponse {
1922
pub file_id: Uuid,
2023
pub chapters_id: Vec<Uuid>,
2124
}
25+
26+
#[derive(Serialize, JsonSchema)]
27+
pub struct MovieResponse {
28+
#[serde(flatten)]
29+
pub movie: Movie,
30+
pub poster: Option<Image>,
31+
#[schemars(skip)]
32+
#[serde(skip_serializing_if = "Option::is_none")]
33+
pub package: Option<Package>,
34+
#[schemars(skip)]
35+
#[serde(skip_serializing_if = "Option::is_none")]
36+
pub artist: Option<ArtistResponse>,
37+
#[schemars(skip)]
38+
#[serde(skip_serializing_if = "Option::is_none")]
39+
pub file: Option<File>,
40+
}

api/api/src/responses/package.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use domain::models::{artist::Artist, image::Image, package::Package};
2+
use rocket_okapi::okapi::schemars;
3+
use rocket_okapi::okapi::schemars::JsonSchema;
4+
use serde::Serialize;
5+
6+
#[derive(Serialize, JsonSchema)]
7+
pub struct PackageResponse {
8+
#[serde(flatten)]
9+
pub package: Package,
10+
pub poster: Option<Image>,
11+
#[schemars(skip)]
12+
#[serde(skip_serializing_if = "Option::is_none")]
13+
pub artist: Option<Option<Artist>>,
14+
}

api/api/src/services/artist.rs

+9-12
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,16 @@ pub fn find<'s>(
3434
use domain::schema::artists::dsl::*;
3535
use domain::schema::images::dsl::images;
3636
let uuid_parse_result = Uuid::parse_str(slug_or_uuid);
37+
let mut query = artists.left_join(images).into_boxed();
3738

38-
let (artist, image) = match uuid_parse_result {
39-
Ok(uuid) => artists
40-
.left_join(images)
41-
.filter(id.eq(uuid))
42-
.select((Artist::as_select(), Option::<Image>::as_select()))
43-
.first(connection),
44-
_ => artists
45-
.left_join(images)
46-
.filter(slug.eq(slug_or_uuid))
47-
.select((Artist::as_select(), Option::<Image>::as_select()))
48-
.first(connection),
49-
}?;
39+
if let Ok(uuid) = uuid_parse_result {
40+
query = query.filter(id.eq(uuid));
41+
} else {
42+
query = query.filter(slug.eq(slug_or_uuid))
43+
}
44+
let (artist, image) = query
45+
.select((Artist::as_select(), Option::<Image>::as_select()))
46+
.first(connection)?;
5047

5148
Ok(ArtistResponse {
5249
artist,

api/api/src/services/chapters.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use diesel::prelude::*;
2+
use domain::models::{chapter::Chapter, image::Image};
3+
use rocket::serde::uuid::Uuid;
4+
5+
use crate::responses::chapter::ChapterResponse;
6+
7+
pub fn find_by_movie(
8+
movie_uuid: &Uuid,
9+
connection: &mut PgConnection,
10+
) -> Result<Vec<ChapterResponse>, diesel::result::Error> {
11+
use domain::schema::chapters::dsl::*;
12+
use domain::schema::images::dsl::*;
13+
14+
let movie_chapters: Vec<(Chapter, Option<Image>)> = chapters
15+
.filter(movie_id.eq(movie_uuid))
16+
.left_join(images)
17+
.order(start_time.asc())
18+
.get_results(connection)?;
19+
20+
Ok(movie_chapters
21+
.iter()
22+
.map(move |(chapter, thumbnail)| -> ChapterResponse {
23+
ChapterResponse {
24+
chapter: chapter.clone(),
25+
thumbnail: thumbnail.clone(),
26+
}
27+
})
28+
.collect())
29+
}

api/api/src/services/extra.rs

+28-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
use diesel::{prelude::*, PgConnection};
2-
use domain::models::extra::{Extra, ExtraType};
2+
use domain::models::{
3+
extra::{Extra, ExtraType},
4+
image::Image,
5+
};
36
use rocket::serde::uuid::Uuid;
47
use slug::slugify;
58

9+
use crate::responses::extra::ExtraResponse;
10+
611
pub fn create<'s>(
712
extra_name: &'s str,
813
disc: Option<i16>,
@@ -29,6 +34,27 @@ pub fn create<'s>(
2934

3035
diesel::insert_into(extras)
3136
.values(&creation_dto)
32-
// .select(Extra::as_select())
3337
.get_result::<Extra>(connection)
3438
}
39+
40+
pub fn find(
41+
uuid: &Uuid,
42+
connection: &mut PgConnection,
43+
) -> Result<ExtraResponse, diesel::result::Error> {
44+
use domain::schema::extras::dsl::*;
45+
use domain::schema::images::dsl::images;
46+
47+
let (extra, image) = extras
48+
.filter(id.eq(uuid))
49+
.left_join(images)
50+
.select((Extra::as_select(), Option::<Image>::as_select()))
51+
.first(connection)?;
52+
53+
Ok(ExtraResponse {
54+
extra,
55+
thumbnail: image,
56+
artist: None,
57+
package: None,
58+
file: None,
59+
})
60+
}

api/api/src/services/file.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use diesel::prelude::*;
22
use domain::models::{file::File, video_quality::VideoQuality};
3+
use rocket::serde::uuid::Uuid;
34

45
pub fn create_or_find<'s>(
56
file_path: &'s str,
@@ -26,3 +27,9 @@ pub fn create_or_find<'s>(
2627
.values(&creation_dto)
2728
.get_result(connection)
2829
}
30+
31+
pub fn find(uuid: &Uuid, connection: &mut PgConnection) -> Result<File, diesel::result::Error> {
32+
use domain::schema::files::dsl::*;
33+
34+
files.filter(id.eq(uuid)).first(connection)
35+
}

api/api/src/services/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod artist;
22
pub mod chapter;
3+
pub mod chapters;
34
pub mod extra;
45
pub mod file;
56
pub mod image;

0 commit comments

Comments
 (0)