mi/backend/src/api/switch.rs

188 lines
5.0 KiB
Rust
Raw Normal View History

use super::{Error, Result, StringBody};
2020-11-04 17:36:12 +00:00
use crate::{
models, paseto, schema,
web::{PluralKit, SwitchCounter},
MainDatabase,
};
2020-11-02 19:03:32 +00:00
use chrono::prelude::*;
2020-11-02 18:06:50 +00:00
use diesel::prelude::*;
use rocket::State;
2020-11-02 18:06:50 +00:00
use rocket_contrib::json::Json;
2020-11-02 19:03:32 +00:00
use rusty_ulid::generate_ulid_string;
2020-11-04 12:09:41 +00:00
2020-11-02 18:06:50 +00:00
#[derive(serde::Serialize)]
pub struct FrontChange {
pub id: String,
pub who: String, // models::Member.name
pub started_at: NaiveDateTime,
pub ended_at: Option<NaiveDateTime>,
2020-11-02 19:03:32 +00:00
pub duration: Option<i32>,
2020-11-02 18:06:50 +00:00
}
#[get("/switches?<count>&<page>")]
#[instrument(skip(conn), err)]
pub fn list(
2020-11-02 18:06:50 +00:00
conn: MainDatabase,
count: Option<i64>,
page: Option<i64>,
2020-11-03 19:55:03 +00:00
tok: paseto::Token,
2020-11-02 18:06:50 +00:00
) -> Result<Json<Vec<FrontChange>>> {
use schema::{members, switches};
let count = count.unwrap_or(30);
2020-11-02 18:06:50 +00:00
let page = page.unwrap_or(0);
let count = if count < 100 { count } else { 100 };
let result: Vec<FrontChange> = switches::table
.inner_join(members::table)
.order_by(switches::dsl::started_at.desc())
.limit(count)
.offset(count * (page - 1))
.load::<(models::Switch, models::Member)>(&*conn)
.map_err(Error::Database)?
.into_iter()
2020-11-03 14:47:19 +00:00
.map(|(switch, member)| FrontChange {
duration: switch.duration(),
id: switch.id,
who: member.cmene,
started_at: switch.started_at,
ended_at: switch.ended_at,
2020-11-02 18:06:50 +00:00
})
.collect();
match result.len() {
0 => Err(Error::NotFound),
_ => Ok(Json(result)),
}
}
#[get("/switches/current")]
#[instrument(skip(conn), err)]
pub fn current_front(conn: MainDatabase, tok: paseto::Token) -> Result<Json<FrontChange>> {
2020-11-02 18:06:50 +00:00
use schema::{members, switches};
let mut front: Vec<(models::Switch, models::Member)> = switches::table
.inner_join(members::table)
.order_by(switches::dsl::started_at.desc())
.limit(1)
.load(&*conn)
.map_err(Error::Database)?;
match front.pop() {
2020-11-03 14:47:19 +00:00
Some((switch, member)) => Ok(Json(FrontChange {
duration: switch.duration(),
id: switch.id,
who: member.cmene,
started_at: switch.started_at,
ended_at: switch.ended_at,
2020-11-02 18:06:50 +00:00
})),
None => Err(Error::NotFound),
}
}
2020-11-04 20:21:12 +00:00
#[get("/switches/current/text")]
#[instrument(skip(conn), err)]
pub fn current_front_text(conn: MainDatabase, tok: paseto::Token) -> Result<String> {
use schema::{members, switches};
let mut front: Vec<(models::Switch, models::Member)> = switches::table
.inner_join(members::table)
.order_by(switches::dsl::started_at.desc())
.limit(1)
.load(&*conn)
.map_err(Error::Database)?;
match front.pop() {
Some((_, member)) => Ok(member.cmene),
None => Err(Error::NotFound),
}
}
2020-11-02 18:06:50 +00:00
#[post("/switches/switch", data = "<who>")]
#[instrument(skip(conn, sc, pk), err)]
pub fn switch(
conn: MainDatabase,
who: StringBody,
2020-11-04 17:36:12 +00:00
sc: State<SwitchCounter>,
pk: State<PluralKit>,
2020-11-03 19:55:03 +00:00
tok: paseto::Token,
) -> Result<String> {
2020-11-02 19:03:32 +00:00
use schema::{members, switches};
let who = who.unwrap();
let (last, member): (models::Switch, models::Member) = switches::table
.inner_join(members::table)
.order_by(switches::dsl::started_at.desc())
.limit(1)
.load(&*conn)
.map_err(Error::Database)?
.pop()
.ok_or_else(|| Error::NotFound)?;
let to: models::Member = members::dsl::members
.filter({
use members::dsl::cmene;
cmene.eq(who)
})
.limit(1)
.load::<models::Member>(&*conn)
.map_err(Error::Database)?
.pop()
.ok_or_else(|| Error::NotFound)?;
2020-11-05 15:16:42 +00:00
if member.cmene == to.cmene {
return Err(Error::SameFronter);
}
2020-11-02 19:03:32 +00:00
let now = Utc::now().naive_utc();
let switch = models::NewSwitch {
id: generate_ulid_string(),
member_id: to.id,
started_at: now,
};
{
use schema::switches::dsl::*;
diesel::update(switches.find(last.id))
.set(&models::UpdateSwitchTime {
ended_at: Some(now.clone()),
})
.execute(&*conn)
.map_err(Error::Database)
}?;
diesel::insert_into(switches::table)
.values(&switch)
.execute(&*conn)
.map_err(Error::Database)?;
info!(from = &member.cmene[..], to = &to.cmene[..], "switched");
sc.switch(to.cmene.clone())?;
pk.switch(to.cmene.clone())?;
2020-11-02 19:03:32 +00:00
Ok(to.cmene)
2020-11-02 18:06:50 +00:00
}
2020-11-02 19:16:35 +00:00
#[get("/switches/<switch_id>")]
#[instrument(skip(conn), err)]
pub fn get(tok: paseto::Token, conn: MainDatabase, switch_id: String) -> Result<Json<FrontChange>> {
2020-11-02 19:16:35 +00:00
use schema::{members, switches::dsl::switches};
let (switch, member): (models::Switch, models::Member) = switches
.find(switch_id)
.inner_join(members::table)
.get_result(&*conn)
.map_err(Error::Database)?;
Ok(Json(FrontChange {
2020-11-03 14:47:19 +00:00
duration: switch.duration(),
2020-11-02 19:16:35 +00:00
id: switch.id,
who: member.cmene,
started_at: switch.started_at,
ended_at: switch.ended_at,
}))
}