Update
This commit is contained in:
parent
f614e606f4
commit
a177f2a5d4
22 changed files with 1339 additions and 667 deletions
|
@ -10,3 +10,6 @@ BACKEND_UNTIS_CLIENT_NAME="bvplan"
|
||||||
BACKEND_UNTIS_SCHOOL=
|
BACKEND_UNTIS_SCHOOL=
|
||||||
BACKEND_UNTIS_USERNAME=
|
BACKEND_UNTIS_USERNAME=
|
||||||
BACKEND_UNTIS_PASSWORD=
|
BACKEND_UNTIS_PASSWORD=
|
||||||
|
BACKEND_UNTIS_VPLAN_URL=
|
||||||
|
BACKEND_UNTIS_VPLAN_USERNAME=
|
||||||
|
BACKEND_UNTIS_VPLAN_PASSWORD=
|
||||||
|
|
11
Makefile
11
Makefile
|
@ -1,9 +1,6 @@
|
||||||
.PHONY: all dev prod
|
.PHONY: all build
|
||||||
|
|
||||||
all: prod
|
all: build
|
||||||
|
|
||||||
dev:
|
build:
|
||||||
docker-compose build --build-arg BUILD_ENV=development
|
BUILDKIT_PROGRESS=plain docker compose build
|
||||||
|
|
||||||
prod:
|
|
||||||
docker-compose build
|
|
||||||
|
|
|
@ -7,3 +7,27 @@ insert_final_newline = true
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.sql]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.sql]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.html]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
689
backend/Cargo.lock
generated
689
backend/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -6,6 +6,9 @@ edition = "2021"
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "api"
|
name = "api"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "worker"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
lto = "fat"
|
lto = "fat"
|
||||||
|
@ -19,13 +22,17 @@ anyhow = { version = "1.0.66", features = ["backtrace"] }
|
||||||
celery = { git = "https://github.com/rusty-celery/rusty-celery.git", branch = "main" }
|
celery = { git = "https://github.com/rusty-celery/rusty-celery.git", branch = "main" }
|
||||||
chrono = "0.4.23"
|
chrono = "0.4.23"
|
||||||
diesel = { version = "2.0.2", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes", "postgres", "chrono", "r2d2"] }
|
diesel = { version = "2.0.2", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes", "postgres", "chrono", "r2d2"] }
|
||||||
env_logger = "0.10.0"
|
env_logger = "0.9.3"
|
||||||
envconfig = "0.10.0"
|
envconfig = "0.10.0"
|
||||||
juniper = { version = "0.15.10", features = ["scalar-naivetime"] }
|
juniper = { version = "0.15.10", features = ["scalar-naivetime"] }
|
||||||
juniper_actix = "0.4.0"
|
juniper_actix = "0.4.0"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
|
r2d2_redis = "0.14.0"
|
||||||
|
reqwest = "0.11.13"
|
||||||
|
scraper = "0.14.0"
|
||||||
serde = "1.0.148"
|
serde = "1.0.148"
|
||||||
|
stdext = "0.3.1"
|
||||||
tokio = { version = "1.22.0", features = ["full"] }
|
tokio = { version = "1.22.0", features = ["full"] }
|
||||||
untis = { git = "https://git.dergrimm.net/dergrimm/untis.rs.git", branch = "main" }
|
untis = { git = "https://git.dergrimm.net/dergrimm/untis.rs.git", branch = "main" }
|
||||||
url = "2.3.1"
|
url = "2.3.1"
|
||||||
|
|
|
@ -1,26 +1,27 @@
|
||||||
FROM lukemathwalker/cargo-chef:latest-rust-1.65.0 as chef
|
FROM docker.io/lukemathwalker/cargo-chef:latest-rust-1.65.0 as chef
|
||||||
WORKDIR /usr/src/backend
|
|
||||||
|
FROM chef as diesel
|
||||||
|
RUN cargo install diesel_cli --no-default-features --features postgres
|
||||||
|
|
||||||
FROM chef as planner
|
FROM chef as planner
|
||||||
|
WORKDIR /usr/src/backend
|
||||||
RUN mkdir src && touch src/main.rs
|
RUN mkdir src && touch src/main.rs
|
||||||
COPY ./Cargo.toml ./Cargo.lock ./
|
COPY ./Cargo.toml ./Cargo.lock ./
|
||||||
RUN cargo chef prepare --recipe-path recipe.json
|
RUN cargo chef prepare --recipe-path recipe.json
|
||||||
|
|
||||||
FROM chef as builder
|
FROM chef as builder
|
||||||
|
WORKDIR /usr/src/backend
|
||||||
COPY --from=planner /usr/src/backend/recipe.json .
|
COPY --from=planner /usr/src/backend/recipe.json .
|
||||||
RUN cargo chef cook --release --recipe-path recipe.json
|
RUN cargo chef cook --release --recipe-path recipe.json
|
||||||
COPY ./src ./src
|
COPY ./src ./src
|
||||||
RUN cargo build --release
|
RUN cargo build --release
|
||||||
|
|
||||||
FROM chef as diesel
|
FROM docker.io/debian:bullseye-slim as runner
|
||||||
RUN cargo install diesel_cli --no-default-features --features postgres
|
|
||||||
|
|
||||||
FROM debian:buster-slim as runner
|
|
||||||
RUN apt update
|
RUN apt update
|
||||||
RUN apt install -y libpq5
|
RUN apt install -y libpq5
|
||||||
RUN apt install -y ca-certificates
|
RUN apt install -y ca-certificates
|
||||||
RUN apt-get clean
|
RUN apt-get clean
|
||||||
RUN apt-get autoremove --yes
|
RUN apt-get autoremove -y
|
||||||
RUN rm -rf /var/lib/{apt,dpkg,cache,log}/
|
RUN rm -rf /var/lib/{apt,dpkg,cache,log}/
|
||||||
WORKDIR /usr/local/bin
|
WORKDIR /usr/local/bin
|
||||||
COPY --from=diesel /usr/local/cargo/bin/diesel .
|
COPY --from=diesel /usr/local/cargo/bin/diesel .
|
||||||
|
|
|
@ -12,6 +12,8 @@ DROP TYPE substitution_type;
|
||||||
|
|
||||||
DROP TABLE substitution_queries;
|
DROP TABLE substitution_queries;
|
||||||
|
|
||||||
|
DROP TYPE week_type;
|
||||||
|
|
||||||
DROP TABLE timegrid_time_unit;
|
DROP TABLE timegrid_time_unit;
|
||||||
|
|
||||||
DROP TABLE timegrid_days;
|
DROP TABLE timegrid_days;
|
||||||
|
|
|
@ -110,20 +110,13 @@ CREATE TABLE timegrid_time_unit(
|
||||||
updated_at TIMESTAMP
|
updated_at TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TYPE week_type AS ENUM ('a', 'b');
|
||||||
|
|
||||||
CREATE TABLE substitution_queries (
|
CREATE TABLE substitution_queries (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
schoolyear_id INTEGER NOT NULL REFERENCES schoolyears (id),
|
schoolyear_id INTEGER NOT NULL REFERENCES schoolyears (id),
|
||||||
date DATE NOT NULL UNIQUE,
|
date DATE NOT NULL,
|
||||||
active BOOLEAN NOT NULL,
|
week_type week_type NOT NULL,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
updated_at TIMESTAMP
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE INDEX substitution_queries_active ON substitution_queries(active);
|
|
||||||
|
|
||||||
CREATE TABLE substitution_query_results(
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
substitution_query_id INTEGER NOT NULL REFERENCES substitution_queries(id),
|
|
||||||
queried_at TIMESTAMP NOT NULL,
|
queried_at TIMESTAMP NOT NULL,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP
|
updated_at TIMESTAMP
|
||||||
|
@ -149,7 +142,7 @@ CREATE TYPE substitution_type AS ENUM (
|
||||||
|
|
||||||
CREATE TABLE substitutions(
|
CREATE TABLE substitutions(
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
substitution_query_result_id INTEGER NOT NULL REFERENCES substitution_query_results(id),
|
substitution_query_id INTEGER NOT NULL REFERENCES substitution_queries (id),
|
||||||
subst_type substitution_type NOT NULL,
|
subst_type substitution_type NOT NULL,
|
||||||
lesson_id INTEGER NOT NULL,
|
lesson_id INTEGER NOT NULL,
|
||||||
start_time TIME NOT NULL,
|
start_time TIME NOT NULL,
|
||||||
|
@ -191,6 +184,7 @@ CREATE TABLE substitution_rooms(
|
||||||
substitution_id INTEGER NOT NULL REFERENCES substitutions (id),
|
substitution_id INTEGER NOT NULL REFERENCES substitutions (id),
|
||||||
position SMALLINT NOT NULL,
|
position SMALLINT NOT NULL,
|
||||||
room_id INTEGER REFERENCES rooms (id),
|
room_id INTEGER REFERENCES rooms (id),
|
||||||
|
original_room_id INTEGER REFERENCES rooms (id),
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP
|
updated_at TIMESTAMP
|
||||||
);
|
);
|
|
@ -1,4 +1,5 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
DATABASE_URL="$BACKEND_DB_URL" diesel setup \
|
DATABASE_URL="$BACKEND_DB_URL" diesel setup \
|
||||||
--migration-dir ./migrations \
|
--migration-dir ./migrations \
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
// #[cfg(not(target_env = "msvc"))]
|
|
||||||
// use tikv_jemallocator::Jemalloc;
|
|
||||||
|
|
||||||
// #[cfg(not(target_env = "msvc"))]
|
|
||||||
// #[global_allocator]
|
|
||||||
// static GLOBAL: Jemalloc = Jemalloc;
|
|
||||||
|
|
||||||
// async fn graphql_route(
|
|
||||||
// req: actix_web::HttpRequest,
|
|
||||||
// payload: actix_web::web::Payload,
|
|
||||||
// schema: actix_web::web::Data<backend::graphql::Schema>,
|
|
||||||
// ) -> Result<actix_web::HttpResponse, actix_web::Error> {
|
|
||||||
// juniper_actix::graphql_handler(
|
|
||||||
// &schema,
|
|
||||||
// &backend::graphql::Context {
|
|
||||||
// pool: backend::db::POOL.clone(),
|
|
||||||
// },
|
|
||||||
// req,
|
|
||||||
// payload,
|
|
||||||
// )
|
|
||||||
// .await
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[actix_web::main]
|
|
||||||
// async fn main() -> std::io::Result<()> {
|
|
||||||
// std::env::set_var("RUST_LOG", "info");
|
|
||||||
// env_logger::init();
|
|
||||||
|
|
||||||
// let server = actix_web::HttpServer::new(move || {
|
|
||||||
// actix_web::App::new()
|
|
||||||
// .app_data(actix_web::web::Data::new(backend::graphql::schema()))
|
|
||||||
// .wrap(
|
|
||||||
// actix_cors::Cors::default()
|
|
||||||
// .allow_any_origin()
|
|
||||||
// .allowed_methods(vec!["POST", "GET"])
|
|
||||||
// .allowed_headers(vec![
|
|
||||||
// actix_web::http::header::AUTHORIZATION,
|
|
||||||
// actix_web::http::header::ACCEPT,
|
|
||||||
// ])
|
|
||||||
// .allowed_header(actix_web::http::header::CONTENT_TYPE)
|
|
||||||
// .supports_credentials()
|
|
||||||
// .max_age(3600),
|
|
||||||
// )
|
|
||||||
// .wrap(actix_web::middleware::Compress::default())
|
|
||||||
// .wrap(actix_web::middleware::Logger::default())
|
|
||||||
// .service(
|
|
||||||
// actix_web::web::resource("/")
|
|
||||||
// .route(actix_web::web::post().to(graphql_route))
|
|
||||||
// .route(actix_web::web::get().to(graphql_route)),
|
|
||||||
// )
|
|
||||||
// });
|
|
||||||
// println!("Starting server on port 80!");
|
|
||||||
|
|
||||||
// server.bind("0.0.0.0:80")?.run().await
|
|
||||||
// }
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
#[cfg(not(target_env = "msvc"))]
|
||||||
|
use tikv_jemallocator::Jemalloc;
|
||||||
|
|
||||||
|
#[cfg(not(target_env = "msvc"))]
|
||||||
|
#[global_allocator]
|
||||||
|
static GLOBAL: Jemalloc = Jemalloc;
|
||||||
|
|
||||||
use actix_cors::Cors;
|
use actix_cors::Cors;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
http::header,
|
http::header,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use std::thread;
|
|
||||||
#[cfg(not(target_env = "msvc"))]
|
#[cfg(not(target_env = "msvc"))]
|
||||||
use tikv_jemallocator::Jemalloc;
|
use tikv_jemallocator::Jemalloc;
|
||||||
|
|
||||||
|
@ -6,6 +5,8 @@ use tikv_jemallocator::Jemalloc;
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static GLOBAL: Jemalloc = Jemalloc;
|
static GLOBAL: Jemalloc = Jemalloc;
|
||||||
|
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
std::env::set_var("RUST_LOG", "info");
|
std::env::set_var("RUST_LOG", "info");
|
||||||
|
|
26
backend/src/cache.rs
Normal file
26
backend/src/cache.rs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use r2d2_redis::{r2d2, RedisConnectionManager};
|
||||||
|
|
||||||
|
use crate::config;
|
||||||
|
|
||||||
|
pub type CachePool = r2d2::Pool<RedisConnectionManager>;
|
||||||
|
pub type ConnectionPool = r2d2::PooledConnection<RedisConnectionManager>;
|
||||||
|
|
||||||
|
pub fn establish_connection() -> Result<RedisConnectionManager> {
|
||||||
|
Ok(RedisConnectionManager::new(
|
||||||
|
config::CONFIG.redis_url.as_str(),
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pool() -> Result<CachePool> {
|
||||||
|
Ok(r2d2::Pool::builder().build(establish_connection()?)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref POOL: CachePool = pool().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod keys {
|
||||||
|
pub const LAST_SUBSTITUTION_QUERY_ID: &str = "last_subst_query_id";
|
||||||
|
}
|
|
@ -11,6 +11,9 @@ pub struct Config {
|
||||||
#[envconfig(from = "BACKEND_AMQP_URL")]
|
#[envconfig(from = "BACKEND_AMQP_URL")]
|
||||||
pub amqp_url: String,
|
pub amqp_url: String,
|
||||||
|
|
||||||
|
#[envconfig(from = "BACKEND_REDIS_URL")]
|
||||||
|
pub redis_url: String,
|
||||||
|
|
||||||
#[envconfig(from = "BACKEND_UNTIS_API_URL")]
|
#[envconfig(from = "BACKEND_UNTIS_API_URL")]
|
||||||
pub untis_api_url: String,
|
pub untis_api_url: String,
|
||||||
|
|
||||||
|
@ -28,6 +31,15 @@ pub struct Config {
|
||||||
|
|
||||||
#[envconfig(from = "BACKEND_UNTIS_PASSWORD")]
|
#[envconfig(from = "BACKEND_UNTIS_PASSWORD")]
|
||||||
pub untis_password: String,
|
pub untis_password: String,
|
||||||
|
|
||||||
|
#[envconfig(from = "BACKEND_UNTIS_VPLAN_URL")]
|
||||||
|
pub untis_vplan_url: String,
|
||||||
|
|
||||||
|
#[envconfig(from = "BACKEND_UNTIS_VPLAN_USERNAME")]
|
||||||
|
pub untis_vplan_username: String,
|
||||||
|
|
||||||
|
#[envconfig(from = "BACKEND_UNTIS_VPLAN_PASSWORD")]
|
||||||
|
pub untis_vplan_password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
use juniper::GraphQLEnum;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use crate::db::schema;
|
use crate::db::schema;
|
||||||
|
@ -187,14 +188,48 @@ pub struct NewHoliday<'a> {
|
||||||
pub end_date: NaiveDate,
|
pub end_date: NaiveDate,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Identifiable, Queryable, Associations, Debug)]
|
#[derive(GraphQLEnum, diesel::FromSqlRow, diesel::AsExpression, PartialEq, Eq, Clone, Debug)]
|
||||||
|
#[diesel(sql_type = schema::sql_types::WeekType)]
|
||||||
|
pub enum WeekType {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl diesel::serialize::ToSql<schema::sql_types::WeekType, diesel::pg::Pg> for WeekType {
|
||||||
|
fn to_sql<'b>(
|
||||||
|
&'b self,
|
||||||
|
out: &mut diesel::serialize::Output<'b, '_, diesel::pg::Pg>,
|
||||||
|
) -> diesel::serialize::Result {
|
||||||
|
match *self {
|
||||||
|
Self::A => out.write_all(b"a")?,
|
||||||
|
Self::B => out.write_all(b"b")?,
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(diesel::serialize::IsNull::No)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl diesel::deserialize::FromSql<schema::sql_types::WeekType, diesel::pg::Pg> for WeekType {
|
||||||
|
fn from_sql(
|
||||||
|
bytes: diesel::backend::RawValue<'_, diesel::pg::Pg>,
|
||||||
|
) -> diesel::deserialize::Result<Self> {
|
||||||
|
match bytes.as_bytes() {
|
||||||
|
b"a" => Ok(Self::A),
|
||||||
|
b"b" => Ok(Self::B),
|
||||||
|
_ => Err("Unrecognized enum variant".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Identifiable, Queryable, Associations, Clone, Debug)]
|
||||||
#[diesel(table_name = schema::substitution_queries)]
|
#[diesel(table_name = schema::substitution_queries)]
|
||||||
#[diesel(belongs_to(Schoolyear))]
|
#[diesel(belongs_to(Schoolyear))]
|
||||||
pub struct SubstitutionQuery {
|
pub struct SubstitutionQuery {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub schoolyear_id: i32,
|
pub schoolyear_id: i32,
|
||||||
pub date: NaiveDate,
|
pub date: NaiveDate,
|
||||||
pub active: bool,
|
pub week_type: WeekType,
|
||||||
|
pub queried_at: NaiveDateTime,
|
||||||
pub created_at: NaiveDateTime,
|
pub created_at: NaiveDateTime,
|
||||||
pub updated_at: Option<NaiveDateTime>,
|
pub updated_at: Option<NaiveDateTime>,
|
||||||
}
|
}
|
||||||
|
@ -204,27 +239,11 @@ pub struct SubstitutionQuery {
|
||||||
pub struct NewSubstitutionQuery {
|
pub struct NewSubstitutionQuery {
|
||||||
pub schoolyear_id: i32,
|
pub schoolyear_id: i32,
|
||||||
pub date: NaiveDate,
|
pub date: NaiveDate,
|
||||||
pub active: bool,
|
pub week_type: WeekType,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Identifiable, Queryable, Associations, Debug)]
|
|
||||||
#[diesel(table_name = schema::substitution_query_results)]
|
|
||||||
#[diesel(belongs_to(SubstitutionQuery))]
|
|
||||||
pub struct SubstitutionQueryResult {
|
|
||||||
pub id: i32,
|
|
||||||
pub substitution_query_id: i32,
|
|
||||||
pub queried_at: NaiveDateTime,
|
|
||||||
pub created_at: NaiveDateTime,
|
|
||||||
pub updated_at: Option<NaiveDateTime>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Insertable, Debug)]
|
|
||||||
#[diesel(table_name = schema::substitution_query_results)]
|
|
||||||
pub struct NewSubstitutionQueryResult {
|
|
||||||
pub substitution_query_id: i32,
|
|
||||||
pub queried_at: NaiveDateTime,
|
pub queried_at: NaiveDateTime,
|
||||||
}
|
}
|
||||||
#[derive(diesel::FromSqlRow, diesel::AsExpression, PartialEq, Eq, Debug)]
|
|
||||||
|
#[derive(GraphQLEnum, diesel::FromSqlRow, diesel::AsExpression, PartialEq, Eq, Clone, Debug)]
|
||||||
#[diesel(sql_type = schema::sql_types::SubstitutionType)]
|
#[diesel(sql_type = schema::sql_types::SubstitutionType)]
|
||||||
pub enum SubstitutionType {
|
pub enum SubstitutionType {
|
||||||
Cancel,
|
Cancel,
|
||||||
|
@ -324,10 +343,10 @@ impl From<untis::RpcSubstitionType> for SubstitutionType {
|
||||||
|
|
||||||
#[derive(Identifiable, Queryable, Associations, Debug)]
|
#[derive(Identifiable, Queryable, Associations, Debug)]
|
||||||
#[diesel(table_name = schema::substitutions)]
|
#[diesel(table_name = schema::substitutions)]
|
||||||
#[diesel(belongs_to(SubstitutionQueryResult))]
|
#[diesel(belongs_to(SubstitutionQuery))]
|
||||||
pub struct Substitution {
|
pub struct Substitution {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub substitution_query_result_id: i32,
|
pub substitution_query_id: i32,
|
||||||
pub subst_type: SubstitutionType,
|
pub subst_type: SubstitutionType,
|
||||||
pub lesson_id: i32,
|
pub lesson_id: i32,
|
||||||
pub start_time: NaiveTime,
|
pub start_time: NaiveTime,
|
||||||
|
@ -340,7 +359,7 @@ pub struct Substitution {
|
||||||
#[derive(Insertable, Debug)]
|
#[derive(Insertable, Debug)]
|
||||||
#[diesel(table_name = schema::substitutions)]
|
#[diesel(table_name = schema::substitutions)]
|
||||||
pub struct NewSubstitution<'a> {
|
pub struct NewSubstitution<'a> {
|
||||||
pub substitution_query_result_id: i32,
|
pub substitution_query_id: i32,
|
||||||
pub subst_type: SubstitutionType,
|
pub subst_type: SubstitutionType,
|
||||||
pub lesson_id: i32,
|
pub lesson_id: i32,
|
||||||
pub start_time: NaiveTime,
|
pub start_time: NaiveTime,
|
||||||
|
@ -421,6 +440,7 @@ pub struct SubstitutionRoom {
|
||||||
pub position: i16,
|
pub position: i16,
|
||||||
pub index: i16,
|
pub index: i16,
|
||||||
pub room_id: Option<i32>,
|
pub room_id: Option<i32>,
|
||||||
|
pub original_room_id: Option<i32>,
|
||||||
pub created_at: NaiveDateTime,
|
pub created_at: NaiveDateTime,
|
||||||
pub updated_at: Option<NaiveDateTime>,
|
pub updated_at: Option<NaiveDateTime>,
|
||||||
}
|
}
|
||||||
|
@ -431,4 +451,5 @@ pub struct NewSubstitutionRoom {
|
||||||
pub substitution_id: i32,
|
pub substitution_id: i32,
|
||||||
pub position: i16,
|
pub position: i16,
|
||||||
pub room_id: Option<i32>,
|
pub room_id: Option<i32>,
|
||||||
|
pub original_room_id: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,10 @@ pub mod sql_types {
|
||||||
#[derive(diesel::sql_types::SqlType)]
|
#[derive(diesel::sql_types::SqlType)]
|
||||||
#[diesel(postgres_type(name = "substitution_type"))]
|
#[diesel(postgres_type(name = "substitution_type"))]
|
||||||
pub struct SubstitutionType;
|
pub struct SubstitutionType;
|
||||||
|
|
||||||
|
#[derive(diesel::sql_types::SqlType)]
|
||||||
|
#[diesel(postgres_type(name = "week_type"))]
|
||||||
|
pub struct WeekType;
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
|
@ -136,20 +140,15 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
|
use diesel::sql_types::*;
|
||||||
|
|
||||||
|
use super::sql_types::WeekType;
|
||||||
|
|
||||||
substitution_queries {
|
substitution_queries {
|
||||||
id -> Integer,
|
id -> Integer,
|
||||||
schoolyear_id -> Integer,
|
schoolyear_id -> Integer,
|
||||||
date -> Date,
|
date -> Date,
|
||||||
active -> Bool,
|
week_type -> WeekType,
|
||||||
created_at -> Timestamp,
|
|
||||||
updated_at -> Nullable<Timestamp>,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diesel::table! {
|
|
||||||
substitution_query_results {
|
|
||||||
id -> Integer,
|
|
||||||
substitution_query_id -> Integer,
|
|
||||||
queried_at -> Timestamp,
|
queried_at -> Timestamp,
|
||||||
created_at -> Timestamp,
|
created_at -> Timestamp,
|
||||||
updated_at -> Nullable<Timestamp>,
|
updated_at -> Nullable<Timestamp>,
|
||||||
|
@ -163,7 +162,7 @@ diesel::table! {
|
||||||
|
|
||||||
substitutions {
|
substitutions {
|
||||||
id -> Integer,
|
id -> Integer,
|
||||||
substitution_query_result_id -> Integer,
|
substitution_query_id -> Integer,
|
||||||
subst_type -> SubstitutionType,
|
subst_type -> SubstitutionType,
|
||||||
lesson_id -> Integer,
|
lesson_id -> Integer,
|
||||||
start_time -> Time,
|
start_time -> Time,
|
||||||
|
@ -213,6 +212,7 @@ diesel::table! {
|
||||||
substitution_id -> Integer,
|
substitution_id -> Integer,
|
||||||
position -> SmallInt,
|
position -> SmallInt,
|
||||||
room_id -> Nullable<Integer>,
|
room_id -> Nullable<Integer>,
|
||||||
|
original_room_id -> Nullable<Integer>,
|
||||||
created_at -> Timestamp,
|
created_at -> Timestamp,
|
||||||
updated_at -> Nullable<Timestamp>,
|
updated_at -> Nullable<Timestamp>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,286 @@
|
||||||
use juniper::{graphql_object, EmptyMutation, EmptySubscription, GraphQLObject, RootNode};
|
use diesel::prelude::*;
|
||||||
|
use juniper::{graphql_object, EmptyMutation, EmptySubscription, FieldResult, RootNode};
|
||||||
|
use r2d2_redis::redis;
|
||||||
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
|
use crate::{cache, db};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Context;
|
pub struct Context;
|
||||||
|
|
||||||
impl juniper::Context for Context {}
|
impl juniper::Context for Context {}
|
||||||
|
|
||||||
|
pub struct Schoolyear {
|
||||||
|
pub model: db::models::Schoolyear,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql_object]
|
||||||
|
impl Schoolyear {
|
||||||
|
fn id(&self) -> i32 {
|
||||||
|
self.model.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn untis_id(&self) -> i32 {
|
||||||
|
self.model.untis_id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
self.model.name.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_date(&self) -> chrono::NaiveDate {
|
||||||
|
self.model.start_date
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_date(&self) -> chrono::NaiveDate {
|
||||||
|
self.model.end_date
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Teacher {
|
||||||
|
pub model: db::models::Teacher,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql_object]
|
||||||
|
impl Teacher {
|
||||||
|
fn id(&self) -> i32 {
|
||||||
|
self.model.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn untis_id(&self) -> i32 {
|
||||||
|
self.model.untis_id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schoolyear(&self) -> FieldResult<Schoolyear> {
|
||||||
|
let db_conn = &mut db::POOL.get()?;
|
||||||
|
|
||||||
|
Ok(Schoolyear {
|
||||||
|
model: db::schema::schoolyears::table
|
||||||
|
.filter(db::schema::schoolyears::id.eq(self.model.schoolyear_id))
|
||||||
|
.first::<db::models::Schoolyear>(db_conn)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
&self.model.name
|
||||||
|
}
|
||||||
|
|
||||||
|
fn forename(&self) -> Option<&str> {
|
||||||
|
self.model.forename.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_name(&self) -> &str {
|
||||||
|
&self.model.display_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Class {
|
||||||
|
pub model: db::models::Class,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql_object]
|
||||||
|
impl Class {
|
||||||
|
fn id(&self) -> i32 {
|
||||||
|
self.model.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn untis_id(&self) -> i32 {
|
||||||
|
self.model.untis_id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schoolyear(&self) -> FieldResult<Schoolyear> {
|
||||||
|
let db_conn = &mut db::POOL.get()?;
|
||||||
|
|
||||||
|
Ok(Schoolyear {
|
||||||
|
model: db::schema::schoolyears::table
|
||||||
|
.filter(db::schema::schoolyears::id.eq(self.model.schoolyear_id))
|
||||||
|
.first::<db::models::Schoolyear>(db_conn)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
&self.model.name
|
||||||
|
}
|
||||||
|
|
||||||
|
fn long_name(&self) -> &str {
|
||||||
|
&self.model.long_name
|
||||||
|
}
|
||||||
|
|
||||||
|
fn active(&self) -> bool {
|
||||||
|
self.model.active
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SubstitutionClass {
|
||||||
|
pub model: db::models::SubstitutionClass,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql_object]
|
||||||
|
impl SubstitutionClass {
|
||||||
|
fn id(&self) -> i32 {
|
||||||
|
self.model.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn substitution(&self) -> FieldResult<Substitution> {
|
||||||
|
let db_conn = &mut db::POOL.get()?;
|
||||||
|
|
||||||
|
Ok(Substitution {
|
||||||
|
model: db::schema::substitutions::table
|
||||||
|
.filter(db::schema::substitutions::id.eq(self.model.substitution_id))
|
||||||
|
.first::<db::models::Substitution>(db_conn)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn position(&self) -> i32 {
|
||||||
|
self.model.position as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn class(&self) -> FieldResult<Class> {
|
||||||
|
let db_conn = &mut db::POOL.get()?;
|
||||||
|
|
||||||
|
Ok(Class {
|
||||||
|
model: db::schema::classes::table
|
||||||
|
.filter(db::schema::classes::id.eq(self.model.class_id))
|
||||||
|
.first::<db::models::Class>(db_conn)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SubstitutionTeacher {
|
||||||
|
pub model: db::models::SubstitutionTeacher,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql_object]
|
||||||
|
impl SubstitutionTeacher {
|
||||||
|
fn id(&self) -> i32 {
|
||||||
|
self.model.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn substitution(&self) -> FieldResult<Substitution> {
|
||||||
|
let db_conn = &mut db::POOL.get()?;
|
||||||
|
|
||||||
|
Ok(Substitution {
|
||||||
|
model: db::schema::substitutions::table
|
||||||
|
.filter(db::schema::substitutions::id.eq(self.model.substitution_id))
|
||||||
|
.first::<db::models::Substitution>(db_conn)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn position(&self) -> i32 {
|
||||||
|
self.model.position as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn teacher(&self) -> FieldResult<Option<Teacher>> {
|
||||||
|
if let Some(teacher_id) = self.model.teacher_id {
|
||||||
|
let db_conn = &mut db::POOL.get()?;
|
||||||
|
|
||||||
|
Ok(Some(Teacher {
|
||||||
|
model: db::schema::teachers::table
|
||||||
|
.filter(db::schema::teachers::id.eq(teacher_id))
|
||||||
|
.first::<db::models::Teacher>(db_conn)?,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Substitution {
|
||||||
|
pub model: db::models::Substitution,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql_object]
|
||||||
|
impl Substitution {
|
||||||
|
fn id(&self) -> i32 {
|
||||||
|
self.model.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn substitution_query(&self) -> FieldResult<SubstitutionQuery> {
|
||||||
|
let db_conn = &mut db::POOL.get()?;
|
||||||
|
|
||||||
|
Ok(SubstitutionQuery {
|
||||||
|
model: db::schema::substitution_queries::table
|
||||||
|
.filter(db::schema::substitution_queries::id.eq(self.model.substitution_query_id))
|
||||||
|
.first::<db::models::SubstitutionQuery>(db_conn)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subst_type(&self) -> db::models::SubstitutionType {
|
||||||
|
self.model.subst_type.to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lesson_id(&self) -> i32 {
|
||||||
|
self.model.lesson_id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_time(&self) -> chrono::NaiveTime {
|
||||||
|
self.model.start_time
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_time(&self) -> chrono::NaiveTime {
|
||||||
|
self.model.end_time
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text(&self) -> Option<&str> {
|
||||||
|
self.model.text.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn classes(&self) -> FieldResult<Vec<SubstitutionClass>> {
|
||||||
|
let db_conn = &mut db::POOL.get()?;
|
||||||
|
|
||||||
|
Ok(db::schema::substitution_classes::table
|
||||||
|
.filter(db::schema::substitution_classes::substitution_id.eq(self.model.id))
|
||||||
|
.load::<db::models::SubstitutionClass>(db_conn)?
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| SubstitutionClass { model: x })
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SubstitutionQuery {
|
||||||
|
pub model: db::models::SubstitutionQuery,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql_object]
|
||||||
|
impl SubstitutionQuery {
|
||||||
|
fn id(&self) -> i32 {
|
||||||
|
self.model.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schoolyear(&self) -> FieldResult<Schoolyear> {
|
||||||
|
let db_conn = &mut db::POOL.get()?;
|
||||||
|
|
||||||
|
Ok(Schoolyear {
|
||||||
|
model: db::schema::schoolyears::table
|
||||||
|
.filter(db::schema::schoolyears::id.eq(self.model.schoolyear_id))
|
||||||
|
.first::<db::models::Schoolyear>(db_conn)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn date(&self) -> chrono::NaiveDate {
|
||||||
|
self.model.date
|
||||||
|
}
|
||||||
|
|
||||||
|
fn week_type(&self) -> db::models::WeekType {
|
||||||
|
self.model.week_type.to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn queried_at(&self) -> chrono::NaiveDateTime {
|
||||||
|
self.model.queried_at
|
||||||
|
}
|
||||||
|
|
||||||
|
fn substitutions(&self) -> FieldResult<Vec<Substitution>> {
|
||||||
|
let db_conn = &mut db::POOL.get()?;
|
||||||
|
|
||||||
|
Ok(db::schema::substitutions::table
|
||||||
|
.filter(db::schema::substitutions::substitution_query_id.eq(self.model.id))
|
||||||
|
.load::<db::models::Substitution>(db_conn)?
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| Substitution { model: x })
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Query;
|
pub struct Query;
|
||||||
|
|
||||||
#[graphql_object(context = Context)]
|
#[graphql_object(context = Context)]
|
||||||
|
@ -12,6 +288,29 @@ impl Query {
|
||||||
fn ping() -> &'static str {
|
fn ping() -> &'static str {
|
||||||
"pong"
|
"pong"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn last_substitution_query() -> FieldResult<SubstitutionQuery> {
|
||||||
|
let db_conn = &mut db::POOL.get()?;
|
||||||
|
let redis_conn = &mut cache::POOL.get()?;
|
||||||
|
|
||||||
|
let id = redis::cmd("GET")
|
||||||
|
.arg(cache::keys::LAST_SUBSTITUTION_QUERY_ID)
|
||||||
|
.query::<Option<i32>>(redis_conn.deref_mut())?
|
||||||
|
.map_or_else(
|
||||||
|
|| {
|
||||||
|
db::schema::substitution_queries::table
|
||||||
|
.select(db::schema::substitution_queries::id)
|
||||||
|
.order(db::schema::substitution_queries::queried_at.desc())
|
||||||
|
.first::<i32>(db_conn)
|
||||||
|
},
|
||||||
|
|x| Ok(x),
|
||||||
|
)?;
|
||||||
|
let last_query = db::schema::substitution_queries::table
|
||||||
|
.filter(db::schema::substitution_queries::id.eq(id))
|
||||||
|
.first::<db::models::SubstitutionQuery>(db_conn)?;
|
||||||
|
|
||||||
|
Ok(SubstitutionQuery { model: last_query })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Schema = RootNode<'static, Query, EmptyMutation<Context>, EmptySubscription<Context>>;
|
pub type Schema = RootNode<'static, Query, EmptyMutation<Context>, EmptySubscription<Context>>;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod cache;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
pub mod graphql;
|
pub mod graphql;
|
||||||
|
|
|
@ -4,6 +4,7 @@ use lazy_static::lazy_static;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time;
|
use std::time;
|
||||||
|
use stdext::duration::DurationExt;
|
||||||
|
|
||||||
use crate::config;
|
use crate::config;
|
||||||
|
|
||||||
|
@ -63,9 +64,9 @@ pub fn beat() -> impl std::future::Future<
|
||||||
celery::beat!(
|
celery::beat!(
|
||||||
broker = AMQPBroker { &config::CONFIG.amqp_url },
|
broker = AMQPBroker { &config::CONFIG.amqp_url },
|
||||||
tasks = [
|
tasks = [
|
||||||
"update_info_" => {
|
"update_info" => {
|
||||||
update_info::update_info,
|
update_info::update_info,
|
||||||
schedule = DeltaSchedule::new(time::Duration::from_secs(5 * 60)),
|
schedule = DeltaSchedule::new(time::Duration::from_minutes(5)),
|
||||||
args = (),
|
args = (),
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
use anyhow::Result;
|
use anyhow::{bail, Context, Result};
|
||||||
use celery::error::TaskError;
|
use celery::error::TaskError;
|
||||||
use celery::task::TaskResult;
|
use celery::task::TaskResult;
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use r2d2_redis::redis;
|
||||||
|
use std::ops::DerefMut;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::{config, db};
|
use crate::{cache, config, db};
|
||||||
|
|
||||||
async fn fetch_schoolyears(client: &untis::Client, conn: &mut PgConnection) -> Result<i32> {
|
async fn fetch_schoolyears(client: &untis::Client, db_conn: &mut PgConnection) -> Result<i32> {
|
||||||
let existing_schoolyears = db::schema::schoolyears::table
|
let existing_schoolyears = db::schema::schoolyears::table
|
||||||
.select(db::schema::schoolyears::untis_id)
|
.select(db::schema::schoolyears::untis_id)
|
||||||
.load::<i32>(conn)?;
|
.load::<i32>(db_conn)?;
|
||||||
diesel::insert_into(db::schema::schoolyears::table)
|
diesel::insert_into(db::schema::schoolyears::table)
|
||||||
.values(
|
.values(
|
||||||
&client
|
&client
|
||||||
|
@ -27,29 +30,29 @@ async fn fetch_schoolyears(client: &untis::Client, conn: &mut PgConnection) -> R
|
||||||
})
|
})
|
||||||
.collect::<Vec<db::models::NewSchoolyear>>(),
|
.collect::<Vec<db::models::NewSchoolyear>>(),
|
||||||
)
|
)
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
|
|
||||||
Ok(db::schema::schoolyears::table
|
Ok(db::schema::schoolyears::table
|
||||||
.filter(db::schema::schoolyears::untis_id.eq(client.current_schoolyear().await?.id))
|
.filter(db::schema::schoolyears::untis_id.eq(client.current_schoolyear().await?.id))
|
||||||
.select(db::schema::schoolyears::id)
|
.select(db::schema::schoolyears::id)
|
||||||
.first(conn)?)
|
.first(db_conn)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_current_tenant(
|
async fn fetch_current_tenant(
|
||||||
client: &untis::Client,
|
client: &untis::Client,
|
||||||
conn: &mut PgConnection,
|
db_conn: &mut PgConnection,
|
||||||
schoolyear_id: i32,
|
schoolyear_id: i32,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let tenant = client.current_tenant().await?;
|
let tenant = client.current_tenant().await?;
|
||||||
if diesel::select(diesel::dsl::not(diesel::dsl::exists(
|
if diesel::select(diesel::dsl::not(diesel::dsl::exists(
|
||||||
db::schema::tenants::table.filter(db::schema::tenants::untis_id.eq(tenant.id)),
|
db::schema::tenants::table.filter(db::schema::tenants::untis_id.eq(tenant.id)),
|
||||||
)))
|
)))
|
||||||
.get_result::<bool>(conn)?
|
.get_result::<bool>(db_conn)?
|
||||||
{
|
{
|
||||||
diesel::update(db::schema::tenants::table)
|
diesel::update(db::schema::tenants::table)
|
||||||
.filter(db::schema::tenants::active)
|
.filter(db::schema::tenants::active)
|
||||||
.set(db::schema::tenants::active.eq(false))
|
.set(db::schema::tenants::active.eq(false))
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
diesel::insert_into(db::schema::tenants::table)
|
diesel::insert_into(db::schema::tenants::table)
|
||||||
.values(db::models::NewTenant {
|
.values(db::models::NewTenant {
|
||||||
untis_id: tenant.id,
|
untis_id: tenant.id,
|
||||||
|
@ -57,13 +60,13 @@ async fn fetch_current_tenant(
|
||||||
name: &tenant.display_name,
|
name: &tenant.display_name,
|
||||||
active: true,
|
active: true,
|
||||||
})
|
})
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
} else if diesel::select(diesel::dsl::exists(
|
} else if diesel::select(diesel::dsl::exists(
|
||||||
db::schema::tenants::table
|
db::schema::tenants::table
|
||||||
.filter(db::schema::tenants::untis_id.eq(tenant.id))
|
.filter(db::schema::tenants::untis_id.eq(tenant.id))
|
||||||
.filter(db::schema::tenants::active.eq(false)),
|
.filter(db::schema::tenants::active.eq(false)),
|
||||||
))
|
))
|
||||||
.get_result::<bool>(conn)?
|
.get_result::<bool>(db_conn)?
|
||||||
{
|
{
|
||||||
diesel::update(db::schema::tenants::table)
|
diesel::update(db::schema::tenants::table)
|
||||||
.filter(db::schema::tenants::active)
|
.filter(db::schema::tenants::active)
|
||||||
|
@ -71,14 +74,14 @@ async fn fetch_current_tenant(
|
||||||
db::schema::tenants::active.eq(false),
|
db::schema::tenants::active.eq(false),
|
||||||
db::schema::tenants::updated_at.eq(diesel::dsl::now),
|
db::schema::tenants::updated_at.eq(diesel::dsl::now),
|
||||||
))
|
))
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
diesel::update(db::schema::tenants::table)
|
diesel::update(db::schema::tenants::table)
|
||||||
.filter(db::schema::tenants::untis_id.eq(tenant.id))
|
.filter(db::schema::tenants::untis_id.eq(tenant.id))
|
||||||
.set((
|
.set((
|
||||||
db::schema::tenants::active.eq(true),
|
db::schema::tenants::active.eq(true),
|
||||||
db::schema::tenants::updated_at.eq(diesel::dsl::now),
|
db::schema::tenants::updated_at.eq(diesel::dsl::now),
|
||||||
))
|
))
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -86,13 +89,13 @@ async fn fetch_current_tenant(
|
||||||
|
|
||||||
async fn fetch_teachers(
|
async fn fetch_teachers(
|
||||||
client: &untis::Client,
|
client: &untis::Client,
|
||||||
conn: &mut PgConnection,
|
db_conn: &mut PgConnection,
|
||||||
schoolyear_id: i32,
|
schoolyear_id: i32,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let existing_teachers = db::schema::teachers::table
|
let existing_teachers = db::schema::teachers::table
|
||||||
.select(db::schema::teachers::untis_id)
|
.select(db::schema::teachers::untis_id)
|
||||||
.filter(db::schema::teachers::schoolyear_id.eq(schoolyear_id))
|
.filter(db::schema::teachers::schoolyear_id.eq(schoolyear_id))
|
||||||
.load::<i32>(conn)?;
|
.load::<i32>(db_conn)?;
|
||||||
diesel::insert_into(db::schema::teachers::table)
|
diesel::insert_into(db::schema::teachers::table)
|
||||||
.values(
|
.values(
|
||||||
&client
|
&client
|
||||||
|
@ -113,20 +116,20 @@ async fn fetch_teachers(
|
||||||
})
|
})
|
||||||
.collect::<Vec<db::models::NewTeacher>>(),
|
.collect::<Vec<db::models::NewTeacher>>(),
|
||||||
)
|
)
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_classes(
|
async fn fetch_classes(
|
||||||
client: &untis::Client,
|
client: &untis::Client,
|
||||||
conn: &mut PgConnection,
|
db_conn: &mut PgConnection,
|
||||||
schoolyear_id: i32,
|
schoolyear_id: i32,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let existing_classes = db::schema::classes::table
|
let existing_classes = db::schema::classes::table
|
||||||
.select(db::schema::classes::untis_id)
|
.select(db::schema::classes::untis_id)
|
||||||
.filter(db::schema::classes::schoolyear_id.eq(schoolyear_id))
|
.filter(db::schema::classes::schoolyear_id.eq(schoolyear_id))
|
||||||
.load::<i32>(conn)?;
|
.load::<i32>(db_conn)?;
|
||||||
diesel::insert_into(db::schema::classes::table)
|
diesel::insert_into(db::schema::classes::table)
|
||||||
.values(
|
.values(
|
||||||
&client
|
&client
|
||||||
|
@ -143,20 +146,20 @@ async fn fetch_classes(
|
||||||
})
|
})
|
||||||
.collect::<Vec<db::models::NewClass>>(),
|
.collect::<Vec<db::models::NewClass>>(),
|
||||||
)
|
)
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_subjects(
|
async fn fetch_subjects(
|
||||||
client: &untis::Client,
|
client: &untis::Client,
|
||||||
conn: &mut PgConnection,
|
db_conn: &mut PgConnection,
|
||||||
schoolyear_id: i32,
|
schoolyear_id: i32,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let existing_classes = db::schema::subjects::table
|
let existing_classes = db::schema::subjects::table
|
||||||
.select(db::schema::subjects::untis_id)
|
.select(db::schema::subjects::untis_id)
|
||||||
.filter(db::schema::subjects::schoolyear_id.eq(schoolyear_id))
|
.filter(db::schema::subjects::schoolyear_id.eq(schoolyear_id))
|
||||||
.load::<i32>(conn)?;
|
.load::<i32>(db_conn)?;
|
||||||
diesel::insert_into(db::schema::subjects::table)
|
diesel::insert_into(db::schema::subjects::table)
|
||||||
.values(
|
.values(
|
||||||
&client
|
&client
|
||||||
|
@ -172,20 +175,20 @@ async fn fetch_subjects(
|
||||||
})
|
})
|
||||||
.collect::<Vec<db::models::NewSubject>>(),
|
.collect::<Vec<db::models::NewSubject>>(),
|
||||||
)
|
)
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_rooms(
|
async fn fetch_rooms(
|
||||||
client: &untis::Client,
|
client: &untis::Client,
|
||||||
conn: &mut PgConnection,
|
db_conn: &mut PgConnection,
|
||||||
schoolyear_id: i32,
|
schoolyear_id: i32,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let existing_classes = db::schema::rooms::table
|
let existing_classes = db::schema::rooms::table
|
||||||
.select(db::schema::rooms::untis_id)
|
.select(db::schema::rooms::untis_id)
|
||||||
.filter(db::schema::rooms::schoolyear_id.eq(schoolyear_id))
|
.filter(db::schema::rooms::schoolyear_id.eq(schoolyear_id))
|
||||||
.load::<i32>(conn)?;
|
.load::<i32>(db_conn)?;
|
||||||
diesel::insert_into(db::schema::rooms::table)
|
diesel::insert_into(db::schema::rooms::table)
|
||||||
.values(
|
.values(
|
||||||
&client
|
&client
|
||||||
|
@ -201,20 +204,20 @@ async fn fetch_rooms(
|
||||||
})
|
})
|
||||||
.collect::<Vec<db::models::NewRoom>>(),
|
.collect::<Vec<db::models::NewRoom>>(),
|
||||||
)
|
)
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_departments(
|
async fn fetch_departments(
|
||||||
client: &untis::Client,
|
client: &untis::Client,
|
||||||
conn: &mut PgConnection,
|
db_conn: &mut PgConnection,
|
||||||
schoolyear_id: i32,
|
schoolyear_id: i32,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let existing_classes = db::schema::departments::table
|
let existing_classes = db::schema::departments::table
|
||||||
.select(db::schema::departments::untis_id)
|
.select(db::schema::departments::untis_id)
|
||||||
.filter(db::schema::departments::schoolyear_id.eq(schoolyear_id))
|
.filter(db::schema::departments::schoolyear_id.eq(schoolyear_id))
|
||||||
.load::<i32>(conn)?;
|
.load::<i32>(db_conn)?;
|
||||||
diesel::insert_into(db::schema::departments::table)
|
diesel::insert_into(db::schema::departments::table)
|
||||||
.values(
|
.values(
|
||||||
&client
|
&client
|
||||||
|
@ -230,20 +233,20 @@ async fn fetch_departments(
|
||||||
})
|
})
|
||||||
.collect::<Vec<db::models::NewDepartment>>(),
|
.collect::<Vec<db::models::NewDepartment>>(),
|
||||||
)
|
)
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_holidays(
|
async fn fetch_holidays(
|
||||||
client: &untis::Client,
|
client: &untis::Client,
|
||||||
conn: &mut PgConnection,
|
db_conn: &mut PgConnection,
|
||||||
schoolyear_id: i32,
|
schoolyear_id: i32,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let existing_classes = db::schema::holidays::table
|
let existing_classes = db::schema::holidays::table
|
||||||
.select(db::schema::holidays::untis_id)
|
.select(db::schema::holidays::untis_id)
|
||||||
.filter(db::schema::holidays::schoolyear_id.eq(schoolyear_id))
|
.filter(db::schema::holidays::schoolyear_id.eq(schoolyear_id))
|
||||||
.load::<i32>(conn)?;
|
.load::<i32>(db_conn)?;
|
||||||
diesel::insert_into(db::schema::holidays::table)
|
diesel::insert_into(db::schema::holidays::table)
|
||||||
.values(
|
.values(
|
||||||
&client
|
&client
|
||||||
|
@ -261,49 +264,88 @@ async fn fetch_holidays(
|
||||||
})
|
})
|
||||||
.collect::<Vec<db::models::NewHoliday>>(),
|
.collect::<Vec<db::models::NewHoliday>>(),
|
||||||
)
|
)
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fetch_substitutions(
|
lazy_static! {
|
||||||
client: &untis::Client,
|
static ref TITLE_SELECTOR: scraper::Selector = scraper::Selector::parse(".mon_title").unwrap();
|
||||||
conn: &mut PgConnection,
|
|
||||||
schoolyear_id: i32,
|
|
||||||
) -> Result<()> {
|
|
||||||
let today = Utc::now().date_naive();
|
|
||||||
if diesel::select(diesel::dsl::not(diesel::dsl::exists(
|
|
||||||
db::schema::substitution_queries::table
|
|
||||||
.filter(db::schema::substitution_queries::date.eq(today)),
|
|
||||||
)))
|
|
||||||
.get_result::<bool>(conn)?
|
|
||||||
{
|
|
||||||
diesel::insert_into(db::schema::substitution_queries::table)
|
|
||||||
.values(db::models::NewSubstitutionQuery {
|
|
||||||
schoolyear_id,
|
|
||||||
date: today,
|
|
||||||
active: true,
|
|
||||||
})
|
|
||||||
.execute(conn)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for query in db::schema::substitution_queries::table
|
async fn fetch_substitutions(
|
||||||
.filter(db::schema::substitution_queries::active)
|
client: &untis::Client,
|
||||||
.load::<db::models::SubstitutionQuery>(conn)?
|
db_conn: &mut PgConnection,
|
||||||
|
redis_conn: &mut cache::ConnectionPool,
|
||||||
|
schoolyear_id: i32,
|
||||||
|
) -> Result<()> {
|
||||||
|
let (date, week_type) = {
|
||||||
|
let html = reqwest::Client::new()
|
||||||
|
.get(&config::CONFIG.untis_vplan_url)
|
||||||
|
.header(
|
||||||
|
reqwest::header::USER_AGENT,
|
||||||
|
&config::CONFIG.untis_client_name,
|
||||||
|
)
|
||||||
|
.header(reqwest::header::ACCEPT, "text/html")
|
||||||
|
.basic_auth(
|
||||||
|
&config::CONFIG.untis_vplan_username,
|
||||||
|
Some(&config::CONFIG.untis_vplan_password),
|
||||||
|
)
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.text()
|
||||||
|
.await?;
|
||||||
|
let document = scraper::Html::parse_document(&html);
|
||||||
|
let title = document
|
||||||
|
.select(&TITLE_SELECTOR)
|
||||||
|
.next()
|
||||||
|
.context("No element in vplan html which is selectable class \"mon_title\"")?
|
||||||
|
.text()
|
||||||
|
.next()
|
||||||
|
.context("\"mon_title\" element is empty")?
|
||||||
|
.split_once(',')
|
||||||
|
.context("Could not split \"mon_title\" string")?;
|
||||||
|
|
||||||
|
(
|
||||||
|
chrono::NaiveDate::parse_from_str(
|
||||||
|
title
|
||||||
|
.0
|
||||||
|
.split_whitespace()
|
||||||
|
.next()
|
||||||
|
.context("Could not find date")?,
|
||||||
|
"%d.%m.%Y",
|
||||||
|
)?,
|
||||||
|
match title
|
||||||
|
.1
|
||||||
|
.split_whitespace()
|
||||||
|
.last()
|
||||||
|
.context("Could not find week type indicator")?
|
||||||
{
|
{
|
||||||
let query_result_id = diesel::insert_into(db::schema::substitution_query_results::table)
|
"A" => db::models::WeekType::A,
|
||||||
.values(db::models::NewSubstitutionQueryResult {
|
"B" => db::models::WeekType::B,
|
||||||
substitution_query_id: query.id,
|
x => bail!("Invalid week type: {:?}", x),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let substitution_query_id = diesel::insert_into(db::schema::substitution_queries::table)
|
||||||
|
.values(db::models::NewSubstitutionQuery {
|
||||||
|
schoolyear_id,
|
||||||
|
date,
|
||||||
|
week_type,
|
||||||
queried_at: Utc::now().naive_utc(),
|
queried_at: Utc::now().naive_utc(),
|
||||||
})
|
})
|
||||||
.returning(db::schema::substitution_query_results::id)
|
.returning(db::schema::substitution_queries::id)
|
||||||
.get_result::<i32>(conn)?;
|
.get_result::<i32>(db_conn)?;
|
||||||
|
redis::cmd("SET")
|
||||||
|
.arg(cache::keys::LAST_SUBSTITUTION_QUERY_ID)
|
||||||
|
.arg(substitution_query_id)
|
||||||
|
.query(redis_conn.deref_mut())?;
|
||||||
|
|
||||||
let substs = client.substitutions(&query.date, &query.date, None).await?;
|
for substitution in client.substitutions(&date, &date, None).await? {
|
||||||
for substitution in substs {
|
|
||||||
let substitution_id = diesel::insert_into(db::schema::substitutions::table)
|
let substitution_id = diesel::insert_into(db::schema::substitutions::table)
|
||||||
.values(db::models::NewSubstitution {
|
.values(db::models::NewSubstitution {
|
||||||
substitution_query_result_id: query_result_id,
|
substitution_query_id,
|
||||||
subst_type: substitution.subst_type.into(),
|
subst_type: substitution.subst_type.into(),
|
||||||
lesson_id: substitution.lesson_id,
|
lesson_id: substitution.lesson_id,
|
||||||
start_time: substitution.start_time,
|
start_time: substitution.start_time,
|
||||||
|
@ -311,7 +353,7 @@ async fn fetch_substitutions(
|
||||||
text: substitution.text.as_deref(),
|
text: substitution.text.as_deref(),
|
||||||
})
|
})
|
||||||
.returning(db::schema::substitutions::id)
|
.returning(db::schema::substitutions::id)
|
||||||
.get_result::<i32>(conn)?;
|
.get_result::<i32>(db_conn)?;
|
||||||
|
|
||||||
diesel::insert_into(db::schema::substitution_classes::table)
|
diesel::insert_into(db::schema::substitution_classes::table)
|
||||||
.values(
|
.values(
|
||||||
|
@ -326,12 +368,13 @@ async fn fetch_substitutions(
|
||||||
class_id: db::schema::classes::table
|
class_id: db::schema::classes::table
|
||||||
.filter(db::schema::classes::untis_id.eq(c.id))
|
.filter(db::schema::classes::untis_id.eq(c.id))
|
||||||
.select(db::schema::classes::id)
|
.select(db::schema::classes::id)
|
||||||
.get_result::<i32>(conn)?,
|
.get_result::<i32>(db_conn)?,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<db::models::NewSubstitutionClass>>>()?,
|
.collect::<Result<Vec<db::models::NewSubstitutionClass>>>()?,
|
||||||
)
|
)
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
|
|
||||||
diesel::insert_into(db::schema::substitution_teachers::table)
|
diesel::insert_into(db::schema::substitution_teachers::table)
|
||||||
.values(
|
.values(
|
||||||
&substitution
|
&substitution
|
||||||
|
@ -349,14 +392,15 @@ async fn fetch_substitutions(
|
||||||
db::schema::teachers::table
|
db::schema::teachers::table
|
||||||
.filter(db::schema::teachers::untis_id.eq(t.id))
|
.filter(db::schema::teachers::untis_id.eq(t.id))
|
||||||
.select(db::schema::teachers::id)
|
.select(db::schema::teachers::id)
|
||||||
.get_result::<i32>(conn)?,
|
.get_result::<i32>(db_conn)?,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<db::models::NewSubstitutionTeacher>>>()?,
|
.collect::<Result<Vec<db::models::NewSubstitutionTeacher>>>()?,
|
||||||
)
|
)
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
|
|
||||||
diesel::insert_into(db::schema::substitution_subjects::table)
|
diesel::insert_into(db::schema::substitution_subjects::table)
|
||||||
.values(
|
.values(
|
||||||
&substitution
|
&substitution
|
||||||
|
@ -370,12 +414,13 @@ async fn fetch_substitutions(
|
||||||
subject_id: db::schema::subjects::table
|
subject_id: db::schema::subjects::table
|
||||||
.filter(db::schema::subjects::untis_id.eq(s.id))
|
.filter(db::schema::subjects::untis_id.eq(s.id))
|
||||||
.select(db::schema::subjects::id)
|
.select(db::schema::subjects::id)
|
||||||
.get_result::<i32>(conn)?,
|
.get_result::<i32>(db_conn)?,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<db::models::NewSubstitutionSubject>>>()?,
|
.collect::<Result<Vec<db::models::NewSubstitutionSubject>>>()?,
|
||||||
)
|
)
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
|
|
||||||
diesel::insert_into(db::schema::substitution_rooms::table)
|
diesel::insert_into(db::schema::substitution_rooms::table)
|
||||||
.values(
|
.values(
|
||||||
&substitution
|
&substitution
|
||||||
|
@ -393,15 +438,24 @@ async fn fetch_substitutions(
|
||||||
db::schema::rooms::table
|
db::schema::rooms::table
|
||||||
.filter(db::schema::rooms::untis_id.eq(r.id))
|
.filter(db::schema::rooms::untis_id.eq(r.id))
|
||||||
.select(db::schema::rooms::id)
|
.select(db::schema::rooms::id)
|
||||||
.get_result::<i32>(conn)?,
|
.get_result::<i32>(db_conn)?,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
original_room_id: if let Some(original_id) = r.original_id {
|
||||||
|
Some(
|
||||||
|
db::schema::rooms::table
|
||||||
|
.filter(db::schema::rooms::untis_id.eq(original_id))
|
||||||
|
.select(db::schema::rooms::id)
|
||||||
|
.get_result::<i32>(db_conn)?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<db::models::NewSubstitutionRoom>>>()?,
|
.collect::<Result<Vec<db::models::NewSubstitutionRoom>>>()?,
|
||||||
)
|
)
|
||||||
.execute(conn)?;
|
.execute(db_conn)?;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -409,10 +463,9 @@ async fn fetch_substitutions(
|
||||||
|
|
||||||
#[celery::task]
|
#[celery::task]
|
||||||
pub async fn update_info() -> TaskResult<()> {
|
pub async fn update_info() -> TaskResult<()> {
|
||||||
let dur = Duration::from_secs(10);
|
let dur = Duration::from_secs(2);
|
||||||
|
|
||||||
thread::sleep(dur);
|
thread::sleep(dur);
|
||||||
dbg!("DONE!");
|
|
||||||
let mut client = match config::untis_from_env() {
|
let mut client = match config::untis_from_env() {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(e) => return Err(TaskError::UnexpectedError(e.to_string())),
|
Err(e) => return Err(TaskError::UnexpectedError(e.to_string())),
|
||||||
|
@ -421,65 +474,58 @@ pub async fn update_info() -> TaskResult<()> {
|
||||||
return Err(TaskError::UnexpectedError(e.to_string()));
|
return Err(TaskError::UnexpectedError(e.to_string()));
|
||||||
}
|
}
|
||||||
thread::sleep(dur);
|
thread::sleep(dur);
|
||||||
dbg!("DONE!");
|
|
||||||
|
|
||||||
let conn = &mut match db::POOL.get() {
|
let db_conn = &mut match db::POOL.get() {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => return Err(TaskError::UnexpectedError(e.to_string())),
|
||||||
|
};
|
||||||
|
let redis_conn = &mut match cache::POOL.get() {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(e) => return Err(TaskError::UnexpectedError(e.to_string())),
|
Err(e) => return Err(TaskError::UnexpectedError(e.to_string())),
|
||||||
};
|
};
|
||||||
|
|
||||||
let schoolyear_id = match fetch_schoolyears(&client, conn).await {
|
let schoolyear_id = match fetch_schoolyears(&client, db_conn).await {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(e) => return Err(TaskError::UnexpectedError(e.to_string())),
|
Err(e) => return Err(TaskError::UnexpectedError(e.to_string())),
|
||||||
};
|
};
|
||||||
thread::sleep(dur);
|
thread::sleep(dur);
|
||||||
dbg!("DONE!");
|
if let Err(e) = fetch_current_tenant(&client, db_conn, schoolyear_id).await {
|
||||||
if let Err(e) = fetch_current_tenant(&client, conn, schoolyear_id).await {
|
|
||||||
return Err(TaskError::UnexpectedError(e.to_string()));
|
return Err(TaskError::UnexpectedError(e.to_string()));
|
||||||
}
|
}
|
||||||
thread::sleep(dur);
|
thread::sleep(dur);
|
||||||
dbg!("DONE!");
|
if let Err(e) = fetch_teachers(&client, db_conn, schoolyear_id).await {
|
||||||
if let Err(e) = fetch_teachers(&client, conn, schoolyear_id).await {
|
|
||||||
return Err(TaskError::UnexpectedError(e.to_string()));
|
return Err(TaskError::UnexpectedError(e.to_string()));
|
||||||
}
|
}
|
||||||
thread::sleep(dur);
|
thread::sleep(dur);
|
||||||
dbg!("DONE!");
|
if let Err(e) = fetch_classes(&client, db_conn, schoolyear_id).await {
|
||||||
if let Err(e) = fetch_classes(&client, conn, schoolyear_id).await {
|
|
||||||
return Err(TaskError::UnexpectedError(e.to_string()));
|
return Err(TaskError::UnexpectedError(e.to_string()));
|
||||||
}
|
}
|
||||||
thread::sleep(dur);
|
thread::sleep(dur);
|
||||||
dbg!("DONE!");
|
if let Err(e) = fetch_subjects(&client, db_conn, schoolyear_id).await {
|
||||||
if let Err(e) = fetch_subjects(&client, conn, schoolyear_id).await {
|
|
||||||
return Err(TaskError::UnexpectedError(e.to_string()));
|
return Err(TaskError::UnexpectedError(e.to_string()));
|
||||||
}
|
}
|
||||||
thread::sleep(dur);
|
thread::sleep(dur);
|
||||||
dbg!("DONE!");
|
if let Err(e) = fetch_rooms(&client, db_conn, schoolyear_id).await {
|
||||||
if let Err(e) = fetch_rooms(&client, conn, schoolyear_id).await {
|
|
||||||
return Err(TaskError::UnexpectedError(e.to_string()));
|
return Err(TaskError::UnexpectedError(e.to_string()));
|
||||||
}
|
}
|
||||||
thread::sleep(dur);
|
thread::sleep(dur);
|
||||||
dbg!("DONE!");
|
if let Err(e) = fetch_departments(&client, db_conn, schoolyear_id).await {
|
||||||
if let Err(e) = fetch_departments(&client, conn, schoolyear_id).await {
|
|
||||||
return Err(TaskError::UnexpectedError(e.to_string()));
|
return Err(TaskError::UnexpectedError(e.to_string()));
|
||||||
}
|
}
|
||||||
thread::sleep(dur);
|
thread::sleep(dur);
|
||||||
dbg!("DONE!");
|
if let Err(e) = fetch_holidays(&client, db_conn, schoolyear_id).await {
|
||||||
if let Err(e) = fetch_holidays(&client, conn, schoolyear_id).await {
|
|
||||||
return Err(TaskError::UnexpectedError(e.to_string()));
|
return Err(TaskError::UnexpectedError(e.to_string()));
|
||||||
}
|
}
|
||||||
thread::sleep(dur);
|
thread::sleep(dur);
|
||||||
dbg!("DONE!");
|
if let Err(e) = fetch_substitutions(&client, db_conn, redis_conn, schoolyear_id).await {
|
||||||
if let Err(e) = fetch_substitutions(&client, conn, schoolyear_id).await {
|
|
||||||
return Err(TaskError::UnexpectedError(e.to_string()));
|
return Err(TaskError::UnexpectedError(e.to_string()));
|
||||||
}
|
}
|
||||||
thread::sleep(dur);
|
thread::sleep(dur);
|
||||||
dbg!("DONE!");
|
|
||||||
|
|
||||||
if let Err(e) = client.logout().await {
|
if let Err(e) = client.logout().await {
|
||||||
return Err(TaskError::UnexpectedError(e.to_string()));
|
return Err(TaskError::UnexpectedError(e.to_string()));
|
||||||
}
|
}
|
||||||
thread::sleep(dur);
|
thread::sleep(dur);
|
||||||
dbg!("DONE!");
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,24 +32,5 @@ http {
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~* /rabbitmq/api/(.*?)/(.*) {
|
|
||||||
proxy_pass http://rabbitmq:15672/api/$1/%2F/$2?$query_string;
|
|
||||||
proxy_buffering off;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~* /rabbitmq/(.*) {
|
|
||||||
rewrite ^/rabbitmq/(.*)$ /$1 break;
|
|
||||||
proxy_pass http://rabbitmq:15672;
|
|
||||||
proxy_buffering off;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,15 +10,20 @@ x-backend:
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres
|
- postgres
|
||||||
- rabbitmq
|
- rabbitmq
|
||||||
|
- redis
|
||||||
environment:
|
environment:
|
||||||
BACKEND_DB_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_USER}
|
BACKEND_DB_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_USER}
|
||||||
BACKEND_AMQP_URL: amqp://${RABBITMQ_USER}:${RABBITMQ_PASSWORD}@rabbitmq:5672
|
BACKEND_AMQP_URL: amqp://${RABBITMQ_USER}:${RABBITMQ_PASSWORD}@rabbitmq:5672
|
||||||
|
BACKEND_REDIS_URL: redis://redis:6379
|
||||||
BACKEND_UNTIS_API_URL: ${BACKEND_UNTIS_API_URL}
|
BACKEND_UNTIS_API_URL: ${BACKEND_UNTIS_API_URL}
|
||||||
BACKEND_UNTIS_RPC_URL: ${BACKEND_UNTIS_RPC_URL}
|
BACKEND_UNTIS_RPC_URL: ${BACKEND_UNTIS_RPC_URL}
|
||||||
BACKEND_UNTIS_CLIENT_NAME: ${BACKEND_UNTIS_CLIENT_NAME}
|
BACKEND_UNTIS_CLIENT_NAME: ${BACKEND_UNTIS_CLIENT_NAME}
|
||||||
BACKEND_UNTIS_SCHOOL: ${BACKEND_UNTIS_SCHOOL}
|
BACKEND_UNTIS_SCHOOL: ${BACKEND_UNTIS_SCHOOL}
|
||||||
BACKEND_UNTIS_USERNAME: ${BACKEND_UNTIS_USERNAME}
|
BACKEND_UNTIS_USERNAME: ${BACKEND_UNTIS_USERNAME}
|
||||||
BACKEND_UNTIS_PASSWORD: ${BACKEND_UNTIS_PASSWORD}
|
BACKEND_UNTIS_PASSWORD: ${BACKEND_UNTIS_PASSWORD}
|
||||||
|
BACKEND_UNTIS_VPLAN_URL: ${BACKEND_UNTIS_VPLAN_URL}
|
||||||
|
BACKEND_UNTIS_VPLAN_USERNAME: ${BACKEND_UNTIS_VPLAN_USERNAME}
|
||||||
|
BACKEND_UNTIS_VPLAN_PASSWORD: ${BACKEND_UNTIS_VPLAN_PASSWORD}
|
||||||
|
|
||||||
services:
|
services:
|
||||||
nginx:
|
nginx:
|
||||||
|
@ -49,7 +54,7 @@ services:
|
||||||
- postgres
|
- postgres
|
||||||
|
|
||||||
rabbitmq:
|
rabbitmq:
|
||||||
image: docker.io/rabbitmq:3-management-alpine
|
image: docker.io/rabbitmq:3-alpine
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER}
|
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER}
|
||||||
|
@ -57,6 +62,12 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- rabbitmq:/var/lib/rabbitmq
|
- rabbitmq:/var/lib/rabbitmq
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: docker.io/redis:alpine
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- redis:/data
|
||||||
|
|
||||||
worker:
|
worker:
|
||||||
<<: *backend
|
<<: *backend
|
||||||
command: worker
|
command: worker
|
||||||
|
@ -72,5 +83,6 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
postgres:
|
postgres:
|
||||||
rabbitmq:
|
rabbitmq:
|
||||||
|
redis:
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue