Skip to content
Snippets Groups Projects
Verified Commit 48bf978f authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Minor cleanup

parent 29c354c9
No related branches found
No related tags found
No related merge requests found
......@@ -547,8 +547,8 @@ dependencies = [
"time",
"traitobject",
"typeable",
"unicase",
"url",
"unicase 1.4.2",
"url 1.7.2",
]
[[package]]
......@@ -562,6 +562,17 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "idna"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.5.2"
......@@ -702,6 +713,7 @@ dependencies = [
"itertools",
"rocket",
"rocket_contrib",
"rocket_cors",
"serde",
"serde_json",
"uuid",
......@@ -1140,6 +1152,22 @@ dependencies = [
"yansi",
]
[[package]]
name = "rocket_cors"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea20696dc46308d0ca06222905fe38e02b8e46c087af9c82ea85cdc386271076"
dependencies = [
"log 0.4.11",
"regex",
"rocket",
"serde",
"serde_derive",
"unicase 2.6.0",
"unicase_serde",
"url 2.1.1",
]
[[package]]
name = "rocket_http"
version = "0.4.5"
......@@ -1359,6 +1387,25 @@ dependencies = [
"version_check 0.1.5",
]
[[package]]
name = "unicase"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check 0.9.2",
]
[[package]]
name = "unicase_serde"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ef53697679d874d69f3160af80bc28de12730a985d57bdf2b47456ccb8b11f1"
dependencies = [
"serde",
"unicase 2.6.0",
]
[[package]]
name = "unicode-bidi"
version = "0.3.4"
......@@ -1405,11 +1452,22 @@ version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
dependencies = [
"idna",
"idna 0.1.5",
"matches",
"percent-encoding 1.0.1",
]
[[package]]
name = "url"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
dependencies = [
"idna 0.2.0",
"matches",
"percent-encoding 2.1.0",
]
[[package]]
name = "uuid"
version = "0.7.4"
......
......@@ -11,6 +11,7 @@ env_logger = "0.7.1"
futures = "0.3.5"
itertools = "0.9.0"
rocket = "0.4.5"
rocket_cors = "0.5.2"
serde_json = "1.0.57"
[dependencies.chrono]
......@@ -24,7 +25,7 @@ features = ["postgres", "chrono", "uuidv07"]
[dependencies.rocket_contrib]
version = "0.4.5"
default-features = false
features = ["json", "diesel_postgres_pool"]
features = ["json", "diesel_postgres_pool", "serve"]
[dependencies.serde]
version = "1.0.115"
......
schema {
query: Query
}
type Query {
apiVersion: String!
genres(id: ID = null, limit: Int = null, offset: Int = null): [Genre!]!
people(id: ID = null, limit: Int = null, offset: Int = null): [Person!]!
titles(id: ID = null, limit: Int = null, offset: Int = null): [Title!]!
}
type Genre {
id: ID!
tmdbId: Int
name: String!
titles(limit: Int = null, offset: Int = null): [Title!]!
}
type Person {
id: ID!
imdbId: ID
name: String!
starring(limit: Int = null, offset: Int = null): [Title!]!
}
type Cast {
id: ID!
category: String
characters: [String!]!
credit: String
title: Title
person: Person
}
type Description {
id: ID!
region: String
languages: [String!]!
kind: LocalizedKind!
overview: String!
tagline: String
}
type ShowEpisode {
id: ID!
seasonNumber: String
episodeNumber: String
airDate: Date
show: Title
episode: Title
}
type Image {
id: ID!
kind: ImageKind!
mime: String!
src: String!
}
type Media {
id: ID!
mime: String
codecs: [String!]!
languages: [String!]!
src: String!
}
type Name {
id: ID!
region: String
languages: [String!]!
kind: LocalizedKind!
name: String!
}
type Rating {
id: ID!
region: String
certification: String!
}
type Subtitle {
id: ID!
format: String!
language: String
region: String
specifier: String
src: String!
}
type Title {
id: ID!
imdbId: String
tmdbId: Int
tvdbId: Int
originalLanguage: String
runtime: Int
yearStart: Int
yearEnd: Int
cast(limit: Int = null, offset: Int = null): [Cast!]!
descriptions(region: String = null, language: String = null, limit: Int = null, offset: Int = null): [Description!]!
genres: [Genre!]!
image: [Image!]!
media: [Media!]!
names(region: String = null, language: String = null, limit: Int = null, offset: Int = null): [Name!]!
ratings(region: String = null, limit: Int = null, offset: Int = null): [Rating!]!
subtitles: [Subtitle!]!
episodes(seasonNumber: Int = null, episodeNumber: Int = null, limit: Int = null, offset: Int = null): [ShowEpisode!]!
show: ShowEpisode
}
scalar Date
enum ImageKind {
still
backdrop
poster
logo
}
enum LocalizedKind {
primary
original
localized
}
\ No newline at end of file
use serde::{Deserialize, Serialize};
use crate::models::{Genre, Person, Title, TitleCast, TitleDescription, TitleName, TitleImage, TitleMedium, TitleRating, TitleSubtitle};
use crate::models::*;
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct TitleDto {
pub ids: TitleIdDto,
pub original_language: Option<String>,
pub runtime: Option<i32>,
pub year_start: Option<i32>,
pub year_end: Option<i32>,
pub titles: Vec<TitleNameDto>, //
pub titles: Vec<TitleNameDto>,
pub descriptions: Vec<TitleDescriptionDto>,
pub cast: Vec<TitleCastDto>,
pub genres: Vec<GenreDto>, //
pub ratings: Vec<TitleRatingDto>, //
pub images: Vec<TitleImageDto>,
pub media: Vec<TitleMediaDto>,
pub subtitles: Vec<TitleSubtitleDto>,
pub cast: Vec<CastDto>,
pub genres: Vec<GenreDto>,
pub ratings: Vec<RatingDto>,
pub images: Vec<ImageDto>,
pub media: Vec<MediaDto>,
pub subtitles: Vec<SubtitleDto>,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
}
......@@ -25,12 +27,12 @@ impl TitleDto {
src: Title,
titles: Vec<TitleNameDto>,
descriptions: Vec<TitleDescriptionDto>,
cast: Vec<TitleCastDto>,
cast: Vec<CastDto>,
genres: Vec<GenreDto>,
ratings: Vec<TitleRatingDto>,
images: Vec<TitleImageDto>,
media: Vec<TitleMediaDto>,
subtitles: Vec<TitleSubtitleDto>
ratings: Vec<RatingDto>,
images: Vec<ImageDto>,
media: Vec<MediaDto>,
subtitles: Vec<SubtitleDto>,
) -> Self {
TitleDto {
ids: TitleIdDto {
......@@ -58,6 +60,7 @@ impl TitleDto {
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct TitleIdDto {
pub uuid: uuid::Uuid,
pub imdb: Option<String>,
......@@ -66,6 +69,7 @@ pub struct TitleIdDto {
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct TitleNameDto {
pub region: Option<String>,
pub languages: Vec<String>,
......@@ -85,6 +89,7 @@ impl From<TitleName> for TitleNameDto {
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct TitleDescriptionDto {
pub region: Option<String>,
pub languages: Vec<String>,
......@@ -106,6 +111,7 @@ impl From<TitleDescription> for TitleDescriptionDto {
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct GenreDto {
pub id: uuid::Uuid,
pub tmdb_id: Option<i32>,
......@@ -123,22 +129,17 @@ impl From<Genre> for GenreDto {
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct GenreWithTitlesDto {
pub genre: GenreDto,
pub titles: Vec<TitleDto>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct TitleCastDto {
#[serde(rename_all = "camelCase")]
pub struct CastDto {
pub category: Option<String>,
pub characters: Vec<String>,
pub credit: Option<String>,
pub person: PersonDto,
}
impl TitleCastDto {
impl CastDto {
pub fn of(cast: TitleCast, person: Person) -> Self {
TitleCastDto {
CastDto {
category: cast.category,
characters: cast.characters,
credit: cast.credit,
......@@ -148,6 +149,7 @@ impl TitleCastDto {
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct PersonDto {
pub id: uuid::Uuid,
pub imdb_id: Option<String>,
......@@ -165,67 +167,82 @@ impl From<Person> for PersonDto {
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct TitleEpisodeDto {
pub show_id: uuid::Uuid,
pub episode_id: uuid::Uuid,
pub season_number: Option<String>,
pub episode_number: Option<String>,
#[serde(rename_all = "camelCase")]
pub struct EpisodeDto {
pub season: Option<String>,
pub episode: Option<String>,
pub air_date: Option<chrono::NaiveDate>,
pub title: TitleDto,
}
impl EpisodeDto {
pub fn of(episode: TitleEpisode, title: TitleDto) -> Self {
EpisodeDto {
season: episode.season_number,
episode: episode.episode_number,
air_date: episode.air_date,
title
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct TitleImageDto {
#[serde(rename_all = "camelCase")]
pub struct ImageDto {
pub kind: String,
pub mime: String,
pub src: String,
}
impl From<TitleImage> for TitleImageDto {
impl From<TitleImage> for ImageDto {
fn from(src: TitleImage) -> Self {
TitleImageDto {
ImageDto {
kind: src.kind,
mime: src.mime,
src: src.src
src: src.src,
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct TitleMediaDto {
#[serde(rename_all = "camelCase")]
pub struct MediaDto {
pub mime: String,
pub codecs: Vec<String>,
pub languages: Vec<String>,
pub src: String,
}
impl From<TitleMedium> for TitleMediaDto {
impl From<TitleMedium> for MediaDto {
fn from(src: TitleMedium) -> Self {
TitleMediaDto {
MediaDto {
mime: src.mime,
codecs: src.codecs,
languages: src.languages,
src: src.src
src: src.src,
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct TitleRatingDto {
#[serde(rename_all = "camelCase")]
pub struct RatingDto {
pub region: Option<String>,
pub certification: String,
}
impl From<TitleRating> for TitleRatingDto {
impl From<TitleRating> for RatingDto {
fn from(src: TitleRating) -> Self {
TitleRatingDto {
RatingDto {
region: src.region,
certification: src.certification
certification: src.certification,
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct TitleSubtitleDto {
#[serde(rename_all = "camelCase")]
pub struct SubtitleDto {
pub format: String,
pub language: Option<String>,
pub region: Option<String>,
......@@ -233,14 +250,21 @@ pub struct TitleSubtitleDto {
pub src: String,
}
impl From<TitleSubtitle> for TitleSubtitleDto {
impl From<TitleSubtitle> for SubtitleDto {
fn from(src: TitleSubtitle) -> Self {
TitleSubtitleDto {
SubtitleDto {
format: src.format,
language: src.language,
region: src.region,
specifier: src.specifier,
src: src.src
src: src.src,
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct GenreWithTitlesDto {
pub genre: GenreDto,
pub titles: Vec<TitleDto>,
}
\ No newline at end of file
......@@ -89,22 +89,22 @@ fn process_title(
}).collect::<Vec<_>>(),
cast.into_iter().map(|src| {
let (cast, person) = src;
TitleCastDto::of(cast, person)
CastDto::of(cast, person)
}).collect::<Vec<_>>(),
genres.into_iter().map(|(_, src)| {
GenreDto::from(src)
}).collect::<Vec<_>>(),
ratings.into_iter().map(|src| {
TitleRatingDto::from(src)
RatingDto::from(src)
}).collect::<Vec<_>>(),
images.into_iter().map(|src| {
TitleImageDto::from(src)
ImageDto::from(src)
}).collect::<Vec<_>>(),
media.into_iter().map(|src| {
TitleMediaDto::from(src)
MediaDto::from(src)
}).collect::<Vec<_>>(),
subtitles.into_iter().map(|src| {
TitleSubtitleDto::from(src)
SubtitleDto::from(src)
}).collect::<Vec<_>>(),
)
}
\ No newline at end of file
......@@ -6,10 +6,14 @@ extern crate rocket;
#[macro_use]
extern crate rocket_contrib;
use std::env;
use diesel::prelude::*;
use dotenv::dotenv;
use rocket_contrib::databases::diesel;
use rocket_contrib::json::Json;
use rocket_contrib::serve::StaticFiles;
use rocket_cors::AllowedHeaders;
use media_backend::dto::*;
use media_backend::dto_helpers::{load_title, load_titles};
......@@ -20,17 +24,17 @@ use media_backend::param_helpers::ParamUuid;
struct MediaflixConnection(diesel::PgConnection);
#[get("/api/v1/genres")]
fn list_genres(db: MediaflixConnection) -> QueryResult<Json<Vec<Genre>>> {
fn list_genres(db: MediaflixConnection) -> QueryResult<Json<Vec<GenreDto>>> {
use media_backend::schema::*;
let query = genres::table.into_boxed();
Ok(Json(query.load::<Genre>(&db.0)?))
let data = genres::table.load::<Genre>(&db.0)?;
Ok(Json(data.into_iter().map(GenreDto::from).collect::<Vec<_>>()))
}
#[get("/api/v1/genres/<id>")]
fn get_genre(db: MediaflixConnection, id: ParamUuid) -> QueryResult<Json<GenreWithTitlesDto>> {
#[get("/api/v1/genres/<genre_id>")]
fn get_genre(db: MediaflixConnection, genre_id: ParamUuid) -> QueryResult<Json<GenreWithTitlesDto>> {
use media_backend::schema::*;
let genre: Genre = genres::table
.find(id.uuid())
.find(genre_id.uuid())
.first::<Genre>(&db.0)?;
let titles: Vec<Title> = title_genres::table
.filter(title_genres::genre_id.eq(genre.id))
......@@ -54,23 +58,42 @@ fn list_titles(db: MediaflixConnection) -> QueryResult<Json<Vec<TitleDto>>> {
Ok(Json(load_titles(&db.0, titles)?))
}
#[get("/api/v1/titles/<title>")]
fn get_title(db: MediaflixConnection, title: ParamUuid) -> QueryResult<Json<TitleDto>> {
#[get("/api/v1/titles/<title_id>")]
fn get_title(db: MediaflixConnection, title_id: ParamUuid) -> QueryResult<Json<TitleDto>> {
use media_backend::schema::*;
let title = load_title(
&db.0,
titles::table
.find(title.uuid())
.find(title_id.uuid())
.first::<Title>(&db.0)?,
)?;
Ok(Json(title))
}
fn main() {
#[get("/api/v1/titles/<title_id>/episodes")]
fn list_episodes(db: MediaflixConnection, title_id: ParamUuid) -> QueryResult<Json<Vec<EpisodeDto>>> {
use media_backend::schema::*;
let titles: Vec<(TitleEpisode, Title)> = title_episodes::table
.filter(title_episodes::show_id.eq(title_id.uuid()))
.inner_join(titles::table.on(titles::id.eq(title_episodes::episode_id)))
.load::<(TitleEpisode, Title)>(&db.0)?;
let (episodes, titles): (Vec<TitleEpisode>, Vec<Title>) = titles.into_iter().unzip();
let titles = load_titles(&db.0, titles)?;
Ok(Json(episodes.into_iter().zip(titles)
.map(|(episode, title)| EpisodeDto::of(episode, title))
.collect::<Vec<_>>()))
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
dotenv().ok();
rocket::ignite()
.attach(MediaflixConnection::fairing())
.attach(rocket_cors::CorsOptions {
allowed_headers: AllowedHeaders::some(&["Authorization", "Accept", "Accept-Language"]),
allow_credentials: true,
..Default::default()
}.to_cors()?)
.mount(
"/",
rocket::routes![
......@@ -80,5 +103,8 @@ fn main() {
get_title
],
)
.mount("/static", StaticFiles::from(env::var("MEDIAFLIX_PATH")?))
.launch();
Ok(())
}
extern crate diesel;
use diesel::*;
use serde::{Deserialize, Serialize};
use super::schema::*;
#[derive(Identifiable, Queryable, Associations, Serialize, Deserialize, PartialEq, Debug)]
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[table_name = "genres"]
pub struct Genre {
pub id: uuid::Uuid,
......@@ -15,7 +14,7 @@ pub struct Genre {
pub updated_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Identifiable, Queryable, Associations, Serialize, Deserialize, PartialEq, Debug)]
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[table_name = "people"]
pub struct Person {
pub id: uuid::Uuid,
......@@ -25,7 +24,7 @@ pub struct Person {
pub updated_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Identifiable, Queryable, Associations, Serialize, Deserialize, PartialEq, Debug)]
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Title, foreign_key = "title_id")]
#[belongs_to(Person, foreign_key = "person_id")]
#[table_name = "title_casts"]
......@@ -40,7 +39,7 @@ pub struct TitleCast {
pub person_id: uuid::Uuid,
}
#[derive(Identifiable, Queryable, Associations, Serialize, Deserialize, PartialEq, Debug)]
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Title, foreign_key = "title_id")]
#[table_name = "title_descriptions"]
pub struct TitleDescription {
......@@ -55,7 +54,7 @@ pub struct TitleDescription {
pub title_id: uuid::Uuid,
}
#[derive(Identifiable, Queryable, Associations, Serialize, Deserialize, PartialEq, Debug)]
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Title, foreign_key = "show_id")]
#[table_name = "title_episodes"]
pub struct TitleEpisode {
......@@ -69,7 +68,7 @@ pub struct TitleEpisode {
pub updated_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Identifiable, Queryable, Associations, Serialize, Deserialize, PartialEq, Debug)]
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Title, foreign_key = "title_id")]
#[belongs_to(Genre, foreign_key = "genre_id")]
#[table_name = "title_genres"]
......@@ -81,7 +80,7 @@ pub struct TitleGenre {
pub updated_at: chrono::DateTime<chrono::Utc>,
}
#[derive(Identifiable, Queryable, Associations, Serialize, Deserialize, PartialEq, Debug)]
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Title, foreign_key = "title_id")]
#[table_name = "title_images"]
pub struct TitleImage {
......@@ -94,7 +93,7 @@ pub struct TitleImage {
pub title_id: uuid::Uuid,
}
#[derive(Identifiable, Queryable, Associations, Serialize, Deserialize, PartialEq, Debug)]
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Title, foreign_key = "title_id")]
#[table_name = "title_media"]
pub struct TitleMedium {
......@@ -108,7 +107,7 @@ pub struct TitleMedium {
pub title_id: uuid::Uuid,
}
#[derive(Identifiable, Queryable, Associations, Serialize, Deserialize, PartialEq, Debug)]
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Title, foreign_key = "title_id")]
#[table_name = "title_names"]
pub struct TitleName {
......@@ -122,7 +121,7 @@ pub struct TitleName {
pub title_id: uuid::Uuid,
}
#[derive(Identifiable, Queryable, Associations, Serialize, Deserialize, PartialEq, Debug)]
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Title, foreign_key = "title_id")]
#[table_name = "title_ratings"]
pub struct TitleRating {
......@@ -134,7 +133,7 @@ pub struct TitleRating {
pub title_id: uuid::Uuid,
}
#[derive(Identifiable, Queryable, Associations, Serialize, Deserialize, PartialEq, Debug)]
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Title, foreign_key = "title_id")]
#[table_name = "title_subtitles"]
pub struct TitleSubtitle {
......@@ -149,7 +148,7 @@ pub struct TitleSubtitle {
pub title_id: uuid::Uuid,
}
#[derive(Identifiable, Queryable, Serialize, Deserialize, PartialEq, Debug)]
#[derive(Identifiable, Queryable, PartialEq, Debug)]
#[table_name = "titles"]
pub struct Title {
pub id: uuid::Uuid,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment