updated events endpoints to include preview and create
This commit is contained in:
parent
a96867d1b9
commit
65425b5626
@ -8,7 +8,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
tokio = { version = "1.27", features = ["full"] }
|
||||
axum = "0.6"
|
||||
sqlx = { version = "0.6", features = ["postgres", "runtime-tokio-rustls"] }
|
||||
sqlx = { version = "0.6", features = ["postgres", "runtime-tokio-rustls", "all-types"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tracing = "0.1"
|
||||
|
||||
152
src/events.rs
152
src/events.rs
@ -1,25 +1,104 @@
|
||||
use axum::{
|
||||
extract::{Query, State},
|
||||
http::StatusCode,
|
||||
response::IntoResponse,
|
||||
Json,
|
||||
};
|
||||
use axum::{extract::State, http::StatusCode, response::IntoResponse, Json};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
use sqlx::query;
|
||||
use sqlx::{
|
||||
query, query_as,
|
||||
types::{chrono::NaiveDateTime, BigDecimal},
|
||||
};
|
||||
|
||||
use crate::AppState;
|
||||
|
||||
#[derive(
|
||||
sqlx::Type, Copy, Clone, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize,
|
||||
)]
|
||||
#[sqlx(type_name = "event_type", rename_all = "snake_case")]
|
||||
enum EventType {
|
||||
Sports,
|
||||
Meetings,
|
||||
Drama,
|
||||
Music,
|
||||
Other,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct EventsPreviewQuery {
|
||||
count: u32,
|
||||
}
|
||||
|
||||
pub async fn get_events_preview(
|
||||
State(app_state): State<AppState>,
|
||||
Query(query): Query<EventsPreviewQuery>,
|
||||
) -> impl IntoResponse {
|
||||
let result = query!(
|
||||
#[derive(Clone, Deserialize, Debug)]
|
||||
pub struct NewEventRequestEntry {
|
||||
title: String,
|
||||
description: String,
|
||||
#[serde(with = "serialize_datetime")]
|
||||
time_start: NaiveDateTime,
|
||||
#[serde(with = "serialize_datetime")]
|
||||
time_end: NaiveDateTime,
|
||||
event_type: EventType,
|
||||
points: i32,
|
||||
place: Option<String>,
|
||||
#[serde(with = "serialize_big_decimal")]
|
||||
price: BigDecimal,
|
||||
created_by: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Debug)]
|
||||
pub struct Event {
|
||||
id: i32,
|
||||
title: String,
|
||||
description: String,
|
||||
#[serde(with = "serialize_datetime")]
|
||||
time_start: NaiveDateTime,
|
||||
#[serde(with = "serialize_datetime")]
|
||||
time_end: NaiveDateTime,
|
||||
event_type: EventType,
|
||||
points: i32,
|
||||
place: Option<String>,
|
||||
#[serde(with = "serialize_big_decimal")]
|
||||
price: BigDecimal,
|
||||
created_by: Option<i32>,
|
||||
}
|
||||
|
||||
mod serialize_datetime {
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{self, Deserialize, Deserializer, Serializer};
|
||||
use sqlx::types::chrono::NaiveDateTime;
|
||||
|
||||
pub fn serialize<S>(dt: &NaiveDateTime, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&dt.to_string())
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D: Deserializer<'de>>(
|
||||
deserializer: D,
|
||||
) -> Result<NaiveDateTime, D::Error> {
|
||||
let str = <String as Deserialize>::deserialize(deserializer)?;
|
||||
NaiveDateTime::from_str(&str).map_err(|err| serde::de::Error::custom(err))
|
||||
}
|
||||
}
|
||||
|
||||
mod serialize_big_decimal {
|
||||
use serde::{self, Deserialize, Deserializer, Serializer};
|
||||
use sqlx::types::BigDecimal;
|
||||
|
||||
pub fn serialize<S>(bd: &BigDecimal, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(&bd.to_string())
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<BigDecimal, D::Error> {
|
||||
let float = f32::deserialize(deserializer)?;
|
||||
BigDecimal::try_from(float).map_err(|err| serde::de::Error::custom(err))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_events_preview(State(app_state): State<AppState>) -> impl IntoResponse {
|
||||
let result = query_as!(
|
||||
Event,
|
||||
r#"
|
||||
SELECT
|
||||
id,
|
||||
@ -27,10 +106,9 @@ SELECT
|
||||
description,
|
||||
time_start,
|
||||
time_end,
|
||||
event_type,
|
||||
event_type AS "event_type!: EventType",
|
||||
points,
|
||||
place,
|
||||
attending,
|
||||
price,
|
||||
created_by
|
||||
FROM
|
||||
@ -42,7 +120,49 @@ ORDER BY
|
||||
LIMIT
|
||||
10;
|
||||
"#
|
||||
);
|
||||
)
|
||||
.fetch_all(&app_state.db_pool)
|
||||
.await;
|
||||
|
||||
(StatusCode::OK, Json(json!({})))
|
||||
match result {
|
||||
Ok(events) => (StatusCode::OK, Json(json!(events))),
|
||||
Err(err) => (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(json!({
|
||||
"error": format!("Unknown error getting events: {}", err)
|
||||
})),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_event(
|
||||
State(app_state): State<AppState>,
|
||||
Json(event_post_query): Json<NewEventRequestEntry>,
|
||||
) -> impl IntoResponse {
|
||||
let result = query!(
|
||||
r#"
|
||||
INSERT INTO events (title, description, time_start, time_end, event_type, points, place, price, created_by)
|
||||
VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9 )
|
||||
"#,
|
||||
event_post_query.title,
|
||||
event_post_query.description,
|
||||
event_post_query.time_start,
|
||||
event_post_query.time_end,
|
||||
event_post_query.event_type as EventType,
|
||||
event_post_query.points,
|
||||
event_post_query.place,
|
||||
event_post_query.price,
|
||||
event_post_query.created_by,
|
||||
).execute(&app_state.db_pool).await;
|
||||
|
||||
match result {
|
||||
Ok(_) => (StatusCode::OK, "").into_response(),
|
||||
Err(err) => (
|
||||
StatusCode::BAD_REQUEST,
|
||||
Json(json!({
|
||||
"error": format!("Unknown error creating event: {}", err)
|
||||
})),
|
||||
)
|
||||
.into_response(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +40,8 @@ async fn main() {
|
||||
.route("/", get(root))
|
||||
.route("/user/signup", post(signup))
|
||||
.route("/user/signin", post(signin))
|
||||
.route("/event/prview", get(events::get_events_preview))
|
||||
.route("/event", post(events::create_event))
|
||||
.route("/event/preview", get(events::get_events_preview))
|
||||
.with_state(AppState { db_pool, jwt_key });
|
||||
|
||||
// run our app with hyper
|
||||
|
||||
16
src/user.rs
16
src/user.rs
@ -8,9 +8,20 @@ use crate::{jwt::Claims, AppState};
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Signup {
|
||||
username: String,
|
||||
role: Role,
|
||||
password: String,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
sqlx::Type, Copy, Clone, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize,
|
||||
)]
|
||||
#[sqlx(type_name = "role", rename_all = "snake_case")]
|
||||
pub enum Role {
|
||||
Student,
|
||||
Teacher,
|
||||
Admin,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct Signin {
|
||||
username: String,
|
||||
@ -32,11 +43,12 @@ pub async fn signup(
|
||||
|
||||
let result = sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO users (username, password)
|
||||
VALUES ( $1, $2 )
|
||||
INSERT INTO users (username, role, password)
|
||||
VALUES ( $1, $2, $3 )
|
||||
RETURNING id;
|
||||
"#,
|
||||
signup.username,
|
||||
signup.role as Role,
|
||||
pass_hash.as_bytes(),
|
||||
)
|
||||
.fetch_one(&app_state.db_pool)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user