Conclude example

This commit is contained in:
finga 2021-04-14 23:02:09 +02:00
parent 13aacc3b6b
commit 78ef2762e7
21 changed files with 1809 additions and 6 deletions

View file

@ -523,11 +523,6 @@
** Lets create a small web app
A chat box where everybody can post.
*** Caution
HTML is not disabled!
** Let us start
#+BEGIN_CENTER
#+LaTeX:\includegraphics[width = 0.7\textwidth]{img/challenge-accepted-lets-code-it.jpg}
#+END_CENTER

View file

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.14.1"
@ -79,6 +81,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
[[package]]
name = "atty"
version = "0.2.14"
@ -1179,6 +1187,7 @@ dependencies = [
name = "simple_text_board"
version = "0.1.0"
dependencies = [
"anyhow",
"chrono",
"diesel",
"log 0.4.13",

View file

@ -10,6 +10,7 @@ chrono = { version = "0.4", features = ["serde"] }
diesel = { version = "1.4", features = ["sqlite", "chrono"] }
log = "0.4"
serde = { version = "1.0", features = ["derive"] }
anyhow = "1.0"
[dependencies.rocket_contrib]
version = "0.4"

View file

@ -15,7 +15,7 @@ pub struct NewPost<'a> {
}
impl NewPost<'_> {
pub fn insert(&self, conn: &diesel::SqliteConnection) -> QueryResult<usize> {
pub fn insert(&self, conn: &SqliteConnection) -> QueryResult<usize> {
diesel::insert_into(table_posts).values(self).execute(conn)
}
}

View file

@ -0,0 +1 @@
finga@serenity.11826:1618395756

1
simpler_text_board/.env Normal file
View file

@ -0,0 +1 @@
DATABASE_URL=simpler_text_board.sqlite

1
simpler_text_board/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

1595
simpler_text_board/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,18 @@
[package]
name = "simpler_text_board"
version = "0.1.0"
authors = ["finga <finga@onders.org>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rocket = "0.4"
diesel = { version = "1.4", features = ["sqlite"] }
serde = { version = "1.0", features = ["derive"] }
anyhow = "1.0"
[dependencies.rocket_contrib]
version = "0.4"
default-features = false
features = ["diesel_sqlite_pool", "tera_templates"]

View file

@ -0,0 +1,8 @@
[development]
address = "0.0.0.0"
port = 8000
workers = 2
keep_alive = 5
[global.databases]
sqlite = { url = "simpler_text_board.sqlite" }

View file

@ -0,0 +1,5 @@
# For documentation on how to configure this file,
# see diesel.rs/guides/configuring-diesel-cli
[print_schema]
file = "src/schema.rs"

View file

View file

@ -0,0 +1 @@
DROP TABLE posts;

View file

@ -0,0 +1,7 @@
CREATE TABLE posts (
id INTEGER NOT NULL PRIMARY KEY,
author VARCHAR NOT NULL,
email VARCHAR NOT NULL,
title VARCHAR NOT NULL,
content VARCHAR NOT NULL
);

Binary file not shown.

View file

@ -0,0 +1,70 @@
#![feature(decl_macro)]
#[macro_use]
extern crate diesel;
use std::{collections::HashMap, net::SocketAddr};
use anyhow;
use diesel::SqliteConnection;
use rocket::{
get, post,
request::{FlashMessage, Form},
response::{Flash, Redirect},
routes, uri,
};
use rocket_contrib::{database, templates::Template};
use serde::Serialize;
mod models;
mod schema;
use models::{NewPost, Post};
#[database("sqlite")]
struct DbCon(SqliteConnection);
#[derive(Serialize)]
struct Posts {
posts: Vec<Post>,
}
#[get("/")]
fn index(conn: DbCon) -> anyhow::Result<Template> {
Ok(Template::render(
"index",
Posts {
posts: Post::get_all(&conn)?,
},
))
}
#[get("/create")]
fn create_form(flash: Option<FlashMessage>) -> Template {
let mut context = HashMap::new();
if let Some(ref msg) = flash {
context.insert("flash", msg.msg());
}
Template::render("create", &context)
}
#[post("/create", data = "<post>")]
fn create_post(conn: DbCon, post: Form<NewPost>) -> Result<Redirect, Flash<Redirect>> {
match post.insert(&conn) {
Ok(_) => Ok(Redirect::to(uri!(index))),
Err(e) => Err(Flash::error(
Redirect::to(uri!(create_form)),
"Could not create post.".to_string(),
)),
}
}
fn main() {
rocket::ignite()
.mount("/", routes![index, create_form, create_post])
.attach(DbCon::fairing())
.attach(Template::fairing())
.launch();
}

View file

@ -0,0 +1,34 @@
use crate::schema::posts::{self, dsl::posts as table_posts};
use diesel::{QueryResult, RunQueryDsl, SqliteConnection};
use rocket::FromForm;
use serde::Serialize;
#[derive(Queryable, Serialize)]
pub struct Post {
pub id: i32,
pub author: String,
pub email: String,
pub title: String,
pub content: String,
}
impl Post {
pub fn get_all(conn: &SqliteConnection) -> QueryResult<Vec<Post>> {
posts::table.load::<Post>(conn)
}
}
#[derive(Insertable, FromForm)]
#[table_name = "posts"]
pub struct NewPost {
pub author: String,
pub email: String,
pub title: String,
pub content: String,
}
impl NewPost {
pub fn insert(&self, conn: &SqliteConnection) -> QueryResult<usize> {
diesel::insert_into(table_posts).values(self).execute(conn)
}
}

View file

@ -0,0 +1,9 @@
table! {
posts (id) {
id -> Integer,
author -> Text,
email -> Text,
title -> Text,
content -> Text,
}
}

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>simpler text board</title>
</head>
<body>
<ul>
<li><a href="/">home</a></li>
<li><a href="/create">create post</a></li>
</ul>
{% block content %} {% endblock %}
</body>
</html>

View file

@ -0,0 +1,23 @@
{% extends "base" %}
{% block content %}
<h1> simpler text board</h1>
<h2>create a post</h2>
{% if flash %}<p>{{ flash }}</p>{% endif %}
<form action="/create" method="post" accept-charset="utf-8">
<label for="author">author name</label>
<input type="text" placeholder="author" name="author" required>
<label for="email">email</label>
<input type="text" placeholder="email" name="email">
<label for="title">title</label>
<input type="text" placeholder="title" name="title" required>
<label for="content">content</label>
<textarea type="text" placeholder="content" name="content" rows="8" cols="50" required>
</textarea>
<button type="submit">create</button>
</form>
{% endblock content %}

View file

@ -0,0 +1,10 @@
{% extends "base" %}
{% block content %}
<h1> simpler text board</h1>
<ul>
{% for post in posts %}
<li>{{ loop.index }} - {{ post.title }} - {{ post.author }}</li>
{% endfor %}
</ul>
{% endblock content %}