updated events endpoints to include preview and create
This commit is contained in:
parent
a96867d1b9
commit
65425b5626
@ -8,7 +8,7 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
tokio = { version = "1.27", features = ["full"] }
|
tokio = { version = "1.27", features = ["full"] }
|
||||||
axum = "0.6"
|
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 = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
|||||||
152
src/events.rs
152
src/events.rs
@ -1,25 +1,104 @@
|
|||||||
use axum::{
|
use axum::{extract::State, http::StatusCode, response::IntoResponse, Json};
|
||||||
extract::{Query, State},
|
|
||||||
http::StatusCode,
|
|
||||||
response::IntoResponse,
|
|
||||||
Json,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use sqlx::query;
|
use sqlx::{
|
||||||
|
query, query_as,
|
||||||
|
types::{chrono::NaiveDateTime, BigDecimal},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::AppState;
|
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)]
|
#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct EventsPreviewQuery {
|
pub struct EventsPreviewQuery {
|
||||||
count: u32,
|
count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_events_preview(
|
#[derive(Clone, Deserialize, Debug)]
|
||||||
State(app_state): State<AppState>,
|
pub struct NewEventRequestEntry {
|
||||||
Query(query): Query<EventsPreviewQuery>,
|
title: String,
|
||||||
) -> impl IntoResponse {
|
description: String,
|
||||||
let result = query!(
|
#[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#"
|
r#"
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
@ -27,10 +106,9 @@ SELECT
|
|||||||
description,
|
description,
|
||||||
time_start,
|
time_start,
|
||||||
time_end,
|
time_end,
|
||||||
event_type,
|
event_type AS "event_type!: EventType",
|
||||||
points,
|
points,
|
||||||
place,
|
place,
|
||||||
attending,
|
|
||||||
price,
|
price,
|
||||||
created_by
|
created_by
|
||||||
FROM
|
FROM
|
||||||
@ -42,7 +120,49 @@ ORDER BY
|
|||||||
LIMIT
|
LIMIT
|
||||||
10;
|
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("/", get(root))
|
||||||
.route("/user/signup", post(signup))
|
.route("/user/signup", post(signup))
|
||||||
.route("/user/signin", post(signin))
|
.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 });
|
.with_state(AppState { db_pool, jwt_key });
|
||||||
|
|
||||||
// run our app with hyper
|
// 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)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
pub struct Signup {
|
pub struct Signup {
|
||||||
username: String,
|
username: String,
|
||||||
|
role: Role,
|
||||||
password: String,
|
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)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
pub struct Signin {
|
pub struct Signin {
|
||||||
username: String,
|
username: String,
|
||||||
@ -32,11 +43,12 @@ pub async fn signup(
|
|||||||
|
|
||||||
let result = sqlx::query!(
|
let result = sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO users (username, password)
|
INSERT INTO users (username, role, password)
|
||||||
VALUES ( $1, $2 )
|
VALUES ( $1, $2, $3 )
|
||||||
RETURNING id;
|
RETURNING id;
|
||||||
"#,
|
"#,
|
||||||
signup.username,
|
signup.username,
|
||||||
|
signup.role as Role,
|
||||||
pass_hash.as_bytes(),
|
pass_hash.as_bytes(),
|
||||||
)
|
)
|
||||||
.fetch_one(&app_state.db_pool)
|
.fetch_one(&app_state.db_pool)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user