aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--planetwars-server/src/routes/bots.rs12
-rw-r--r--web/pw-server/src/routes/bots/new.svelte98
-rw-r--r--web/pw-server/src/routes/matches/new.svelte1
-rw-r--r--web/pw-server/src/routes/users/[user_name].svelte33
4 files changed, 140 insertions, 4 deletions
diff --git a/planetwars-server/src/routes/bots.rs b/planetwars-server/src/routes/bots.rs
index 8de479f..f2bf202 100644
--- a/planetwars-server/src/routes/bots.rs
+++ b/planetwars-server/src/routes/bots.rs
@@ -134,17 +134,25 @@ pub struct BotParams {
name: String,
}
+// TODO: can we unify this with save_bot?
pub async fn create_bot(
conn: DatabaseConnection,
user: User,
params: Json<BotParams>,
-) -> (StatusCode, Json<Bot>) {
+) -> Result<(StatusCode, Json<Bot>), SaveBotError> {
+ validate_bot_name(&params.name)?;
+ let existing_bot = bots::find_bot_by_name(&params.name, &conn)
+ .optional()
+ .expect("could not run query");
+ if existing_bot.is_some() {
+ return Err(SaveBotError::BotNameTaken);
+ }
let bot_params = bots::NewBot {
owner_id: Some(user.id),
name: &params.name,
};
let bot = bots::create_bot(&bot_params, &conn).unwrap();
- (StatusCode::CREATED, Json(bot))
+ Ok((StatusCode::CREATED, Json(bot)))
}
// TODO: handle errors
diff --git a/web/pw-server/src/routes/bots/new.svelte b/web/pw-server/src/routes/bots/new.svelte
new file mode 100644
index 0000000..7cb7229
--- /dev/null
+++ b/web/pw-server/src/routes/bots/new.svelte
@@ -0,0 +1,98 @@
+<script lang="ts">
+ import { goto } from "$app/navigation";
+ import { get_session_token } from "$lib/auth";
+ import { currentUser } from "$lib/stores/current_user";
+ import { onMount } from "svelte";
+ let botName: string | undefined = undefined;
+ let saveErrors: string[] = [];
+
+ onMount(() => {
+ // ensure user is logged in
+ if (!$currentUser) {
+ goto("/login");
+ }
+ });
+
+ async function createBot() {
+ saveErrors = [];
+
+ let response = await fetch("/api/bots", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${get_session_token()}`,
+ },
+ body: JSON.stringify({
+ name: botName,
+ }),
+ });
+
+ let responseData = await response.json();
+ if (response.ok) {
+ let bot = responseData;
+ goto(`/bots/${bot["name"]}`);
+ } else {
+ const error = responseData["error"];
+ if (error["type"] === "validation_failed") {
+ saveErrors = error["validation_errors"];
+ } else if (error["type"] === "bot_name_taken") {
+ saveErrors = ["Bot name is already taken"];
+ } else {
+ // unexpected error
+ throw responseData;
+ }
+ }
+ }
+</script>
+
+<div class="container">
+ <div class="create-bot-form">
+ <h4>Create new bot</h4>
+ <input type="text" class="bot-name-input" placeholder="bot name" bind:value={botName} />
+ {#if saveErrors.length > 0}
+ <ul>
+ {#each saveErrors as errorText}
+ <li class="error-text">{errorText}</li>
+ {/each}
+ </ul>
+ {/if}
+ <button class="submit-button save-button" on:click={createBot}>Save</button>
+ </div>
+</div>
+
+<style lang="scss">
+ .container {
+ width: 400px;
+ max-width: 80%;
+ margin: 50px auto;
+ }
+
+ .create-bot-form h4 {
+ margin-bottom: 0.3em;
+ }
+
+ .error-text {
+ color: red;
+ }
+
+ .submit-button {
+ padding: 6px 16px;
+ border-radius: 4px;
+ border: 0;
+ font-size: 18pt;
+ display: block;
+ margin: 10px auto;
+ background-color: lightgreen;
+ cursor: pointer;
+ }
+
+ .bot-name-input {
+ width: 100%;
+ font-size: 16px;
+ padding: 8px 16px;
+ box-sizing: border-box;
+ margin: 10px 0;
+ border: 1px solid rgb(216, 219, 223);
+ border-radius: 3px;
+ }
+</style>
diff --git a/web/pw-server/src/routes/matches/new.svelte b/web/pw-server/src/routes/matches/new.svelte
index ebc0e15..35e792f 100644
--- a/web/pw-server/src/routes/matches/new.svelte
+++ b/web/pw-server/src/routes/matches/new.svelte
@@ -1,6 +1,5 @@
<script lang="ts" context="module">
import { get_session_token } from "$lib/auth";
- import { mount_component } from "svelte/internal";
export async function load({ page }) {
const token = get_session_token();
diff --git a/web/pw-server/src/routes/users/[user_name].svelte b/web/pw-server/src/routes/users/[user_name].svelte
index a1801f4..b6bd34e 100644
--- a/web/pw-server/src/routes/users/[user_name].svelte
+++ b/web/pw-server/src/routes/users/[user_name].svelte
@@ -17,6 +17,8 @@
</script>
<script lang="ts">
+ import { currentUser } from "$lib/stores/current_user";
+
export let userName: string;
export let bots: object[];
</script>
@@ -25,7 +27,13 @@
<div class="header">
<h1 class="user-name">{userName}</h1>
</div>
- <h2>Bots</h2>
+
+ <div class="bot-list-header">
+ <h2 class="bot-list-header-title">Bots</h2>
+ {#if $currentUser && $currentUser.username == userName}
+ <a href="/bots/new" class="btn-new-bot"> New bot </a>
+ {/if}
+ </div>
<ul class="bot-list">
{#each bots as bot}
<li class="bot">
@@ -51,6 +59,29 @@
margin-bottom: 0.5em;
}
+ .bot-list-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-end;
+ }
+
+ .bot-list-header-title {
+ margin-bottom: 0px;
+ }
+
+ .btn-new-bot {
+ padding: 8px 12px;
+ border-radius: 4px;
+ border: 0;
+ display: block;
+ color: white;
+ background-color: rgb(40, 167, 69);
+ font-weight: 500;
+ text-decoration: none;
+ font-size: 11pt;
+ cursor: pointer;
+ }
+
.bot-list {
list-style: none;
padding: 0;