mirror of https://github.com/dpc/tagwiki
Progress
This commit is contained in:
parent
94d3101cd1
commit
1f899adee4
|
@ -424,6 +424,12 @@ version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
|
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "horrorshow"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87ce7e0a1bc8e4489896abc94e5664e811a502a151bebfe113b3214fa181d3fb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -1194,6 +1200,7 @@ dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"hex",
|
"hex",
|
||||||
|
"horrorshow",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log 0.4.8",
|
"log 0.4.8",
|
||||||
"pulldown-cmark",
|
"pulldown-cmark",
|
||||||
|
|
|
@ -32,3 +32,4 @@ walkdir = "*"
|
||||||
async-trait = "0.1.30"
|
async-trait = "0.1.30"
|
||||||
serde = "*"
|
serde = "*"
|
||||||
serde_derive = "*"
|
serde_derive = "*"
|
||||||
|
horrorshow = "*"
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/* http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0 | 20110126
|
||||||
|
License: none (public domain)
|
||||||
|
*/
|
||||||
|
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
* {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #baa4a4;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TOOD: make the whole form exactly fit the screen (including the buttons) */
|
||||||
|
textarea {
|
||||||
|
height: 90vh;
|
||||||
|
width: 100%;
|
||||||
|
}
|
46
src/index.rs
46
src/index.rs
|
@ -11,12 +11,19 @@ pub struct Index<T> {
|
||||||
// tag -> page_ids
|
// tag -> page_ids
|
||||||
page_ids_by_tag: HashMap<String, HashSet<Id>>,
|
page_ids_by_tag: HashMap<String, HashSet<Id>>,
|
||||||
tags_by_page_id: HashMap<Id, Vec<Tag>>,
|
tags_by_page_id: HashMap<Id, Vec<Tag>>,
|
||||||
|
title_by_page_id: HashMap<Id, String>,
|
||||||
store: T,
|
store: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct PageInfo {
|
||||||
|
pub id: Id,
|
||||||
|
pub title: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct FindResults {
|
pub struct FindResults {
|
||||||
pub matching_pages: Vec<Id>,
|
pub matching_pages: Vec<PageInfo>,
|
||||||
pub matching_tags: Vec<page::Tag>,
|
pub matching_tags: Vec<page::Tag>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +41,7 @@ where
|
||||||
let mut s = Index {
|
let mut s = Index {
|
||||||
page_ids_by_tag: Default::default(),
|
page_ids_by_tag: Default::default(),
|
||||||
tags_by_page_id: Default::default(),
|
tags_by_page_id: Default::default(),
|
||||||
|
title_by_page_id: Default::default(),
|
||||||
store,
|
store,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,9 +65,22 @@ where
|
||||||
|
|
||||||
impl<T> Index<T> {
|
impl<T> Index<T> {
|
||||||
pub fn find(&self, tags: &[TagRef]) -> FindResults {
|
pub fn find(&self, tags: &[TagRef]) -> FindResults {
|
||||||
let mut matching_pages: Vec<String> = vec![];
|
let mut matching_pages: Vec<PageInfo> = vec![];
|
||||||
let mut matching_tags: Vec<String> = vec![];
|
let mut matching_tags: Vec<String> = vec![];
|
||||||
let mut already_tried_tags = HashSet::new();
|
let mut already_tried_tags = HashSet::new();
|
||||||
|
|
||||||
|
if tags.is_empty() {
|
||||||
|
matching_pages = self
|
||||||
|
.tags_by_page_id
|
||||||
|
.keys()
|
||||||
|
.cloned()
|
||||||
|
.map(|id| PageInfo {
|
||||||
|
id: id.clone(),
|
||||||
|
title: self.title_by_page_id[&id].clone(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
for tag in tags {
|
for tag in tags {
|
||||||
if already_tried_tags.contains(tag) {
|
if already_tried_tags.contains(tag) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -67,7 +88,13 @@ impl<T> Index<T> {
|
||||||
already_tried_tags.insert(tag);
|
already_tried_tags.insert(tag);
|
||||||
if matching_tags.is_empty() {
|
if matching_tags.is_empty() {
|
||||||
if let Some(ids) = &self.page_ids_by_tag.get(*tag) {
|
if let Some(ids) = &self.page_ids_by_tag.get(*tag) {
|
||||||
matching_pages = ids.iter().map(|id| id.to_owned()).collect();
|
matching_pages = ids
|
||||||
|
.iter()
|
||||||
|
.map(|id| PageInfo {
|
||||||
|
id: id.to_owned(),
|
||||||
|
title: self.title_by_page_id[id].clone(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
matching_tags.push(tag.to_string())
|
matching_tags.push(tag.to_string())
|
||||||
} else {
|
} else {
|
||||||
return FindResults::empty();
|
return FindResults::empty();
|
||||||
|
@ -76,7 +103,7 @@ impl<T> Index<T> {
|
||||||
if let Some(ids) = self.page_ids_by_tag.get(*tag) {
|
if let Some(ids) = self.page_ids_by_tag.get(*tag) {
|
||||||
let new_matching_pages: Vec<_> = matching_pages
|
let new_matching_pages: Vec<_> = matching_pages
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|id| ids.contains(id.as_str()))
|
.filter(|info| ids.contains(info.id.as_str()))
|
||||||
.map(|id| id.to_owned())
|
.map(|id| id.to_owned())
|
||||||
.collect();
|
.collect();
|
||||||
if new_matching_pages.is_empty() {
|
if new_matching_pages.is_empty() {
|
||||||
|
@ -107,9 +134,11 @@ impl<T> Index<T> {
|
||||||
self.page_ids_by_tag
|
self.page_ids_by_tag
|
||||||
.entry(tag.clone())
|
.entry(tag.clone())
|
||||||
.or_default()
|
.or_default()
|
||||||
.insert(page.headers.id.clone());
|
.insert(page.id().to_owned());
|
||||||
self.tags_by_page_id
|
self.tags_by_page_id
|
||||||
.insert(page.headers.id.clone(), page.tags.clone());
|
.insert(page.id().to_owned(), page.tags.clone());
|
||||||
|
self.title_by_page_id
|
||||||
|
.insert(page.id().to_owned(), page.title.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +154,7 @@ impl<T> Index<T> {
|
||||||
.map(|set| set.remove(&id));
|
.map(|set| set.remove(&id));
|
||||||
}
|
}
|
||||||
self.tags_by_page_id.remove(&id);
|
self.tags_by_page_id.remove(&id);
|
||||||
|
self.title_by_page_id.remove(&id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,8 +170,8 @@ where
|
||||||
async fn put(&mut self, page: &page::Parsed) -> Result<()> {
|
async fn put(&mut self, page: &page::Parsed) -> Result<()> {
|
||||||
self.store.put(page).await?;
|
self.store.put(page).await?;
|
||||||
|
|
||||||
if let Some(_tags) = self.tags_by_page_id.get(&page.headers.id) {
|
if let Some(_tags) = self.tags_by_page_id.get(page.id()) {
|
||||||
self.clean_data_for_page(page.headers.id.clone());
|
self.clean_data_for_page(page.id().to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.add_data_for_page(page);
|
self.add_data_for_page(page);
|
||||||
|
|
187
src/main.rs
187
src/main.rs
|
@ -1,6 +1,6 @@
|
||||||
//! tagwiki
|
//! tagwiki
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{bail, Result};
|
||||||
use log::info;
|
use log::info;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
@ -20,6 +20,10 @@ mod index;
|
||||||
/// Utils
|
/// Utils
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
use horrorshow::helper::doctype;
|
||||||
|
use horrorshow::owned_html;
|
||||||
|
use horrorshow::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct RejectAnyhow(anyhow::Error);
|
struct RejectAnyhow(anyhow::Error);
|
||||||
|
|
||||||
|
@ -44,7 +48,7 @@ fn warp_temporary_redirect(location: &str) -> warp::http::Response<&'static str>
|
||||||
.expect("correct redirect")
|
.expect("correct redirect")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn warp_temporary_redirect_after_post(location: &str) -> warp::http::Response<&'static str> {
|
fn warp_temporary_redirect_to_get_method(location: &str) -> warp::http::Response<&'static str> {
|
||||||
warp::http::Response::builder()
|
warp::http::Response::builder()
|
||||||
.status(303)
|
.status(303)
|
||||||
.header(warp::http::header::LOCATION, location)
|
.header(warp::http::header::LOCATION, location)
|
||||||
|
@ -57,20 +61,73 @@ fn get_rid_of_windows_newlines(s: String) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct GetPrompt {
|
struct GetParams {
|
||||||
edit: Option<bool>,
|
edit: Option<bool>,
|
||||||
|
id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct PostForm {
|
struct PostForm {
|
||||||
body: String,
|
body: String,
|
||||||
|
id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn html_for_editing_page(page: &page::Parsed) -> String {
|
fn render_html_page(page: impl RenderOnce) -> impl RenderOnce {
|
||||||
format!(
|
owned_html! {
|
||||||
"<form action='.' method='POST'><textarea name='body'>{}</textarea><br/><input type=submit></form>",
|
: doctype::HTML;
|
||||||
page.source_body
|
head {
|
||||||
)
|
link(rel="stylesheet", media="all", href="/_style.css");
|
||||||
|
}
|
||||||
|
body : page;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_page_editing_view(page: &page::Parsed) -> impl RenderOnce {
|
||||||
|
let body = page.source_body.clone();
|
||||||
|
let id = page.id().to_owned();
|
||||||
|
owned_html! {
|
||||||
|
form(action=".", method="post") {
|
||||||
|
input(type="submit", value="Save");
|
||||||
|
input(type="hidden", name="id", value=id);
|
||||||
|
textarea(name="body") {
|
||||||
|
: body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_page_view(page: &page::Parsed) -> impl RenderOnce {
|
||||||
|
let page_html = page.html.clone();
|
||||||
|
let id = page.id().to_owned();
|
||||||
|
owned_html! {
|
||||||
|
form(action=".", method="get") {
|
||||||
|
input(type="hidden", name="edit", value="true");
|
||||||
|
input(type="hidden", name="id", value=id);
|
||||||
|
button(type="submit"){
|
||||||
|
: "Edit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: Raw(page_html)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_post_list(posts: impl Iterator<Item = index::PageInfo> + 'static) -> impl RenderOnce {
|
||||||
|
owned_html! {
|
||||||
|
ul {
|
||||||
|
@ for post in posts {
|
||||||
|
li {
|
||||||
|
a(href=format!("?id={}", post.id)) : post.title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn warp_reply_from_render(render: impl RenderOnce) -> Box<dyn warp::Reply> {
|
||||||
|
Box::new(warp::reply::html(
|
||||||
|
render.into_string().expect("rendering without errors"),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_to_tags(path: &FullPath) -> Vec<&str> {
|
fn path_to_tags(path: &FullPath) -> Vec<&str> {
|
||||||
|
@ -81,19 +138,61 @@ fn path_to_tags(path: &FullPath) -> Vec<&str> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_style_css() -> std::result::Result<warp::http::Response<String>, warp::Rejection> {
|
||||||
|
Ok(warp::http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.header(warp::http::header::CONTENT_TYPE, "text/css")
|
||||||
|
.body(
|
||||||
|
include_str!("../resources/reset.css").to_string()
|
||||||
|
+ include_str!("../resources/style.css"),
|
||||||
|
)
|
||||||
|
.expect("correct redirect"))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_post_wrapped(
|
||||||
|
state: Arc<State>,
|
||||||
|
path: FullPath,
|
||||||
|
form: PostForm,
|
||||||
|
) -> Result<Box<dyn warp::Reply>, warp::Rejection> {
|
||||||
|
handle_post(state, path, form)
|
||||||
|
.await
|
||||||
|
.map_err(|e| warp::reject::custom(RejectAnyhow(e)))
|
||||||
|
}
|
||||||
|
|
||||||
async fn handle_post(
|
async fn handle_post(
|
||||||
state: Arc<State>,
|
state: Arc<State>,
|
||||||
path: FullPath,
|
path: FullPath,
|
||||||
form: PostForm,
|
form: PostForm,
|
||||||
) -> std::result::Result<Box<dyn warp::Reply>, warp::Rejection> {
|
) -> Result<Box<dyn warp::Reply>> {
|
||||||
let tags = path_to_tags(&path);
|
let tags = path_to_tags(&path);
|
||||||
let mut write = state.page_store.write().await;
|
let mut write = state.page_store.write().await;
|
||||||
let results = write.find(tags.as_slice());
|
|
||||||
|
|
||||||
|
let post_id = if let Some(id) = form.id {
|
||||||
|
id
|
||||||
|
} else {
|
||||||
|
let results = write.find(tags.as_slice());
|
||||||
|
match results.matching_pages.len() {
|
||||||
|
1 => results.matching_pages[0].id.clone(),
|
||||||
|
0 => bail!("Page not found"),
|
||||||
|
_ => return Ok(Box::new(warp_temporary_redirect_to_get_method(".".into()))),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let page = write.get(post_id.clone()).await?;
|
||||||
|
|
||||||
|
let page = page.with_new_source_body(&get_rid_of_windows_newlines(form.body));
|
||||||
|
|
||||||
|
write.put(&page).await?;
|
||||||
|
|
||||||
|
Ok(Box::new(warp_temporary_redirect_to_get_method(&format!(
|
||||||
|
"?id={}",
|
||||||
|
post_id
|
||||||
|
))))
|
||||||
|
|
||||||
|
/*
|
||||||
match results.matching_pages.len() {
|
match results.matching_pages.len() {
|
||||||
1 => {
|
1 => {
|
||||||
let page = write
|
let page = write
|
||||||
.get(results.matching_pages[0].clone())
|
.get(results.matching_pages[0].id.clone())
|
||||||
.await
|
.await
|
||||||
.map_err(|e| warp::reject::custom(RejectAnyhow(e)))?;
|
.map_err(|e| warp::reject::custom(RejectAnyhow(e)))?;
|
||||||
|
|
||||||
|
@ -110,16 +209,43 @@ async fn handle_post(
|
||||||
// TODO: ERROR
|
// TODO: ERROR
|
||||||
Ok(Box::new(format!("Results: {:?}", results)))
|
Ok(Box::new(format!("Results: {:?}", results)))
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// I wish this could be generic
|
||||||
|
async fn handle_get_wrapped(
|
||||||
|
state: Arc<State>,
|
||||||
|
path: FullPath,
|
||||||
|
query: GetParams,
|
||||||
|
) -> std::result::Result<Box<dyn warp::Reply>, warp::Rejection> {
|
||||||
|
handle_get(state, path, query)
|
||||||
|
.await
|
||||||
|
.map_err(|e| warp::reject::custom(RejectAnyhow(e)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_page(page: &page::Parsed, edit: bool) -> Box<dyn RenderBox> {
|
||||||
|
if edit {
|
||||||
|
Box::new(render_page_editing_view(page)) as Box<dyn RenderBox>
|
||||||
|
} else {
|
||||||
|
Box::new(render_page_view(page)) as Box<dyn RenderBox>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_get(
|
async fn handle_get(
|
||||||
state: Arc<State>,
|
state: Arc<State>,
|
||||||
path: FullPath,
|
path: FullPath,
|
||||||
query: GetPrompt,
|
query: GetParams,
|
||||||
) -> std::result::Result<Box<dyn warp::Reply>, warp::Rejection> {
|
) -> Result<Box<dyn warp::Reply>> {
|
||||||
let tags = path_to_tags(&path);
|
let tags = path_to_tags(&path);
|
||||||
let read = state.page_store.read().await;
|
let read = state.page_store.read().await;
|
||||||
|
|
||||||
|
if let Some(q_id) = query.id {
|
||||||
|
let page = read.get(q_id).await?;
|
||||||
|
return Ok(warp_reply_from_render(render_html_page(render_page(
|
||||||
|
&page,
|
||||||
|
query.edit.is_some(),
|
||||||
|
))));
|
||||||
|
}
|
||||||
let results = read.find(tags.as_slice());
|
let results = read.find(tags.as_slice());
|
||||||
if results.matching_tags != tags {
|
if results.matching_tags != tags {
|
||||||
return Ok(Box::new(warp_temporary_redirect(
|
return Ok(Box::new(warp_temporary_redirect(
|
||||||
|
@ -127,18 +253,15 @@ async fn handle_get(
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
if results.matching_pages.len() == 1 {
|
if results.matching_pages.len() == 1 {
|
||||||
let page = read
|
let page = read.get(results.matching_pages[0].id.clone()).await?;
|
||||||
.get(results.matching_pages[0].clone())
|
Ok(warp_reply_from_render(render_html_page(render_page(
|
||||||
.await
|
&page,
|
||||||
.map_err(|e| warp::reject::custom(RejectAnyhow(e)))?;
|
query.edit.is_some(),
|
||||||
Ok(Box::new(warp::reply::html(if query.edit.is_none() {
|
))))
|
||||||
page.html
|
|
||||||
+ "<form action='.' method='get'><input type='hidden' name='edit' value='true' /><button type='submit'/>Edit Page</form>"
|
|
||||||
} else {
|
|
||||||
html_for_editing_page(&page)
|
|
||||||
})))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(Box::new(format!("Results: {:?}", results)))
|
Ok(warp_reply_from_render(render_html_page(render_post_list(
|
||||||
|
results.matching_pages.into_iter(),
|
||||||
|
))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,17 +274,17 @@ async fn start(opts: &cli::Opts) -> Result<()> {
|
||||||
)),
|
)),
|
||||||
});
|
});
|
||||||
let handler = warp::any()
|
let handler = warp::any()
|
||||||
.and(with_state(state.clone()))
|
.and(warp::path!("_style.css").and_then(handle_style_css))
|
||||||
.and(warp::path::full())
|
.or(with_state(state.clone())
|
||||||
.and(warp::query::<GetPrompt>())
|
.and(warp::path::full())
|
||||||
.and(warp::get())
|
.and(warp::query::<GetParams>())
|
||||||
.and_then(handle_get)
|
.and(warp::get())
|
||||||
.or(warp::any()
|
.and_then(handle_get_wrapped))
|
||||||
.and(with_state(state))
|
.or(with_state(state)
|
||||||
.and(warp::path::full())
|
.and(warp::path::full())
|
||||||
.and(warp::post())
|
.and(warp::post())
|
||||||
.and(warp::filters::body::form())
|
.and(warp::filters::body::form())
|
||||||
.and_then(handle_post));
|
.and_then(handle_post_wrapped));
|
||||||
info!("Listening on port {}", opts.port);
|
info!("Listening on port {}", opts.port);
|
||||||
let _serve = warp::serve(handler).run(([127, 0, 0, 1], opts.port)).await;
|
let _serve = warp::serve(handler).run(([127, 0, 0, 1], opts.port)).await;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ use digest::Digest;
|
||||||
pub type Id = String;
|
pub type Id = String;
|
||||||
pub type Tag = String;
|
pub type Tag = String;
|
||||||
pub type TagRef<'a> = &'a str;
|
pub type TagRef<'a> = &'a str;
|
||||||
|
pub type IdRef<'a> = &'a str;
|
||||||
|
|
||||||
const TAGWIKI_PAGE_ID_KEY: &str = "tagwiki-page-id";
|
const TAGWIKI_PAGE_ID_KEY: &str = "tagwiki-page-id";
|
||||||
|
|
||||||
|
@ -113,6 +114,10 @@ fn parse_tags(body: &str) -> Vec<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parsed {
|
impl Parsed {
|
||||||
|
pub fn id(&self) -> IdRef {
|
||||||
|
self.headers.id.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
fn from_full_source(source: Source) -> Parsed {
|
fn from_full_source(source: Source) -> Parsed {
|
||||||
let (headers, body) = split_headers_and_body(&source);
|
let (headers, body) = split_headers_and_body(&source);
|
||||||
let headers = Headers::parse(headers, &source);
|
let headers = Headers::parse(headers, &source);
|
||||||
|
@ -186,6 +191,6 @@ tagwiki-id: 123
|
||||||
));
|
));
|
||||||
|
|
||||||
println!("{:#?}", page);
|
println!("{:#?}", page);
|
||||||
assert_eq!(page.headers.id, "xyz");
|
assert_eq!(page.id(), "xyz");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue