check joke refs to questions
This commit is contained in:
parent
538c55fb2a
commit
e3c384ea5a
@ -5,8 +5,9 @@ mod question;
|
|||||||
mod question_tag;
|
mod question_tag;
|
||||||
mod tag;
|
mod tag;
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, Query, State},
|
extract::{Path, Query, Request, State},
|
||||||
http::{StatusCode, Uri},
|
http::{header, StatusCode, Uri},
|
||||||
|
middleware::Next,
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
routing::{delete, get, post, put},
|
routing::{delete, get, post, put},
|
||||||
Form, Json, Router,
|
Form, Json, Router,
|
||||||
@ -57,6 +58,27 @@ fn db_string() -> String {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simple cors middleware to avoid pulling in tower just for this
|
||||||
|
async fn add_cors_headers(
|
||||||
|
req: Request,
|
||||||
|
next: Next,
|
||||||
|
) -> Result<impl IntoResponse, (StatusCode, String)> {
|
||||||
|
let mut response = next.run(req).await;
|
||||||
|
response.headers_mut().insert(
|
||||||
|
header::ACCESS_CONTROL_ALLOW_ORIGIN,
|
||||||
|
header::HeaderValue::from_static("*"),
|
||||||
|
);
|
||||||
|
response.headers_mut().insert(
|
||||||
|
header::ACCESS_CONTROL_ALLOW_METHODS,
|
||||||
|
header::HeaderValue::from_static("GET, POST, PUT, DELETE"),
|
||||||
|
);
|
||||||
|
response.headers_mut().insert(
|
||||||
|
header::ACCESS_CONTROL_ALLOW_HEADERS,
|
||||||
|
header::HeaderValue::from_static("Content-Type, Authorization"),
|
||||||
|
);
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let db_url: String = db_string();
|
let db_url: String = db_string();
|
||||||
@ -76,6 +98,7 @@ async fn main() {
|
|||||||
.nest("/api/v1", apis)
|
.nest("/api/v1", apis)
|
||||||
.route("/", get(serve_file))
|
.route("/", get(serve_file))
|
||||||
.route("/*path", get(serve_file))
|
.route("/*path", get(serve_file))
|
||||||
|
.layer(axum::middleware::from_fn(add_cors_headers))
|
||||||
.fallback(handler_404);
|
.fallback(handler_404);
|
||||||
|
|
||||||
axum::serve(listener, app).await.unwrap();
|
axum::serve(listener, app).await.unwrap();
|
||||||
|
@ -27,9 +27,9 @@ pub fn Finder(props: &FinderProps) -> Html {
|
|||||||
let props = props.clone();
|
let props = props.clone();
|
||||||
html! { <>
|
html! { <>
|
||||||
<div>
|
<div>
|
||||||
<input type="text" placeholder="joke id" oninput={change_key}/>
|
<input type="text" placeholder="question id" oninput={change_key}/>
|
||||||
<button onclick={move |_| props.on_find.emit((*key).clone())}>
|
<button onclick={move |_| props.on_find.emit((*key).clone())}>
|
||||||
{"Find this joke"}
|
{"Find this question"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</> }
|
</> }
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
mod finder;
|
mod finder;
|
||||||
mod joke;
|
mod question;
|
||||||
|
|
||||||
use finder::*;
|
use finder::*;
|
||||||
use joke::*;
|
use question::*;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
@ -13,21 +13,21 @@ extern crate wasm_bindgen_futures;
|
|||||||
use web_sys::HtmlTextAreaElement;
|
use web_sys::HtmlTextAreaElement;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub type JokeResult = Result<JokeStruct, gloo_net::Error>;
|
pub type QuestionResult = Result<QuestionStruct, gloo_net::Error>;
|
||||||
|
|
||||||
struct App {
|
struct App {
|
||||||
joke: JokeResult,
|
question: QuestionResult,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
GotJoke(JokeResult),
|
GotQuestion(QuestionResult),
|
||||||
GetJoke(Option<String>),
|
GetQuestion(Option<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
fn refresh_joke(ctx: &Context<Self>, key: Option<String>) {
|
fn refresh_question(ctx: &Context<Self>, key: Option<String>) {
|
||||||
let got_joke = JokeStruct::get_joke(key);
|
let got_question = QuestionStruct::get_question(key);
|
||||||
ctx.link().send_future(got_joke);
|
ctx.link().send_future(got_question);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,42 +36,42 @@ impl Component for App {
|
|||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(ctx: &Context<Self>) -> Self {
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
App::refresh_joke(ctx, None);
|
App::refresh_question(ctx, None);
|
||||||
let joke = Err(gloo_net::Error::GlooError("Loading Joke…".to_string()));
|
let question = Err(gloo_net::Error::GlooError("Loading Question…".to_string()));
|
||||||
Self { joke }
|
Self { question }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::GotJoke(joke) => {
|
Msg::GotQuestion(question) => {
|
||||||
self.joke = joke;
|
self.question = question;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Msg::GetJoke(key) => {
|
Msg::GetQuestion(key) => {
|
||||||
// log!(format!("GetJoke: {:?}", key));
|
// log!(format!("GetQuestion: {:?}", key));
|
||||||
App::refresh_joke(ctx, key);
|
App::refresh_question(ctx, key);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
let joke = &self.joke;
|
let question = &self.question;
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<h1>{ "Knock-Knock" }</h1>
|
<h1>{ "Question and Answer" }</h1>
|
||||||
if let Ok(ref joke) = joke {
|
if let Ok(ref question) = question {
|
||||||
<Joke joke={joke.clone()}/>
|
<Question question={question.clone()}/>
|
||||||
}
|
}
|
||||||
if let Err(ref error) = joke {
|
if let Err(ref error) = question {
|
||||||
<div>
|
<div>
|
||||||
<span class="error">{format!("Server Error: {error}")}</span>
|
<span class="error">{format!("Server Error: {error}")}</span>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div>
|
<div>
|
||||||
<button onclick={ctx.link().callback(|_| Msg::GetJoke(None))}>{"Tell me another!"}</button>
|
<button onclick={ctx.link().callback(|_| Msg::GetQuestion(None))}>{"Ask me another!"}</button>
|
||||||
</div>
|
</div>
|
||||||
<Finder on_find={ctx.link().callback(Msg::GetJoke)}/>
|
<Finder on_find={ctx.link().callback(Msg::GetQuestion)}/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
#[derive(Properties, Clone, PartialEq, serde::Deserialize)]
|
#[derive(Properties, Clone, PartialEq, serde::Deserialize)]
|
||||||
pub struct JokeStruct {
|
pub struct QuestionStruct {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub whos_there: String,
|
pub title: String,
|
||||||
pub answer_who: String,
|
pub content: String,
|
||||||
pub tags: Option<HashSet<String>>,
|
pub tags: Option<HashSet<String>>,
|
||||||
pub source: Option<String>,
|
pub source: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JokeStruct {
|
impl QuestionStruct {
|
||||||
pub async fn get_joke(key: Option<String>) -> Msg {
|
pub async fn get_question(key: Option<String>) -> Msg {
|
||||||
let request = match &key {
|
let request = match &key {
|
||||||
None => "http://localhost:3000/api/v1/joke".to_string(),
|
None => "http://localhost:3000/api/v1/question/2".to_string(),
|
||||||
Some(ref key) => format!("http://localhost:3000/api/v1/joke/{}", key,),
|
Some(ref key) => format!("http://localhost:3000/api/v1/question/{}", key,),
|
||||||
};
|
};
|
||||||
let response = http::Request::get(&request).send().await;
|
let response = http::Request::get(&request).send().await;
|
||||||
match response {
|
match response {
|
||||||
Err(e) => Msg::GotJoke(Err(e)),
|
Err(e) => Msg::GotQuestion(Err(e)),
|
||||||
Ok(data) => Msg::GotJoke(data.json().await),
|
Ok(data) => Msg::GotQuestion(data.json().await),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -28,27 +28,25 @@ pub fn format_tags(tags: &HashSet<String>) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Properties, Clone, PartialEq, serde::Deserialize)]
|
#[derive(Properties, Clone, PartialEq, serde::Deserialize)]
|
||||||
pub struct JokeProps {
|
pub struct QuestionProps {
|
||||||
pub joke: JokeStruct,
|
pub question: QuestionStruct,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[function_component(Joke)]
|
#[function_component(Question)]
|
||||||
pub fn joke(joke: &JokeProps) -> Html {
|
pub fn question(question: &QuestionProps) -> Html {
|
||||||
let joke = &joke.joke;
|
let question = &question.question;
|
||||||
html! { <>
|
html! { <>
|
||||||
<div class="joke">
|
<div class="question">
|
||||||
<span class="teller">{"Knock-Knock!"}</span><br/>
|
<span class="teller">{"Question time!"}</span><br/>
|
||||||
<span class="tellee">{"Who's there?"}</span><br/>
|
<span class="teller">{question.title.clone()}</span><br/>
|
||||||
<span class="teller">{joke.whos_there.clone()}</span><br/>
|
<span class="teller">{question.content.clone()}</span>
|
||||||
<span class="tellee">{format!("{} who?", &joke.whos_there)}</span><br/>
|
|
||||||
<span class="teller">{joke.answer_who.clone()}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="annotation">
|
<span class="annotation">
|
||||||
{format!("[id: {}", &joke.id)}
|
{format!("[id: {}", &question.id)}
|
||||||
if let Some(ref tags) = joke.tags {
|
if let Some(ref tags) = question.tags {
|
||||||
{format!("; tags: {}", &format_tags(tags))}
|
{format!("; tags: {}", &format_tags(tags))}
|
||||||
}
|
}
|
||||||
if let Some(ref source) = joke.source {
|
if let Some(ref source) = question.source {
|
||||||
{format!("; source: {}", source)}
|
{format!("; source: {}", source)}
|
||||||
}
|
}
|
||||||
{"]"}
|
{"]"}
|
||||||
|
Reference in New Issue
Block a user