Initial commit
Signed-off-by: Louis Vallat <louis@louis-vallat.xyz>
This commit is contained in:
commit
a5649447ff
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
.idea/
|
1395
Cargo.lock
generated
Normal file
1395
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "moviequotebot_api"
|
||||
version = "0.1.0"
|
||||
authors = ["louis"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
actix-web = "4.0.0-beta.6"
|
||||
serde = "1.0.126"
|
||||
serde_json = "1.0.64"
|
||||
diesel = { version = "1.4.7", features = ["postgres", "chrono"] }
|
||||
chrono = { version = "0.4.19", features = ["serde"]}
|
5
diesel.toml
Normal file
5
diesel.toml
Normal file
@ -0,0 +1,5 @@
|
||||
# For documentation on how to configure this file,
|
||||
# see diesel.rs/guides/configuring-diesel-cli
|
||||
|
||||
[print_schema]
|
||||
file = "src/schema.rs"
|
0
migrations/.gitkeep
Normal file
0
migrations/.gitkeep
Normal file
2
migrations/2021-06-08-102332_create_subtitle/down.sql
Normal file
2
migrations/2021-06-08-102332_create_subtitle/down.sql
Normal file
@ -0,0 +1,2 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
DROP TABLE IF EXISTS properties, films, languages, subtitle_lines, subtitles, user_config;
|
93
migrations/2021-06-08-102332_create_subtitle/up.sql
Normal file
93
migrations/2021-06-08-102332_create_subtitle/up.sql
Normal file
@ -0,0 +1,93 @@
|
||||
-- Your SQL goes here
|
||||
/**
|
||||
Store some information on the application.
|
||||
*/
|
||||
CREATE TABLE IF NOT EXISTS properties
|
||||
(
|
||||
id int GENERATED ALWAYS AS IDENTITY,
|
||||
app_key text NOT NULL,
|
||||
app_value text NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE (app_key)
|
||||
);
|
||||
|
||||
/**
|
||||
Film
|
||||
*/
|
||||
CREATE TABLE IF NOT EXISTS films
|
||||
(
|
||||
id int GENERATED ALWAYS AS IDENTITY,
|
||||
imdb_id varchar(10) NOT NULL,
|
||||
title text NOT NULL,
|
||||
year int,
|
||||
film_type text NOT NULL,
|
||||
season int,
|
||||
episode int,
|
||||
poster_link text,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE (imdb_id)
|
||||
);
|
||||
|
||||
/**
|
||||
Available languages
|
||||
*/
|
||||
CREATE TABLE IF NOT EXISTS languages
|
||||
(
|
||||
id int GENERATED ALWAYS AS IDENTITY,
|
||||
alpha3_b char(3) NOT NULL,
|
||||
alpha3_t char(3),
|
||||
alpha2 char(2),
|
||||
english text NOT NULL,
|
||||
french text NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE (alpha3_b)
|
||||
);
|
||||
|
||||
/**
|
||||
Subtitles
|
||||
*/
|
||||
CREATE TABLE IF NOT EXISTS subtitles
|
||||
(
|
||||
id int GENERATED ALWAYS AS IDENTITY,
|
||||
film_id int NOT NULL,
|
||||
language_id int NOT NULL,
|
||||
importer_id bigint,
|
||||
importer_guild_id bigint,
|
||||
imported_date timestamptz NOT NULL DEFAULT now(),
|
||||
UNIQUE (film_id, language_id),
|
||||
PRIMARY KEY (id),
|
||||
FOREIGN KEY (film_id)
|
||||
REFERENCES films (id),
|
||||
FOREIGN KEY (language_id)
|
||||
REFERENCES languages (id)
|
||||
);
|
||||
|
||||
/**
|
||||
Subtitle lines
|
||||
*/
|
||||
CREATE TABLE IF NOT EXISTS subtitle_lines
|
||||
(
|
||||
id int GENERATED ALWAYS AS IDENTITY,
|
||||
subtitle_id int NOT NULL,
|
||||
dialog_line text NOT NULL,
|
||||
time_code text NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
FOREIGN KEY (subtitle_id)
|
||||
REFERENCES subtitles (id)
|
||||
);
|
||||
|
||||
/**
|
||||
User configurations
|
||||
*/
|
||||
CREATE TABLE IF NOT EXISTS user_config
|
||||
(
|
||||
id int GENERATED ALWAYS AS IDENTITY,
|
||||
user_id bigint NOT NULL,
|
||||
guild_id bigint DEFAULT NULL,
|
||||
default_language_id int DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE (user_id, guild_id),
|
||||
FOREIGN KEY (default_language_id)
|
||||
REFERENCES languages (id)
|
||||
);
|
||||
|
8
src/lib.rs
Normal file
8
src/lib.rs
Normal file
@ -0,0 +1,8 @@
|
||||
use diesel::pg::PgConnection;
|
||||
use std::env;
|
||||
use diesel::Connection;
|
||||
|
||||
pub async fn establish_connection() -> PgConnection {
|
||||
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||
PgConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url))
|
||||
}
|
32
src/main.rs
Normal file
32
src/main.rs
Normal file
@ -0,0 +1,32 @@
|
||||
#[macro_use]
|
||||
extern crate diesel;
|
||||
extern crate actix_web;
|
||||
|
||||
mod schema;
|
||||
mod model;
|
||||
mod route;
|
||||
mod lib;
|
||||
|
||||
use actix_web::{App, HttpServer, Responder, web};
|
||||
use std::env;
|
||||
|
||||
|
||||
async fn health() -> impl Responder {
|
||||
"Healthy"
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
HttpServer::new(|| {
|
||||
App::new().service(web::scope("/v1")
|
||||
.configure(route::init_routes)
|
||||
)
|
||||
.route("/health", web::get().to(health))
|
||||
})
|
||||
.bind(format!("{}:{}",
|
||||
env::var("HOST_IP").unwrap_or("0.0.0.0".to_string()),
|
||||
env::var("HOST_PORT").unwrap_or("8080".to_string())
|
||||
))?
|
||||
.run()
|
||||
.await
|
||||
}
|
60
src/model.rs
Normal file
60
src/model.rs
Normal file
@ -0,0 +1,60 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
#[derive(Deserialize, Serialize, Queryable)]
|
||||
pub struct Subtitle {
|
||||
pub id: i32,
|
||||
pub film_id: i32,
|
||||
pub language_id: i32,
|
||||
pub importer_id: Option<i64>,
|
||||
pub importer_guild_id: Option<i64>,
|
||||
pub imported_date: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Queryable)]
|
||||
pub struct Language {
|
||||
pub id: i32,
|
||||
pub alpha3_b: String,
|
||||
pub alpha3_t: Option<String>,
|
||||
pub alpha2_b: Option<String>,
|
||||
pub english: String,
|
||||
pub french: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Queryable)]
|
||||
pub struct Film {
|
||||
pub id: i32,
|
||||
pub imdb_id: String,
|
||||
pub title: String,
|
||||
pub year: Option<i32>,
|
||||
pub film_type: String,
|
||||
pub season: Option<i32>,
|
||||
pub episode: Option<i32>,
|
||||
pub poster_link: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct SubtitleTrimmed {
|
||||
pub id: i32,
|
||||
pub film_id: i32,
|
||||
pub language_id: i32,
|
||||
pub imported_date: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl SubtitleTrimmed {
|
||||
pub fn from(s: Subtitle) -> SubtitleTrimmed {
|
||||
SubtitleTrimmed {
|
||||
id: s.id,
|
||||
film_id: s.film_id,
|
||||
language_id: s.language_id,
|
||||
imported_date: s.imported_date
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Queryable)]
|
||||
pub struct SubtitleOutV1 {
|
||||
pub subtitles: Vec<SubtitleTrimmed>,
|
||||
pub films: Vec<Film>,
|
||||
pub languages: Vec<Language>,
|
||||
}
|
44
src/route.rs
Normal file
44
src/route.rs
Normal file
@ -0,0 +1,44 @@
|
||||
extern crate diesel;
|
||||
|
||||
use actix_web::{get, web, HttpResponse, Responder};
|
||||
use crate::diesel::prelude::*;
|
||||
|
||||
use crate::lib::establish_connection;
|
||||
use crate::model::*;
|
||||
|
||||
#[get("/subtitles/list")]
|
||||
async fn list_all() -> impl Responder {
|
||||
use crate::schema::films::dsl::*;
|
||||
use crate::schema::subtitles::dsl::*;
|
||||
use crate::schema::languages::dsl::*;
|
||||
|
||||
let connection = establish_connection().await;
|
||||
let results = subtitles
|
||||
.inner_join(films)
|
||||
.inner_join(languages)
|
||||
.load::<(Subtitle, Film, Language)>(&connection).expect("Error loading subtitles");
|
||||
let mut s: Vec<SubtitleTrimmed> = vec![];
|
||||
let mut f: Vec<Film> = vec![];
|
||||
let mut l: Vec<Language> = vec![];
|
||||
for r in results {
|
||||
s.push(SubtitleTrimmed::from(r.0));
|
||||
let f_id = r.1.id;
|
||||
let l_id = r.2.id;
|
||||
if !f.iter().any(|film| film.id == f_id) {
|
||||
f.push(r.1);
|
||||
}
|
||||
if !l.iter().any(|language| language.id == l_id) {
|
||||
l.push(r.2);
|
||||
}
|
||||
}
|
||||
|
||||
HttpResponse::Ok().json(SubtitleOutV1{
|
||||
subtitles: s,
|
||||
films: f,
|
||||
languages: l
|
||||
})
|
||||
}
|
||||
|
||||
pub fn init_routes(config: &mut web::ServiceConfig) {
|
||||
config.service(list_all);
|
||||
}
|
74
src/schema.rs
Normal file
74
src/schema.rs
Normal file
@ -0,0 +1,74 @@
|
||||
table! {
|
||||
films (id) {
|
||||
id -> Int4,
|
||||
imdb_id -> Varchar,
|
||||
title -> Text,
|
||||
year -> Nullable<Int4>,
|
||||
film_type -> Text,
|
||||
season -> Nullable<Int4>,
|
||||
episode -> Nullable<Int4>,
|
||||
poster_link -> Nullable<Text>,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
languages (id) {
|
||||
id -> Int4,
|
||||
alpha3_b -> Bpchar,
|
||||
alpha3_t -> Nullable<Bpchar>,
|
||||
alpha2 -> Nullable<Bpchar>,
|
||||
english -> Text,
|
||||
french -> Text,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
properties (id) {
|
||||
id -> Int4,
|
||||
app_key -> Text,
|
||||
app_value -> Text,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
subtitle_lines (id) {
|
||||
id -> Int4,
|
||||
subtitle_id -> Int4,
|
||||
dialog_line -> Text,
|
||||
time_code -> Text,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
subtitles (id) {
|
||||
id -> Int4,
|
||||
film_id -> Int4,
|
||||
language_id -> Int4,
|
||||
importer_id -> Nullable<Int8>,
|
||||
importer_guild_id -> Nullable<Int8>,
|
||||
imported_date -> Timestamptz,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
user_config (id) {
|
||||
id -> Int4,
|
||||
user_id -> Int8,
|
||||
guild_id -> Nullable<Int8>,
|
||||
default_language_id -> Nullable<Int4>,
|
||||
}
|
||||
}
|
||||
|
||||
joinable!(subtitle_lines -> subtitles (subtitle_id));
|
||||
joinable!(subtitles -> films (film_id));
|
||||
joinable!(subtitles -> languages (language_id));
|
||||
joinable!(user_config -> languages (default_language_id));
|
||||
|
||||
allow_tables_to_appear_in_same_query!(
|
||||
films,
|
||||
languages,
|
||||
properties,
|
||||
subtitle_lines,
|
||||
subtitles,
|
||||
user_config,
|
||||
);
|
Loading…
Reference in New Issue
Block a user