Conclude example
This commit is contained in:
parent
13aacc3b6b
commit
78ef2762e7
21 changed files with 1809 additions and 6 deletions
|
@ -523,11 +523,6 @@
|
||||||
|
|
||||||
** Lets create a small web app
|
** Lets create a small web app
|
||||||
A chat box where everybody can post.
|
A chat box where everybody can post.
|
||||||
|
|
||||||
*** Caution
|
|
||||||
HTML is not disabled!
|
|
||||||
|
|
||||||
** Let us start
|
|
||||||
#+BEGIN_CENTER
|
#+BEGIN_CENTER
|
||||||
#+LaTeX:\includegraphics[width = 0.7\textwidth]{img/challenge-accepted-lets-code-it.jpg}
|
#+LaTeX:\includegraphics[width = 0.7\textwidth]{img/challenge-accepted-lets-code-it.jpg}
|
||||||
#+END_CENTER
|
#+END_CENTER
|
||||||
|
|
9
simple_text_board/Cargo.lock
generated
9
simple_text_board/Cargo.lock
generated
|
@ -1,5 +1,7 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
version = "0.14.1"
|
version = "0.14.1"
|
||||||
|
@ -79,6 +81,12 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
@ -1179,6 +1187,7 @@ dependencies = [
|
||||||
name = "simple_text_board"
|
name = "simple_text_board"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
"diesel",
|
"diesel",
|
||||||
"log 0.4.13",
|
"log 0.4.13",
|
||||||
|
|
|
@ -10,6 +10,7 @@ chrono = { version = "0.4", features = ["serde"] }
|
||||||
diesel = { version = "1.4", features = ["sqlite", "chrono"] }
|
diesel = { version = "1.4", features = ["sqlite", "chrono"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
anyhow = "1.0"
|
||||||
|
|
||||||
[dependencies.rocket_contrib]
|
[dependencies.rocket_contrib]
|
||||||
version = "0.4"
|
version = "0.4"
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub struct NewPost<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NewPost<'_> {
|
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)
|
diesel::insert_into(table_posts).values(self).execute(conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1
simpler_text_board/.#Cargo.toml
Symbolic link
1
simpler_text_board/.#Cargo.toml
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
finga@serenity.11826:1618395756
|
1
simpler_text_board/.env
Normal file
1
simpler_text_board/.env
Normal file
|
@ -0,0 +1 @@
|
||||||
|
DATABASE_URL=simpler_text_board.sqlite
|
1
simpler_text_board/.gitignore
vendored
Normal file
1
simpler_text_board/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
1595
simpler_text_board/Cargo.lock
generated
Normal file
1595
simpler_text_board/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
18
simpler_text_board/Cargo.toml
Normal file
18
simpler_text_board/Cargo.toml
Normal 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"]
|
8
simpler_text_board/Rocket.toml
Normal file
8
simpler_text_board/Rocket.toml
Normal 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" }
|
5
simpler_text_board/diesel.toml
Normal file
5
simpler_text_board/diesel.toml
Normal 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"
|
0
simpler_text_board/migrations/.gitkeep
Normal file
0
simpler_text_board/migrations/.gitkeep
Normal file
|
@ -0,0 +1 @@
|
||||||
|
DROP TABLE posts;
|
|
@ -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
|
||||||
|
);
|
BIN
simpler_text_board/simpler_text_board.sqlite
Normal file
BIN
simpler_text_board/simpler_text_board.sqlite
Normal file
Binary file not shown.
70
simpler_text_board/src/main.rs
Normal file
70
simpler_text_board/src/main.rs
Normal 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();
|
||||||
|
}
|
34
simpler_text_board/src/models.rs
Normal file
34
simpler_text_board/src/models.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
9
simpler_text_board/src/schema.rs
Normal file
9
simpler_text_board/src/schema.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
table! {
|
||||||
|
posts (id) {
|
||||||
|
id -> Integer,
|
||||||
|
author -> Text,
|
||||||
|
email -> Text,
|
||||||
|
title -> Text,
|
||||||
|
content -> Text,
|
||||||
|
}
|
||||||
|
}
|
15
simpler_text_board/templates/base.html.tera
Normal file
15
simpler_text_board/templates/base.html.tera
Normal 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>
|
23
simpler_text_board/templates/create.html.tera
Normal file
23
simpler_text_board/templates/create.html.tera
Normal 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 %}
|
10
simpler_text_board/templates/index.html.tera
Normal file
10
simpler_text_board/templates/index.html.tera
Normal 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 %}
|
Loading…
Reference in a new issue