lan-party-backend/backend/src/api/event.rs

181 lines
4.2 KiB
Rust

use std::future;
use futures::{StreamExt, TryStreamExt};
use rocket_db_pools::mongodb::bson::to_bson;
use super::{prelude::*, util::PartyError};
use lan_party_core::event::*;
api_routes!(
create_event,
stop_event,
get_event,
update_event,
get_all_events,
event_outcome,
delete_event,
);
pub async fn apply_outcome(outcome: &EventOutcome, db: &Connection<Db>) -> Result<(), PartyError> {
for (player, reward) in outcome.points.iter() {
db.users()
.update_one(
doc! { "id": player },
doc! { "$inc": { "score": reward } },
None,
)
.await?;
}
Ok(())
}
/// # Create event
///
/// Returns the created event.
#[openapi(tag = "Event")]
#[post("/", data = "<event>")]
pub async fn create_event(
_api_key: ApiKey,
db: Connection<Db>,
event: Json<EventSpec>,
) -> Result<Json<Event>, PartyError> {
let event = event.into_inner().create_event()?;
db.events().insert_one(&event, None).await?;
Ok(Json(event))
}
/// # Update event
///
/// Update the supplied values in the event with the given name. The `name` of an event cannot be
/// changed and `concluded` will always be false.
#[openapi(tag = "Event")]
#[post("/<name>", data = "<update>")]
pub async fn update_event(
_api_key: ApiKey,
db: Connection<Db>,
name: String,
update: Json<EventUpdate>,
) -> Result<Status, PartyError> {
let mut event = db
.events()
.find_one(doc! { "name": &name }, None)
.await?
.ok_or(PartyError::EventNotFound(name.clone()))?;
event.apply_update(update.into_inner())?;
db.events()
.update_one(
doc! { "name": &name },
doc! { "$set": to_bson(&event)? },
None,
)
.await?;
Ok(Status::Ok)
}
/// # Get event
///
/// Returns the event with the given name
#[openapi(tag = "Event")]
#[get("/<name>")]
pub async fn get_event(
_api_key: ApiKey,
db: Connection<Db>,
name: String,
) -> Result<Json<Event>, PartyError> {
Ok(Json(
db.events()
.find_one(doc! { "name": &name }, None)
.await?
.ok_or(PartyError::EventNotFound(name))?,
))
}
/// # Get events
///
/// Returns all events
#[openapi(tag = "Event")]
#[get("/?<concluded>")]
pub async fn get_all_events(
_api_key: ApiKey,
db: Connection<Db>,
concluded: Option<bool>,
) -> Result<Json<Vec<Event>>, PartyError> {
let filter = if let Some(concluded) = concluded {
doc! { "concluded": concluded }
} else {
doc! {}
};
Ok(Json(
db.events()
.find(filter, None)
.await?
.filter(|e| future::ready(e.is_ok()))
.try_collect()
.await?,
))
}
/// # Get outcome
///
/// Returns the outcome of an event.
#[openapi(tag = "Event")]
#[get("/<name>/outcome")]
pub async fn event_outcome(
_api_key: ApiKey,
db: Connection<Db>,
name: String,
) -> Result<Json<EventOutcome>, PartyError> {
let event = db
.events()
.find_one(doc! { "name": &name }, None)
.await?
.ok_or(PartyError::EventNotFound(name.clone()))?;
Ok(Json(event.outcome()))
}
/// # Stop event
///
/// This will conclude the event, apply the outcome to the users and return the outcome.
#[openapi(tag = "Event")]
#[post("/<name>/stop")]
pub async fn stop_event(
_api_key: ApiKey,
db: Connection<Db>,
name: String,
) -> Result<Json<EventOutcome>, PartyError> {
let event = db
.events()
.find_one(doc! { "name": &name }, None)
.await?
.ok_or(PartyError::EventNotFound(name.clone()))?;
event.conclude();
db.events()
.update_one(
doc! { "name": &name },
doc! { "$set": { "concluded": true } },
None,
)
.await?;
let outcome = event.outcome();
apply_outcome(&outcome, &db).await?;
Ok(Json(outcome))
}
/// # Delete event by name
#[openapi(tag = "Event")]
#[delete("/<name>")]
pub async fn delete_event(
_api_key: ApiKey,
db: Connection<Db>,
name: String,
) -> Result<Status, PartyError> {
db.events().delete_one(doc! { "name": name }, None).await?;
Ok(Status::Ok)
}