2018-08-07 02:58:07 +00:00
|
|
|
#[macro_use] extern crate rocket;
|
2016-08-02 02:07:36 +00:00
|
|
|
#[macro_use] extern crate diesel;
|
2018-09-11 19:35:33 +00:00
|
|
|
#[macro_use] extern crate diesel_migrations;
|
2018-10-09 11:16:57 +00:00
|
|
|
#[macro_use] extern crate rocket_contrib;
|
2016-08-02 02:07:36 +00:00
|
|
|
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
2016-08-02 02:07:36 +00:00
|
|
|
mod task;
|
2020-09-03 07:12:00 +00:00
|
|
|
|
2017-05-26 23:44:53 +00:00
|
|
|
use rocket::Rocket;
|
2018-09-11 19:35:33 +00:00
|
|
|
use rocket::fairing::AdHoc;
|
UTF-8 routes. Forms revamp. Temp files. Capped.
So. Many. Changes.
This is an insane commit: simultaneously one of the best (because of all
the wonderful improvements!) and one of the worst (because it is just
massive) in the project's history.
Routing:
* All UTF-8 characters are accepted everywhere in route paths. (#998)
* `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]`
becomes `#[route(GET, uri = "..")]`.
Forms Revamp
* All form related types now reside in a new `form` module.
* Multipart forms are supported. (resolves #106)
* Collections are supported in forms and queries. (resolves #205)
* Nested structures in forms and queries are supported. (resolves #313)
* Form fields can be ad-hoc validated with `#[field(validate = expr)]`.
* `FromFormValue` is now `FromFormField`, blanket implements `FromForm`.
* Form field values are always percent-decoded apriori.
Temporary Files
* A new `TempFile` data and form guard allows streaming data directly to a
file which can then be persisted.
* A new `temp_dir` config parameter specifies where to store `TempFile`.
* The limits `file` and `file/$ext`, where `$ext` is the file extension,
determines the data limit for a `TempFile`.
Capped
* A new `Capped` type is used to indicate when data has been truncated due to
incoming data limits. It allows checking whether data is complete or
truncated.
* `DataStream` methods return `Capped` types.
* `DataStream` API has been revamped to account for `Capped` types.
* Several `Capped<T>` types implement `FromData`, `FromForm`.
* HTTP 413 (Payload Too Large) errors are now returned when data limits are
exceeded. (resolves #972)
Hierarchical Limits
* Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c`
falls back to `a/b` then `a`.
Core
* `&RawStr` no longer implements `FromParam`.
* `&str` implements `FromParam`, `FromData`, `FromForm`.
* `FromTransformedData` was removed.
* `FromData` gained a lifetime for use with request-local data.
* The default error HTML is more compact.
* `&Config` is a request guard.
* The `DataStream` interface was entirely revamped.
* `State` is only exported via `rocket::State`.
* A `request::local_cache!()` macro was added for storing values in
request-local cache without consideration for type uniqueness by using a
locally generated anonymous type.
* `Request::get_param()` is now `Request::param()`.
* `Request::get_segments()` is now `Request::segments()`, takes a range.
* `Request::get_query_value()` is now `Request::query_value()`, can parse any
`FromForm` including sequences.
* `std::io::Error` implements `Responder` like `Debug<std::io::Error>`.
* `(Status, R)` where `R: Responder` implements `Responder` by overriding the
`Status` of `R`.
* The name of a route is printed first during route matching.
* `FlashMessage` now only has one lifetime generic.
HTTP
* `RawStr` implements `serde::{Serialize, Deserialize}`.
* `RawStr` implements _many_ more methods, in particular, those related to the
`Pattern` API.
* `RawStr::from_str()` is now `RawStr::new()`.
* `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as
necessary, return `Cow`.
* `Status` implements `Default` with `Status::Ok`.
* `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`.
* Authority and origin part of `Absolute` can be modified with new
`Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods.
* `Origin::segments()` was removed in favor of methods split into query and
path parts and into raw and decoded versions.
* The `Segments` iterator is smarter, returns decoded `&str` items.
* `Segments::into_path_buf()` is now `Segments::to_path_buf()`.
* A new `QuerySegments` is the analogous query segment iterator.
* Once set, `expires` on private cookies is not overwritten. (resolves #1506)
* `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`.
Codegen
* Preserve more spans in `uri!` macro.
* Preserve spans `FromForm` field types.
* All dynamic parameters in a query string must typecheck as `FromForm`.
* `FromFormValue` derive removed; `FromFormField` added.
* The `form` `FromForm` and `FromFormField` field attribute is now named
`field`. `#[form(field = ..)]` is now `#[field(name = ..)]`.
Contrib
* `Json` implements `FromForm`.
* `MsgPack` implements `FromForm`.
* The `json!` macro is exported as `rocket_contrib::json::json!`.
* Added clarifying docs to `StaticFiles`.
Examples
* `form_validation` and `form_kitchen_sink` removed in favor of `forms`.
* The `hello_world` example uses unicode in paths.
* The `json` example only allocates as necessary.
Internal
* Codegen uses new `exports` module with the following conventions:
- Locals starts with `__` and are lowercased.
- Rocket modules start with `_` and are lowercased.
- `std` types start with `_` and are titlecased.
- Rocket types are titlecased.
* A `header` module was added to `http`, contains header types.
* `SAFETY` is used as doc-string keyword for `unsafe` related comments.
* The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
|
|
|
use rocket::request::FlashMessage;
|
2016-09-12 01:57:04 +00:00
|
|
|
use rocket::response::{Flash, Redirect};
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
use rocket::form::Form;
|
2017-02-03 01:38:36 +00:00
|
|
|
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
use rocket_contrib::templates::Template;
|
|
|
|
use rocket_contrib::serve::{StaticFiles, crate_relative};
|
2016-08-02 02:07:36 +00:00
|
|
|
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
use crate::task::{Task, Todo};
|
2018-09-11 19:35:33 +00:00
|
|
|
|
2018-07-21 22:11:08 +00:00
|
|
|
#[database("sqlite_database")]
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
pub struct DbConn(diesel::SqliteConnection);
|
2018-07-21 22:11:08 +00:00
|
|
|
|
2020-07-19 16:12:32 +00:00
|
|
|
#[derive(Debug, serde::Serialize)]
|
2020-07-11 18:17:43 +00:00
|
|
|
struct Context {
|
2021-04-08 02:01:48 +00:00
|
|
|
flash: Option<(String, String)>,
|
2020-06-08 19:11:34 +00:00
|
|
|
tasks: Vec<Task>
|
|
|
|
}
|
2016-07-16 04:09:08 +00:00
|
|
|
|
2020-07-11 18:17:43 +00:00
|
|
|
impl Context {
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
pub async fn err<M: std::fmt::Display>(conn: &DbConn, msg: M) -> Context {
|
2020-07-11 18:17:43 +00:00
|
|
|
Context {
|
2021-04-08 02:01:48 +00:00
|
|
|
flash: Some(("error".into(), msg.to_string())),
|
2020-07-11 18:17:43 +00:00
|
|
|
tasks: Task::all(conn).await.unwrap_or_default()
|
|
|
|
}
|
2016-09-22 11:12:07 +00:00
|
|
|
}
|
|
|
|
|
2021-04-08 02:01:48 +00:00
|
|
|
pub async fn raw(conn: &DbConn, flash: Option<(String, String)>) -> Context {
|
2020-07-11 18:17:43 +00:00
|
|
|
match Task::all(conn).await {
|
2021-04-08 02:01:48 +00:00
|
|
|
Ok(tasks) => Context { flash, tasks },
|
2020-06-08 19:11:34 +00:00
|
|
|
Err(e) => {
|
|
|
|
error_!("DB Task::all() error: {}", e);
|
|
|
|
Context {
|
2021-04-08 02:01:48 +00:00
|
|
|
flash: Some(("error".into(), "Fail to access database.".into())),
|
2020-06-08 19:11:34 +00:00
|
|
|
tasks: vec![]
|
|
|
|
}
|
2020-02-13 04:11:51 +00:00
|
|
|
}
|
|
|
|
}
|
2016-09-22 11:12:07 +00:00
|
|
|
}
|
2016-07-16 04:09:08 +00:00
|
|
|
}
|
|
|
|
|
2016-10-12 07:14:42 +00:00
|
|
|
#[post("/", data = "<todo_form>")]
|
2020-07-11 18:17:43 +00:00
|
|
|
async fn new(todo_form: Form<Todo>, conn: DbConn) -> Flash<Redirect> {
|
2016-10-12 07:14:42 +00:00
|
|
|
let todo = todo_form.into_inner();
|
2016-08-02 02:07:36 +00:00
|
|
|
if todo.description.is_empty() {
|
2016-10-12 07:14:42 +00:00
|
|
|
Flash::error(Redirect::to("/"), "Description cannot be empty.")
|
2020-09-03 07:12:00 +00:00
|
|
|
} else if let Err(e) = Task::insert(todo, &conn).await {
|
2020-06-08 19:11:34 +00:00
|
|
|
error_!("DB insertion error: {}", e);
|
|
|
|
Flash::error(Redirect::to("/"), "Todo could not be inserted due an internal error.")
|
2016-08-02 02:07:36 +00:00
|
|
|
} else {
|
2020-02-13 04:11:51 +00:00
|
|
|
Flash::success(Redirect::to("/"), "Todo successfully added.")
|
2016-08-02 02:07:36 +00:00
|
|
|
}
|
|
|
|
}
|
2016-07-16 04:09:08 +00:00
|
|
|
|
2016-09-25 09:26:15 +00:00
|
|
|
#[put("/<id>")]
|
2020-09-03 07:12:00 +00:00
|
|
|
async fn toggle(id: i32, conn: DbConn) -> Result<Redirect, Template> {
|
|
|
|
match Task::toggle_with_id(id, &conn).await {
|
2020-07-11 18:17:43 +00:00
|
|
|
Ok(_) => Ok(Redirect::to("/")),
|
|
|
|
Err(e) => {
|
2020-06-08 19:11:34 +00:00
|
|
|
error_!("DB toggle({}) error: {}", id, e);
|
2020-09-03 07:12:00 +00:00
|
|
|
Err(Template::render("index", Context::err(&conn, "Failed to toggle task.").await))
|
2020-07-11 18:17:43 +00:00
|
|
|
}
|
|
|
|
}
|
2016-07-16 04:09:08 +00:00
|
|
|
}
|
|
|
|
|
2016-09-25 09:26:15 +00:00
|
|
|
#[delete("/<id>")]
|
2020-09-03 07:12:00 +00:00
|
|
|
async fn delete(id: i32, conn: DbConn) -> Result<Flash<Redirect>, Template> {
|
|
|
|
match Task::delete_with_id(id, &conn).await {
|
2020-07-11 18:17:43 +00:00
|
|
|
Ok(_) => Ok(Flash::success(Redirect::to("/"), "Todo was deleted.")),
|
|
|
|
Err(e) => {
|
2020-06-08 19:11:34 +00:00
|
|
|
error_!("DB deletion({}) error: {}", id, e);
|
2020-09-03 07:12:00 +00:00
|
|
|
Err(Template::render("index", Context::err(&conn, "Failed to delete task.").await))
|
2020-07-11 18:17:43 +00:00
|
|
|
}
|
|
|
|
}
|
2016-07-16 04:09:08 +00:00
|
|
|
}
|
|
|
|
|
2016-09-04 11:06:28 +00:00
|
|
|
#[get("/")]
|
2021-04-08 02:01:48 +00:00
|
|
|
async fn index(flash: Option<FlashMessage<'_>>, conn: DbConn) -> Template {
|
|
|
|
let flash = flash.map(FlashMessage::into_inner);
|
|
|
|
Template::render("index", Context::raw(&conn, flash).await)
|
2016-07-16 04:09:08 +00:00
|
|
|
}
|
|
|
|
|
2021-04-08 02:01:48 +00:00
|
|
|
async fn run_migrations(rocket: Rocket) -> Rocket {
|
Remove 'attach' fairings. Add 'liftoff' fairings.
Launch fairings are now fallible and take the place of attach fairings,
but they are only run, as the name implies, at launch time.
This is is a fundamental shift from eager execution of set-up routines,
including the now defunct attach fairings, to lazy execution,
precipitated by the transition to `async`. The previous functionality,
while simple, caused grave issues:
1. A instance of 'Rocket' with async attach fairings requires an async
runtime to be constructed.
2. The instance is accessible in non-async contexts.
3. The async attach fairings have no runtime in which to be run.
Here's an example:
```rust
let rocket = rocket::ignite()
.attach(AttachFairing::from(|rocket| async {
Ok(rocket.manage(load_from_network::<T>().await))
}));
let state = rocket.state::<T>();
```
This had no real meaning previously yet was accepted by running the
attach fairing future in an isolated runtime. In isolation, this causes
no issue, but when attach fairing futures share reactor state with other
futures in Rocket, panics ensue.
The new Rocket application lifecycle is this:
* Build - A Rocket instance is constructed. No fairings are run.
* Ignition - All launch fairings are run.
* Liftoff - If all launch fairings succeeded, the server is started.
New 'liftoff' fairings are run in this third phase.
2021-04-01 19:32:52 +00:00
|
|
|
// This macro from `diesel_migrations` defines an `embedded_migrations`
|
|
|
|
// module containing a function named `run`. This allows the example to be
|
|
|
|
// run and tested without any outside setup of the database.
|
|
|
|
embed_migrations!();
|
|
|
|
|
|
|
|
let conn = DbConn::get_one(&rocket).await.expect("database connection");
|
2021-04-08 02:01:48 +00:00
|
|
|
conn.run(|c| embedded_migrations::run(c)).await.expect("can run migrations");
|
|
|
|
|
|
|
|
rocket
|
2018-12-30 21:52:08 +00:00
|
|
|
}
|
|
|
|
|
2020-07-22 23:10:02 +00:00
|
|
|
#[launch]
|
2021-04-14 01:12:39 +00:00
|
|
|
fn rocket() -> _ {
|
2021-04-08 08:07:52 +00:00
|
|
|
rocket::build()
|
2018-07-21 22:11:08 +00:00
|
|
|
.attach(DbConn::fairing())
|
2020-10-22 10:27:04 +00:00
|
|
|
.attach(Template::fairing())
|
2021-04-08 02:01:48 +00:00
|
|
|
.attach(AdHoc::on_launch("Run Migrations", run_migrations))
|
|
|
|
.mount("/", StaticFiles::from(crate_relative!("static")))
|
2018-08-24 21:00:36 +00:00
|
|
|
.mount("/", routes![index])
|
2018-07-30 01:24:25 +00:00
|
|
|
.mount("/todo", routes![new, toggle, delete])
|
2017-05-26 23:44:53 +00:00
|
|
|
}
|