Skip to content

Commit

Permalink
Merge pull request #20 from gamemstr/1-campaign
Browse files Browse the repository at this point in the history
1 campaign
  • Loading branch information
jameswolff96 authored Feb 9, 2024
2 parents acb768a + eed7f09 commit 50cc0d8
Show file tree
Hide file tree
Showing 11 changed files with 276 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ license = "MIT OR Apache-2.0"
custom_derive = "0.1.7"
diesel = { version = "2.0.3", features = ["postgres", "postgres_backend", "r2d2", "serde_json"] }
dotenvy = "0.15.6"
gamemstr-common = { git = "https://github.com/gamemstr/gamemstr-common.git", rev="c5a5615d3e980d810d92d60d85905335f8269fb3"}
gamemstr-common = { git = "https://github.com/gamemstr/gamemstr-common.git", rev="7fd6025316fee770002ad789080c1c69464489e3"}
r2d2 = "0.8.10"
r2d2-diesel = "1.0.0"
rocket = { version = "0.5.0-rc.3", features = ["json"] }
Expand Down
2 changes: 1 addition & 1 deletion migrations/2024-02-08-142012_sessions/down.sql
Original file line number Diff line number Diff line change
@@ -1 +1 @@
-- This file should undo anything in `up.sql`
DROP TABLE sessions;
9 changes: 4 additions & 5 deletions migrations/2024-02-08-142012_sessions/up.sql
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
-- Your SQL goes here
CREATE TABLE sessions (
id VARCHAR PRIMARY KEY,
name VARCHAR NOT NULL,
description VARCHAR NOT NULL,
id VARCHAR PRIMARY KEY,
name VARCHAR NOT NULL,
campaign_id VARCHAR NOT NULL,
description VARCHAR NOT NULL,
notes JSONB NOT NULL,
plan JSONB NOT NULL,
plan JSONB NOT NULL,
recap JSONB NOT NULL
);
1 change: 1 addition & 0 deletions migrations/2024-02-08-220006_campaigns/down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE campaigns;
7 changes: 7 additions & 0 deletions migrations/2024-02-08-220006_campaigns/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREATE TABLE campaigns (
id VARCHAR PRIMARY KEY,
name VARCHAR NOT NULL,
description VARCHAR NOT NULL,
world_id VARCHAR NOT NULL,
players JSONB NOT NULL
);
85 changes: 83 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ fn rocket() -> _ {
.mount("/", routes![services::worlds::delete_world])
.mount("/", routes![services::worlds::list_worlds])
.mount("/", routes![services::worlds::update_world])
.mount("/", routes![services::worlds::campaigns::list_campaigns])
.mount("/", routes![services::worlds::campaigns::get_campaign])
.mount("/", routes![services::worlds::campaigns::delete_campaign])
.mount("/", routes![services::worlds::campaigns::create_campaign])
.mount("/", routes![services::worlds::campaigns::update_campaign])
.mount("/", routes![services::worlds::locations::list_locations])
.mount("/", routes![services::worlds::locations::get_location])
.mount("/", routes![services::worlds::locations::delete_location])
Expand Down Expand Up @@ -333,6 +338,70 @@ mod tests {
assert_eq!(response.status(), Status::Ok);
}

#[test]
pub fn test_campaigns_api() {
let client = Client::tracked(crate::rocket()).expect("valid rocket instance");
let world = gamemstr_common::world::World {
id: "2587598027928569265".to_string(),
name: "Test World".to_string(),
description: "Test Description".to_string(),
};
client
.post("/worlds/add")
.header(ContentType::JSON)
.body(serde_json::to_string(&world).unwrap())
.dispatch();
let response = client
.get("/worlds/2587598027928569265/campaigns")
.dispatch();
assert_eq!(response.status(), Status::Ok);
assert!(response.into_string().unwrap().contains("Campaigns"));
let campaign = gamemstr_common::world::campaign::Campaign {
id: "258759802792856926525".to_string(),
name: "Test Campaign".to_string(),
description: "Test Description".to_string(),
world_id: "2587598027928569265".to_string(),
players: None,
};
let response = client
.post("/worlds/2587598027928569265/campaigns/add")
.header(ContentType::JSON)
.body(serde_json::to_string(&campaign).unwrap())
.dispatch();
assert_eq!(response.status(), Status::Created);
let response = client
.get("/worlds/2587598027928569265/campaigns/258759802792856926525")
.dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(
response.into_string(),
Some(serde_json::to_string(&campaign).unwrap())
);
let new_campaign = gamemstr_common::world::campaign::Campaign {
name: "Updated Campaign".to_string(),
..campaign
};
let response = client
.post("/worlds/2587598027928569265/campaigns/258759802792856926525")
.header(ContentType::JSON)
.body(serde_json::to_string(&new_campaign).unwrap())
.dispatch();
assert_eq!(response.status(), Status::Accepted);
assert_eq!(
serde_json::from_str::<gamemstr_common::world::campaign::Campaign>(
&response.into_string().unwrap()
)
.unwrap()
.name,
"Updated Campaign"
);
let response = client
.delete("/worlds/2587598027928569265/campaigns/258759802792856926525")
.dispatch();
assert_eq!(response.status(), Status::Ok);
client.delete("/worlds/2587598027928569265").dispatch();
}

#[test]
pub fn test_locations_api() {
let client = Client::tracked(crate::rocket()).expect("valid rocket instance");
Expand Down Expand Up @@ -403,7 +472,6 @@ mod tests {
}

#[test]
#[should_panic]
pub fn test_sessions_api() {
let client = Client::tracked(crate::rocket()).expect("valid rocket instance");
let world = gamemstr_common::world::World {
Expand All @@ -416,7 +484,18 @@ mod tests {
.header(ContentType::JSON)
.body(serde_json::to_string(&world).unwrap())
.dispatch();
// TODO: Add campaign
let campaign = gamemstr_common::world::campaign::Campaign {
id: "2587598027928569265".to_string(),
name: "Test Campaign".to_string(),
description: "Test Description".to_string(),
world_id: "2587598027928569265".to_string(),
players: None,
};
client
.post("/worlds/2587598027928569265/campaigns/add")
.header(ContentType::JSON)
.body(serde_json::to_string(&campaign).unwrap())
.dispatch();
let response = client
.get("/worlds/2587598027928569265/campaigns/2587598027928569265/sessions")
.dispatch();
Expand Down Expand Up @@ -466,5 +545,7 @@ mod tests {
.delete("/worlds/2587598027928569265/campaigns/2587598027928569265/sessions/2587598027928569265")
.dispatch();
assert_eq!(response.status(), Status::Ok);
client.delete("/worlds/2587598027928569265/campaigns/2587598027928569265").dispatch();
client.delete("/worlds/2587598027928569265").dispatch();
}
}
42 changes: 41 additions & 1 deletion src/models/worlds/campaigns.rs
Original file line number Diff line number Diff line change
@@ -1 +1,41 @@
pub mod sessions;
use diesel::prelude::*;
use serde::{Deserialize, Serialize};

use crate::schema::campaigns;

pub mod sessions;

#[derive(Debug, Serialize, Deserialize, Queryable, Insertable, AsChangeset)]
#[diesel(table_name = campaigns)]
pub struct Campaign {
pub id: String,
pub name: String,
pub description: String,
pub world_id: String,
pub players: serde_json::Value,
}

impl crate::models::Model for Campaign {
type Entity = gamemstr_common::world::campaign::Campaign;

fn new(entity: Self::Entity) -> Self {
Self {
id: entity.id,
name: entity.name,
description: entity.description,
world_id: entity.world_id,
players: serde_json::to_value(entity.players).unwrap(),
}
}

fn to_entity(&self) -> Self::Entity {
Self::Entity {
id: self.id.clone(),
name: self.name.clone(),
description: self.description.clone(),
world_id: self.world_id.clone(),
players: serde_json::from_value(self.players.clone()).unwrap(),
}
}
}

13 changes: 12 additions & 1 deletion src/schema.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
// @generated automatically by Diesel CLI.

diesel::table! {
campaigns (id) {
id -> Varchar,
name -> Varchar,
description -> Varchar,
world_id -> Varchar,
players -> Jsonb,
}
}

diesel::table! {
creatures (id) {
id -> Varchar,
Expand Down Expand Up @@ -60,8 +70,8 @@ diesel::table! {
sessions (id) {
id -> Varchar,
name -> Varchar,
description -> Varchar,
campaign_id -> Varchar,
description -> Varchar,
notes -> Jsonb,
plan -> Jsonb,
recap -> Jsonb,
Expand Down Expand Up @@ -95,6 +105,7 @@ diesel::table! {
}

diesel::allow_tables_to_appear_in_same_query!(
campaigns,
creatures,
items,
locations,
Expand Down
103 changes: 102 additions & 1 deletion src/services/worlds/campaigns.rs
Original file line number Diff line number Diff line change
@@ -1 +1,102 @@
pub mod sessions;
use crate::{
models::{self, Model},
schema,
services::Result,
};
use diesel::prelude::*;
use gamemstr_common::world::campaign::Campaign;
use rocket::{
delete, get, post,
response::status::{Accepted, Created, NotFound},
serde::json::Json,
Either,
};
use rocket_dyn_templates::{context, Template};

pub mod sessions;

#[get("/worlds/<id>/campaigns")]
pub fn list_campaigns(id: String) -> Template {
let connection = &mut super::super::establish_connection_pg();
let campaigns = schema::campaigns::dsl::campaigns
.filter(schema::campaigns::dsl::world_id.eq(id))
.load::<models::worlds::campaigns::Campaign>(connection)
.expect("Error loading campaigns")
.iter()
.map(|campaign| campaign.to_entity())
.collect::<Vec<_>>();
Template::render(
"campaigns",
context! {
campaigns: &campaigns,
count: campaigns.len()
},
)
}

#[get("/worlds/<_world_id>/campaigns/<id>")]
pub fn get_campaign(_world_id: String, id: String) -> Result<Json<Campaign>> {
let connection = &mut super::super::establish_connection_pg();
let campaign = schema::campaigns::dsl::campaigns
.find(id)
.first::<models::worlds::campaigns::Campaign>(connection)
.expect("Error loading campaign")
.to_entity();
Ok(Json(campaign))
}

#[delete("/worlds/<_world_id>/campaigns/<id>")]
pub fn delete_campaign(_world_id: String, id: String) -> Result<Json<Campaign>> {
let connection = &mut super::super::establish_connection_pg();
let campaign = schema::campaigns::dsl::campaigns
.find(&id)
.first::<models::worlds::campaigns::Campaign>(connection)
.expect("Error loading campaign")
.to_entity();
diesel::delete(schema::campaigns::dsl::campaigns.find(&id))
.execute(connection)
.expect("Error deleting campaign");
Ok(Json(campaign))
}

#[post(
"/worlds/<_world_id>/campaigns/add",
rank = 1,
format = "json",
data = "<campaign>"
)]
pub fn create_campaign(
_world_id: String,
campaign: Json<Campaign>,
) -> Result<Created<Json<Campaign>>> {
let connection = &mut super::super::establish_connection_pg();
let new_campaign = models::worlds::campaigns::Campaign::new(campaign.clone().0);
diesel::insert_into(schema::campaigns::dsl::campaigns)
.values(&new_campaign)
.execute(connection)
.expect("Error creating campaign");
Ok(Created::new("/").body(campaign))
}

#[post(
"/worlds/<_world_id>/campaigns/<id>",
rank = 2,
format = "json",
data = "<campaign>"
)]
pub fn update_campaign(
_world_id: String,
id: String,
campaign: Json<Campaign>,
) -> Either<Result<Accepted<Json<Campaign>>>, Result<NotFound<String>>> {
let connection = &mut super::super::establish_connection_pg();
let result = diesel::update(schema::campaigns::dsl::campaigns.find(&id))
.set(&models::worlds::campaigns::Campaign::new(
campaign.clone().0,
))
.execute(connection);
match result {
Ok(_) => Either::Left(Ok(Accepted(Some(campaign)))),
Err(_) => Either::Right(Ok(NotFound(format!("Campaign not found with id {}", id)))),
}
}
23 changes: 23 additions & 0 deletions templates/campaigns.html.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Campaigns</title>
</head>
<body>
<section id = "hello">
<h1>Campaigns</h1>
{{#each campaigns as |campaign|}}
<ul>
<li>ID: {{campaign.id}}</li>
<li>Name: {{campaign.name}}</li>
<li>Description: {{campaign.description}}</li>
<li>World ID: {{campaign.world_id}}</li>
<li>Players: {{campaign.players}}</li>
</ul>
{{/each}}
</section>
</body>
</html>

0 comments on commit 50cc0d8

Please sign in to comment.