Use name as identifier instead of uuid

This commit is contained in:
Daan Vanoverloop 2022-09-04 10:08:18 +02:00
parent bef66328f7
commit de72a44ab5
Signed by: Danacus
GPG Key ID: F2272B50E129FC5C
5 changed files with 107 additions and 65 deletions

47
Cargo.lock generated
View File

@ -48,6 +48,15 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "android_system_properties" name = "android_system_properties"
version = "0.1.4" version = "0.1.4"
@ -939,6 +948,7 @@ dependencies = [
"okapi", "okapi",
"paste", "paste",
"rocket", "rocket",
"rocket_cors",
"rocket_db_pools", "rocket_db_pools",
"rocket_okapi", "rocket_okapi",
"schemars", "schemars",
@ -1478,6 +1488,8 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
dependencies = [ dependencies = [
"aho-corasick",
"memchr",
"regex-syntax", "regex-syntax",
] ]
@ -1585,6 +1597,22 @@ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "rocket_cors"
version = "0.6.0-alpha1"
source = "git+https://github.com/lawliet89/rocket_cors#54fae0701dffbe5df686465780218644ee3fae5f"
dependencies = [
"http",
"log",
"regex",
"rocket",
"serde",
"serde_derive",
"unicase",
"unicase_serde",
"url",
]
[[package]] [[package]]
name = "rocket_db_pools" name = "rocket_db_pools"
version = "0.1.0-rc.2" version = "0.1.0-rc.2"
@ -2442,6 +2470,25 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "unicase"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check",
]
[[package]]
name = "unicase_serde"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ef53697679d874d69f3160af80bc28de12730a985d57bdf2b47456ccb8b11f1"
dependencies = [
"serde",
"unicase",
]
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.8" version = "0.3.8"

View File

@ -16,6 +16,7 @@ futures = "0.3"
lazy_static = "1.4" lazy_static = "1.4"
serde_json = "1" serde_json = "1"
paste = "1" paste = "1"
rocket_cors = { git = "https://github.com/lawliet89/rocket_cors" }
[dependencies.sqlx] [dependencies.sqlx]
version = "*" version = "*"

View File

@ -42,9 +42,6 @@ impl EventOutcome {
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(crate = "rocket::serde")] #[serde(crate = "rocket::serde")]
pub struct Event { pub struct Event {
/// Unique identifier of the event. This will be randomly generated and cannot be modified.
#[serde(default = "uuid")]
id: String,
/// Has this event concluded? /// Has this event concluded?
#[serde(default)] #[serde(default)]
concluded: bool, concluded: bool,
@ -70,10 +67,6 @@ impl Event {
} }
} }
fn uuid() -> String {
uuid::Uuid::new_v4().to_string()
}
/// # EventSpec /// # EventSpec
/// ///
/// A specification of an event /// A specification of an event
@ -124,7 +117,6 @@ macro_rules! events {
}; };
let event = Event { let event = Event {
id: uuid(),
name: self.name, name: self.name,
description: self.description, description: self.description,
concluded: false, concluded: false,
@ -359,7 +351,7 @@ mod free_for_all_game {
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(crate = "rocket::serde")] #[serde(crate = "rocket::serde")]
pub enum FreeForAllGameRanking { pub enum FreeForAllGameRanking {
/// Ranking of participants by user id or team name (first element is first place, second element is second /// Ranking of participants by user name or team name (first element is first place, second element is second
/// place, etc.) /// place, etc.)
Ranking(Vec<String>), Ranking(Vec<String>),
/// Score based ranking of participants/teams /// Score based ranking of participants/teams
@ -378,7 +370,7 @@ mod free_for_all_game {
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(crate = "rocket::serde")] #[serde(crate = "rocket::serde")]
pub struct FreeForAllGame { pub struct FreeForAllGame {
/// Ranking of participants by user id or team name (first element is first place, second element is second /// Ranking of participants by user name or team name (first element is first place, second element is second
/// place, etc.) /// place, etc.)
ranking: Option<FreeForAllGameRanking>, ranking: Option<FreeForAllGameRanking>,
@ -437,10 +429,10 @@ mod free_for_all_game {
/// Set list of participants participating in the game /// Set list of participants participating in the game
SetParticipants(HashSet<String>), SetParticipants(HashSet<String>),
/// Add participant by id /// Add participant by name
AddParticipant(String), AddParticipant(String),
/// Remove participant by id /// Remove participant by name
RemoveParticipant(String), RemoveParticipant(String),
} }
@ -490,11 +482,11 @@ mod free_for_all_game {
}, },
}, },
FreeForAllGameUpdate::Participants(update) => match update { FreeForAllGameUpdate::Participants(update) => match update {
FreeForAllGameUpdateParticipants::AddParticipant(id) => { FreeForAllGameUpdateParticipants::AddParticipant(name) => {
self.spec.participants.insert(id); self.spec.participants.insert(name);
} }
FreeForAllGameUpdateParticipants::RemoveParticipant(id) => { FreeForAllGameUpdateParticipants::RemoveParticipant(name) => {
self.spec.participants.remove(&id); self.spec.participants.remove(&name);
if !self if !self
.ranking .ranking
@ -502,7 +494,7 @@ mod free_for_all_game {
.map(|r| r.is_valid(&self.spec.participants)) .map(|r| r.is_valid(&self.spec.participants))
.unwrap_or(true) .unwrap_or(true)
{ {
self.spec.participants.insert(id); self.spec.participants.insert(name);
return Err(PartyError::Unknown("cannot remove participant, all participants mentioned in ranking must be participating".into())); return Err(PartyError::Unknown("cannot remove participant, all participants mentioned in ranking must be participating".into()));
} }
} }
@ -562,9 +554,6 @@ events!(test => Test, team_game => TeamGame, free_for_all_game => FreeForAllGame
/// # Create event /// # Create event
/// ///
/// If an `id` is supplied, it will be replaced by a randomly generated
/// one.
///
/// Returns the created event. /// Returns the created event.
#[openapi(tag = "Event")] #[openapi(tag = "Event")]
#[post("/", data = "<event>")] #[post("/", data = "<event>")]
@ -580,26 +569,30 @@ pub async fn create_event(
/// # Update event /// # Update event
/// ///
/// Update the supplied values in the event with the given id. The `id` of an event cannot be /// 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. /// changed and `concluded` will always be false.
#[openapi(tag = "Event")] #[openapi(tag = "Event")]
#[post("/<id>", data = "<update>")] #[post("/<name>", data = "<update>")]
pub async fn update_event( pub async fn update_event(
_api_key: ApiKey, _api_key: ApiKey,
db: Connection<Db>, db: Connection<Db>,
id: String, name: String,
update: Json<EventUpdate>, update: Json<EventUpdate>,
) -> Result<Status, PartyError> { ) -> Result<Status, PartyError> {
let mut event = db let mut event = db
.events() .events()
.find_one(doc! { "id": &id }, None) .find_one(doc! { "name": &name }, None)
.await? .await?
.ok_or(PartyError::EventNotFound(id.clone()))?; .ok_or(PartyError::EventNotFound(name.clone()))?;
event.apply_update(update.into_inner())?; event.apply_update(update.into_inner())?;
db.events() db.events()
.update_one(doc! { "id": &id }, doc! { "$set": to_bson(&event)? }, None) .update_one(
doc! { "name": &name },
doc! { "$set": to_bson(&event)? },
None,
)
.await?; .await?;
Ok(Status::Ok) Ok(Status::Ok)
@ -607,19 +600,19 @@ pub async fn update_event(
/// # Get event /// # Get event
/// ///
/// Returns the event with the given id /// Returns the event with the given name
#[openapi(tag = "Event")] #[openapi(tag = "Event")]
#[get("/<id>")] #[get("/<name>")]
pub async fn get_event( pub async fn get_event(
_api_key: ApiKey, _api_key: ApiKey,
db: Connection<Db>, db: Connection<Db>,
id: String, name: String,
) -> Result<Json<Event>, PartyError> { ) -> Result<Json<Event>, PartyError> {
Ok(Json( Ok(Json(
db.events() db.events()
.find_one(doc! { "id": &id }, None) .find_one(doc! { "name": &name }, None)
.await? .await?
.ok_or(PartyError::EventNotFound(id))?, .ok_or(PartyError::EventNotFound(name))?,
)) ))
} }
@ -652,17 +645,17 @@ pub async fn get_all_events(
/// ///
/// Returns the outcome of an event. /// Returns the outcome of an event.
#[openapi(tag = "Event")] #[openapi(tag = "Event")]
#[get("/<id>/outcome")] #[get("/<name>/outcome")]
pub async fn event_outcome( pub async fn event_outcome(
_api_key: ApiKey, _api_key: ApiKey,
db: Connection<Db>, db: Connection<Db>,
id: String, name: String,
) -> Result<Json<EventOutcome>, PartyError> { ) -> Result<Json<EventOutcome>, PartyError> {
let event = db let event = db
.events() .events()
.find_one(doc! { "id": &id }, None) .find_one(doc! { "name": &name }, None)
.await? .await?
.ok_or(PartyError::EventNotFound(id.clone()))?; .ok_or(PartyError::EventNotFound(name.clone()))?;
Ok(Json(event.outcome())) Ok(Json(event.outcome()))
} }
@ -670,21 +663,21 @@ pub async fn event_outcome(
/// ///
/// This will conclude the event, apply the outcome to the users and return the outcome. /// This will conclude the event, apply the outcome to the users and return the outcome.
#[openapi(tag = "Event")] #[openapi(tag = "Event")]
#[post("/<id>/stop")] #[post("/<name>/stop")]
pub async fn stop_event( pub async fn stop_event(
_api_key: ApiKey, _api_key: ApiKey,
db: Connection<Db>, db: Connection<Db>,
id: String, name: String,
) -> Result<Json<EventOutcome>, PartyError> { ) -> Result<Json<EventOutcome>, PartyError> {
let event = db let event = db
.events() .events()
.find_one(doc! { "id": &id }, None) .find_one(doc! { "name": &name }, None)
.await? .await?
.ok_or(PartyError::EventNotFound(id.clone()))?; .ok_or(PartyError::EventNotFound(name.clone()))?;
event.conclude(); event.conclude();
db.events() db.events()
.update_one( .update_one(
doc! { "id": &id }, doc! { "name": &name },
doc! { "$set": { "concluded": true } }, doc! { "$set": { "concluded": true } },
None, None,
) )

View File

@ -22,8 +22,6 @@ pub struct User {
name: String, name: String,
/// Score of the user /// Score of the user
score: i64, score: i64,
/// Unique identifier of the user
id: String,
} }
/// # Create new user with the give name /// # Create new user with the give name
@ -37,7 +35,6 @@ pub async fn add_user(
name: Json<&str>, name: Json<&str>,
) -> Result<status::Created<Json<User>>, PartyError> { ) -> Result<status::Created<Json<User>>, PartyError> {
let user = User { let user = User {
id: uuid::Uuid::new_v4().to_string(),
score: 0, score: 0,
name: name.to_string(), name: name.to_string(),
}; };
@ -47,34 +44,34 @@ pub async fn add_user(
Ok(status::Created::new("/").body(Json(user))) Ok(status::Created::new("/").body(Json(user)))
} }
/// # Delete user by id /// # Delete user by name
#[openapi(tag = "User")] #[openapi(tag = "User")]
#[delete("/<id>")] #[delete("/<name>")]
pub async fn delete_user( pub async fn delete_user(
_api_key: ApiKey, _api_key: ApiKey,
db: Connection<Db>, db: Connection<Db>,
id: String, name: String,
) -> Result<Status, PartyError> { ) -> Result<Status, PartyError> {
db.users().delete_one(doc! { "id": id }, None).await?; db.users().delete_one(doc! { "name": name }, None).await?;
Ok(Status::Ok) Ok(Status::Ok)
} }
/// # Get user by id /// # Get user by id
/// ///
/// Returns a single user by id /// Returns a single user by name
#[openapi(tag = "User")] #[openapi(tag = "User")]
#[get("/<id>")] #[get("/<name>")]
pub async fn get_user( pub async fn get_user(
_api_key: ApiKey, _api_key: ApiKey,
db: Connection<Db>, db: Connection<Db>,
id: String, name: String,
) -> Result<Json<User>, PartyError> { ) -> Result<Json<User>, PartyError> {
let user = db let user = db
.users() .users()
.find_one(doc! { "id": &id }, None) .find_one(doc! { "name": &name }, None)
.await? .await?
.ok_or(PartyError::UserNotFound(id))?; .ok_or(PartyError::UserNotFound(name))?;
Ok(Json(user)) Ok(Json(user))
} }
@ -88,8 +85,6 @@ pub enum UserSort {
Score, Score,
#[field(value = "name")] #[field(value = "name")]
Name, Name,
#[field(value = "id")]
Id,
} }
impl ToString for UserSort { impl ToString for UserSort {
@ -97,7 +92,6 @@ impl ToString for UserSort {
match self { match self {
Self::Score => "score", Self::Score => "score",
Self::Name => "name", Self::Name => "name",
Self::Id => "id",
} }
.into() .into()
} }
@ -139,18 +133,18 @@ pub async fn get_all_users(
Ok(Json(users)) Ok(Json(users))
} }
/// # Set score of user by id /// # Set score of user by name
#[openapi(tag = "User")] #[openapi(tag = "User")]
#[post("/<id>/score", data = "<score>")] #[post("/<name>/score", data = "<score>")]
pub async fn set_score( pub async fn set_score(
_api_key: ApiKey, _api_key: ApiKey,
db: Connection<Db>, db: Connection<Db>,
id: String, name: String,
score: Json<i64>, score: Json<i64>,
) -> Result<Status, PartyError> { ) -> Result<Status, PartyError> {
db.users() db.users()
.update_one( .update_one(
doc! { "id": id }, doc! { "name": name },
doc! { "$set": { "score": *score } }, doc! { "$set": { "score": *score } },
None, None,
) )
@ -159,21 +153,21 @@ pub async fn set_score(
Ok(Status::Ok) Ok(Status::Ok)
} }
/// # Get score of user by id /// # Get score of user by name
/// ///
/// Returns the score of a single user by id /// Returns the score of a single user by name
#[openapi(tag = "User")] #[openapi(tag = "User")]
#[get("/<id>/score")] #[get("/<name>/score")]
pub async fn get_score( pub async fn get_score(
_api_key: ApiKey, _api_key: ApiKey,
db: Connection<Db>, db: Connection<Db>,
id: String, name: String,
) -> Result<Json<i64>, PartyError> { ) -> Result<Json<i64>, PartyError> {
Ok(Json( Ok(Json(
db.users() db.users()
.find_one(doc! { "id": &id }, None) .find_one(doc! { "name": &name }, None)
.await? .await?
.ok_or(PartyError::UserNotFound(id))? .ok_or(PartyError::UserNotFound(name))?
.score, .score,
)) ))
} }

View File

@ -1,5 +1,6 @@
mod api; mod api;
use rocket_cors::CorsOptions;
use rocket_db_pools::{mongodb, Database}; use rocket_db_pools::{mongodb, Database};
use rocket_okapi::{ use rocket_okapi::{
openapi, openapi,
@ -23,8 +24,14 @@ fn index() -> String {
#[launch] #[launch]
fn rocket() -> _ { fn rocket() -> _ {
let cors = CorsOptions::default()
.allowed_origins(rocket_cors::AllOrSome::All)
.to_cors()
.unwrap();
let building_rocket = rocket::build() let building_rocket = rocket::build()
.attach(Db::init()) .attach(Db::init())
.attach(cors)
.mount("/", routes![index]) .mount("/", routes![index])
.mount( .mount(
"/swagger", "/swagger",