DEVELOPMENT ENVIRONMENT

~liljamo/deck-builder

15a0cdfe722e1cb5a06eef2bfee7fa69de4dca66 — Jonni Liljamo 1 year, 9 months ago 5a980b1
feat(api): stubs for most game endpoints, complete create
A api/src/actions/game/all_forming.rs => api/src/actions/game/all_forming.rs +14 -0
@@ 0,0 1,14 @@
/*
 * This file is part of laurelin/api
 * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
 *
 * Licensed under GPL-3.0-only.
 * See LICENSE for licensing information.
 */

use diesel::PgConnection;
use laurelin_shared::error::api::APIError;

pub(crate) fn all_forming(conn: &mut PgConnection) -> Result<(), APIError> {
    Err(APIError::Undefined)
}

A api/src/actions/game/create.rs => api/src/actions/game/create.rs +53 -0
@@ 0,0 1,53 @@
/*
 * This file is part of laurelin/api
 * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
 *
 * Licensed under GPL-3.0-only.
 * See LICENSE for licensing information.
 */

use diesel::{ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl};
use laurelin_shared::error::api::APIError;
use uuid::Uuid;

use crate::{
    models::{Game, GameData, InsertableGame, InsertableGameData},
    schema::{gamedata, games},
};

pub(crate) fn create(conn: &mut PgConnection, user_id: &str) -> Result<Game, APIError> {
    let new_gamedata = InsertableGameData {
        turn: 0,
        host_hand: None,
        host_deck: None,
        guest_hand: None,
        guest_deck: None,
    };

    let gamedata: GameData = match diesel::insert_into(gamedata::table)
        .values(&new_gamedata)
        .get_result::<GameData>(conn)
    {
        Err(_) => return Err(APIError::Undefined), // TODO: new error variant
        Ok(gamedata) => gamedata,
    };

    let new_game = InsertableGame {
        // TODO: handle unwrap
        host_id: Uuid::parse_str(user_id).unwrap(),
        guest_id: None,
        state: 0,
        ended_at: None,
        game_data_id: gamedata.id,
    };

    let game: Game = match diesel::insert_into(games::table)
        .values(&new_game)
        .get_result::<Game>(conn)
    {
        Err(_) => return Err(APIError::Undefined), // TODO: new error variant
        Ok(game) => game,
    };

    Ok(game)
}

A api/src/actions/game/info.rs => api/src/actions/game/info.rs +14 -0
@@ 0,0 1,14 @@
/*
 * This file is part of laurelin/api
 * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
 *
 * Licensed under GPL-3.0-only.
 * See LICENSE for licensing information.
 */

use diesel::PgConnection;
use laurelin_shared::error::api::APIError;

pub(crate) fn info(conn: &mut PgConnection) -> Result<(), APIError> {
    Err(APIError::Undefined)
}

A api/src/actions/game/join.rs => api/src/actions/game/join.rs +14 -0
@@ 0,0 1,14 @@
/*
 * This file is part of laurelin/api
 * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
 *
 * Licensed under GPL-3.0-only.
 * See LICENSE for licensing information.
 */

use diesel::PgConnection;
use laurelin_shared::error::api::APIError;

pub(crate) fn join(conn: &mut PgConnection) -> Result<(), APIError> {
    Err(APIError::Undefined)
}

A api/src/actions/game/mod.rs => api/src/actions/game/mod.rs +22 -0
@@ 0,0 1,22 @@
/*
 * This file is part of laurelin/api
 * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
 *
 * Licensed under GPL-3.0-only.
 * See LICENSE for licensing information.
 */

mod create;
pub(crate) use create::create;

mod all_forming;
pub(crate) use all_forming::all_forming;

mod my_games;
pub(crate) use my_games::my_games;

mod info;
pub(crate) use info::info;

mod join;
pub(crate) use join::join;

A api/src/actions/game/my_games.rs => api/src/actions/game/my_games.rs +14 -0
@@ 0,0 1,14 @@
/*
 * This file is part of laurelin/api
 * Copyright (C) 2023 Jonni Liljamo <jonni@liljamo.com>
 *
 * Licensed under GPL-3.0-only.
 * See LICENSE for licensing information.
 */

use diesel::PgConnection;
use laurelin_shared::error::api::APIError;

pub(crate) fn my_games(conn: &mut PgConnection) -> Result<(), APIError> {
    Err(APIError::Undefined)
}

M api/src/actions/mod.rs => api/src/actions/mod.rs +2 -0
@@ 7,3 7,5 @@
 */

pub(crate) mod user;

pub(crate) mod game;

M api/src/handlers/game/mod.rs => api/src/handlers/game/mod.rs +86 -0
@@ 5,3 5,89 @@
 * Licensed under GPL-3.0-only.
 * See LICENSE for licensing information.
 */

use actix_session::Session;
use actix_web::{get, post, web, HttpResponse, Responder};
use laurelin_shared::error::api::APIError;

use crate::{actions, session, PgPool};

#[post("/api/game")]
async fn create(session: Session, pool: web::Data<PgPool>) -> impl Responder {
    let session_validation = session::validate_session(&session);

    match session_validation {
        Err(err) => err,
        Ok(user_id) => {
            let game_create = web::block(move || {
                let mut conn = match pool.get() {
                    Err(_) => return Err(APIError::DatabasePoolGetFailed),
                    Ok(conn) => conn,
                };
                actions::game::create(&mut conn, &user_id)
            })
            .await;
            match game_create {
                Err(_err) => {
                    return HttpResponse::InternalServerError().json(APIError::Undefined);
                }
                Ok(game_res) => match game_res {
                    Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
                    Ok(game) => HttpResponse::Ok().json(game),
                },
            }
        }
    }
}

#[get("/api/game/{id}")]
async fn info(session: Session, pool: web::Data<PgPool>, id: web::Path<String>) -> impl Responder {
    let session_validation = session::validate_session(&session);

    match session_validation {
        Err(err) => err,
        Ok(user_id) => {
            //
            return HttpResponse::Ok().body("INFO");
        }
    }
}

#[post("/api/game/{id}/join")]
async fn join(session: Session, pool: web::Data<PgPool>, id: web::Path<String>) -> impl Responder {
    let session_validation = session::validate_session(&session);

    match session_validation {
        Err(err) => err,
        Ok(user_id) => {
            //
            return HttpResponse::Ok().body("JOIN");
        }
    }
}

#[get("/api/game/all_forming")]
async fn all_forming(session: Session, pool: web::Data<PgPool>) -> impl Responder {
    let session_validation = session::validate_session(&session);

    match session_validation {
        Err(err) => err,
        Ok(user_id) => {
            //
            return HttpResponse::Ok().body("ALL_FORMING");
        }
    }
}

#[get("/api/game/my_games")]
async fn my_games(session: Session, pool: web::Data<PgPool>) -> impl Responder {
    let session_validation = session::validate_session(&session);

    match session_validation {
        Err(err) => err,
        Ok(user_id) => {
            //
            return HttpResponse::Ok().body("MY_GAMES");
        }
    }
}

M api/src/main.rs => api/src/main.rs +8 -0
@@ 102,6 102,14 @@ async fn main() -> std::io::Result<()> {
            .service(handlers::user::create)
            .service(handlers::user::login)
            .service(handlers::user::logout)
            .service(handlers::game::create)
            .service(handlers::game::all_forming)
            .service(handlers::game::my_games)
            // NOTE: these have to be registered last!
            //       otherwise the positional {id} will catch
            //       things like "all_forming"
            .service(handlers::game::info)
            .service(handlers::game::join)
    })
    .bind(("0.0.0.0", 8080))?
    .run()