Merge branch 'master' of github.com:Plume-org/Plume
This commit is contained in:
commit
b9951f0d70
|
@ -5,3 +5,4 @@ rls
|
||||||
rls
|
rls
|
||||||
translations
|
translations
|
||||||
po/*.po~
|
po/*.po~
|
||||||
|
.env
|
||||||
|
|
|
@ -245,6 +245,14 @@ dependencies = [
|
||||||
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "comrak"
|
name = "comrak"
|
||||||
version = "0.2.12"
|
version = "0.2.12"
|
||||||
|
@ -999,6 +1007,7 @@ dependencies = [
|
||||||
"base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bcrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bcrypt 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"comrak 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"comrak 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"diesel 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"diesel 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1015,6 +1024,7 @@ dependencies = [
|
||||||
"rocket_codegen 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
|
"rocket_codegen 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
|
||||||
"rocket_contrib 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
|
"rocket_contrib 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
|
||||||
"rocket_i18n 0.1.1 (git+https://github.com/BaptisteGelez/rocket_i18n?rev=5b4225d5bed5769482dc926a7e6d6b79f1217be6)",
|
"rocket_i18n 0.1.1 (git+https://github.com/BaptisteGelez/rocket_i18n?rev=5b4225d5bed5769482dc926a7e6d6b79f1217be6)",
|
||||||
|
"rpassword 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1282,6 +1292,16 @@ dependencies = [
|
||||||
"tera 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tera 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rpassword"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
|
@ -1998,6 +2018,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||||
"checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6"
|
"checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6"
|
||||||
"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
|
"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
|
||||||
|
"checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc"
|
||||||
"checksum comrak 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "053b26c8ce23b4c505a9479beace98f95899e0bf5c5255cf0219e9b0f48cf6ea"
|
"checksum comrak 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "053b26c8ce23b4c505a9479beace98f95899e0bf5c5255cf0219e9b0f48cf6ea"
|
||||||
"checksum cookie 0.11.0-dev (git+https://github.com/alexcrichton/cookie-rs?rev=0365a18)" = "<none>"
|
"checksum cookie 0.11.0-dev (git+https://github.com/alexcrichton/cookie-rs?rev=0365a18)" = "<none>"
|
||||||
"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67"
|
"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67"
|
||||||
|
@ -2110,6 +2131,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum rocket_contrib 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "<none>"
|
"checksum rocket_contrib 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "<none>"
|
||||||
"checksum rocket_http 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "<none>"
|
"checksum rocket_http 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "<none>"
|
||||||
"checksum rocket_i18n 0.1.1 (git+https://github.com/BaptisteGelez/rocket_i18n?rev=5b4225d5bed5769482dc926a7e6d6b79f1217be6)" = "<none>"
|
"checksum rocket_i18n 0.1.1 (git+https://github.com/BaptisteGelez/rocket_i18n?rev=5b4225d5bed5769482dc926a7e6d6b79f1217be6)" = "<none>"
|
||||||
|
"checksum rpassword 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d127299b02abda51634f14025aec43ae87a7aa7a95202b6a868ec852607d1451"
|
||||||
"checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb"
|
"checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb"
|
||||||
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
|
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
|
||||||
"checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade"
|
"checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade"
|
||||||
|
|
|
@ -8,6 +8,7 @@ ammonia = "1.1.0"
|
||||||
array_tool = "1.0"
|
array_tool = "1.0"
|
||||||
base64 = "0.9"
|
base64 = "0.9"
|
||||||
bcrypt = "0.2"
|
bcrypt = "0.2"
|
||||||
|
colored = "1.6"
|
||||||
comrak = "0.2"
|
comrak = "0.2"
|
||||||
dotenv = "*"
|
dotenv = "*"
|
||||||
failure = "0.1"
|
failure = "0.1"
|
||||||
|
@ -19,6 +20,7 @@ hyper = "*"
|
||||||
lazy_static = "*"
|
lazy_static = "*"
|
||||||
openssl = "0.10.6"
|
openssl = "0.10.6"
|
||||||
reqwest = "0.8"
|
reqwest = "0.8"
|
||||||
|
rpassword = "2.0"
|
||||||
serde = "*"
|
serde = "*"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
|
@ -42,46 +42,16 @@ Now, you can use the following command to start Postgres on a one-time basis.
|
||||||
pg_ctl -D /usr/local/var/postgres start
|
pg_ctl -D /usr/local/var/postgres start
|
||||||
```
|
```
|
||||||
|
|
||||||
After starting Postgres, we need to enter [PSQL](http://postgresguide.com/utilities/psql.html), the interactive terminal for running postgres queries. We'll be running this as the user `postgres` which is an admin-type postgres user.
|
When you will launch Plume for the first time, it will setup the database by itself.
|
||||||
|
|
||||||
```
|
|
||||||
psql postgres
|
|
||||||
```
|
|
||||||
|
|
||||||
Now that you are in psql, enter the following queries to prepare the database for Plume.
|
|
||||||
|
|
||||||
```
|
|
||||||
CREATE DATABASE plume;
|
|
||||||
CREATE USER plume WITH PASSWORD 'plume';
|
|
||||||
GRANT ALL PRIVILEGES ON DATABASE plume to plume;
|
|
||||||
\q
|
|
||||||
```
|
|
||||||
|
|
||||||
The final command `\q` lets us exit psql and returns us to the Terminal. Now, we will open psql again, this time as the `plume` user we just created. Then we'll give all privileges on all tables and sequences to our `plume` user. This is for local development use only and it's not recommend to give complete access to this user in a production environment.
|
|
||||||
|
|
||||||
```
|
|
||||||
psql plume
|
|
||||||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO plume;
|
|
||||||
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO plume;
|
|
||||||
\q
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Database Migration
|
#### Database Migration
|
||||||
|
|
||||||
Now that the Postgres database is set up and the `plume` user has the privileges it needs, we can set up the database using the diesel CLI. If this was your time installing Rust, you
|
To run migrations and correctly setup the database, Plume use the `diesel` CLI tool under the hood. Therefore you should install it before running Plume. If this was your time installing Rust, you will probably need to run that using `cargo`. `cargo` is installed with `rustc` so if you followed the earlier instructions it will already be available.
|
||||||
will probably need to run that using `cargo`. `cargo` is installed with `rustc` so if you followed the earlier instructions it will already be available.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
cargo install diesel_cli
|
cargo install diesel_cli
|
||||||
```
|
```
|
||||||
|
|
||||||
The first time you run this, you can run setup. After that, every time you pull the repository you will want to run the migration command in case there were any migrations. Those commands are
|
|
||||||
|
|
||||||
```
|
|
||||||
diesel setup --database-url='postgres://localhost/plume'
|
|
||||||
diesel migration run --database-url='postgres://localhost/plume'
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Running Plume
|
#### Running Plume
|
||||||
|
|
||||||
To run Plume locally, make sure you are once again in the Plume directory, such as `~/dev/Plume`. Now you will be able to run the application using the command
|
To run Plume locally, make sure you are once again in the Plume directory, such as `~/dev/Plume`. Now you will be able to run the application using the command
|
||||||
|
@ -92,7 +62,7 @@ cargo run
|
||||||
|
|
||||||
#### Configuration
|
#### Configuration
|
||||||
|
|
||||||
Now Plume should be running on your machine at [http://localhost:8000](http://localhost:8000). The first time you run the application, you'll want to configure your blog name on the [http://localhost:8000/configure](http://localhost:8000/configure) page. You'll be able to change this name later.
|
The first time you'll run Plume, it will help you setup your instance through an interactive tool. Once you'll have answered all its question, your instance will start.
|
||||||
|
|
||||||
#### Testing the federation
|
#### Testing the federation
|
||||||
|
|
||||||
|
|
22
src/main.rs
22
src/main.rs
|
@ -7,6 +7,7 @@ extern crate array_tool;
|
||||||
extern crate base64;
|
extern crate base64;
|
||||||
extern crate bcrypt;
|
extern crate bcrypt;
|
||||||
extern crate chrono;
|
extern crate chrono;
|
||||||
|
extern crate colored;
|
||||||
extern crate comrak;
|
extern crate comrak;
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -26,6 +27,7 @@ extern crate reqwest;
|
||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
extern crate rocket_contrib;
|
extern crate rocket_contrib;
|
||||||
extern crate rocket_i18n;
|
extern crate rocket_i18n;
|
||||||
|
extern crate rpassword;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
@ -35,18 +37,17 @@ extern crate tera;
|
||||||
extern crate url;
|
extern crate url;
|
||||||
extern crate webfinger;
|
extern crate webfinger;
|
||||||
|
|
||||||
use diesel::{pg::PgConnection, r2d2::{ConnectionManager, Pool}};
|
|
||||||
use dotenv::dotenv;
|
|
||||||
use rocket_contrib::Template;
|
use rocket_contrib::Template;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
mod activity_pub;
|
mod activity_pub;
|
||||||
mod db_conn;
|
mod db_conn;
|
||||||
mod models;
|
mod models;
|
||||||
|
mod safe_string;
|
||||||
mod schema;
|
mod schema;
|
||||||
|
mod setup;
|
||||||
mod routes;
|
mod routes;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod safe_string;
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref BASE_URL: String = env::var("BASE_URL")
|
pub static ref BASE_URL: String = env::var("BASE_URL")
|
||||||
|
@ -56,17 +57,8 @@ lazy_static! {
|
||||||
.unwrap_or(format!("postgres://plume:plume@localhost/{}", env::var("DB_NAME").unwrap_or(String::from("plume"))));
|
.unwrap_or(format!("postgres://plume:plume@localhost/{}", env::var("DB_NAME").unwrap_or(String::from("plume"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
type PgPool = Pool<ConnectionManager<PgConnection>>;
|
|
||||||
|
|
||||||
/// Initializes a database pool.
|
|
||||||
fn init_pool() -> PgPool {
|
|
||||||
dotenv().ok();
|
|
||||||
|
|
||||||
let manager = ConnectionManager::<PgConnection>::new(DB_URL.as_str());
|
|
||||||
Pool::new(manager).expect("DB pool error")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let pool = setup::check();
|
||||||
rocket::ignite()
|
rocket::ignite()
|
||||||
.mount("/", routes![
|
.mount("/", routes![
|
||||||
routes::blogs::details,
|
routes::blogs::details,
|
||||||
|
@ -81,8 +73,6 @@ fn main() {
|
||||||
routes::comments::create,
|
routes::comments::create,
|
||||||
|
|
||||||
routes::instance::index,
|
routes::instance::index,
|
||||||
routes::instance::configure,
|
|
||||||
routes::instance::post_config,
|
|
||||||
routes::instance::shared_inbox,
|
routes::instance::shared_inbox,
|
||||||
routes::instance::nodeinfo,
|
routes::instance::nodeinfo,
|
||||||
|
|
||||||
|
@ -133,7 +123,7 @@ fn main() {
|
||||||
routes::errors::not_found,
|
routes::errors::not_found,
|
||||||
routes::errors::server_error
|
routes::errors::server_error
|
||||||
])
|
])
|
||||||
.manage(init_pool())
|
.manage(pool)
|
||||||
.attach(Template::custom(|engines| {
|
.attach(Template::custom(|engines| {
|
||||||
rocket_i18n::tera(&mut engines.tera);
|
rocket_i18n::tera(&mut engines.tera);
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -484,16 +484,16 @@ impl Signer for User {
|
||||||
impl NewUser {
|
impl NewUser {
|
||||||
/// Creates a new local user
|
/// Creates a new local user
|
||||||
pub fn new_local(
|
pub fn new_local(
|
||||||
|
conn: &PgConnection,
|
||||||
username: String,
|
username: String,
|
||||||
display_name: String,
|
display_name: String,
|
||||||
is_admin: bool,
|
is_admin: bool,
|
||||||
summary: String,
|
summary: String,
|
||||||
email: String,
|
email: String,
|
||||||
password: String,
|
password: String
|
||||||
instance_id: i32
|
) -> User {
|
||||||
) -> NewUser {
|
|
||||||
let (pub_key, priv_key) = gen_keypair();
|
let (pub_key, priv_key) = gen_keypair();
|
||||||
NewUser {
|
User::insert(conn, NewUser {
|
||||||
username: username,
|
username: username,
|
||||||
display_name: display_name,
|
display_name: display_name,
|
||||||
outbox_url: String::from(""),
|
outbox_url: String::from(""),
|
||||||
|
@ -502,11 +502,11 @@ impl NewUser {
|
||||||
summary: SafeString::new(&summary),
|
summary: SafeString::new(&summary),
|
||||||
email: Some(email),
|
email: Some(email),
|
||||||
hashed_password: Some(password),
|
hashed_password: Some(password),
|
||||||
instance_id: instance_id,
|
instance_id: Instance::local_id(conn),
|
||||||
ap_url: String::from(""),
|
ap_url: String::from(""),
|
||||||
public_key: String::from_utf8(pub_key).unwrap(),
|
public_key: String::from_utf8(pub_key).unwrap(),
|
||||||
private_key: Some(String::from_utf8(priv_key).unwrap()),
|
private_key: Some(String::from_utf8(priv_key).unwrap()),
|
||||||
shared_inbox_url: None
|
shared_inbox_url: None
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use gettextrs::gettext;
|
use gettextrs::gettext;
|
||||||
use rocket::{request::Form, response::Redirect};
|
|
||||||
use rocket_contrib::{Json, Template};
|
use rocket_contrib::{Json, Template};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
use BASE_URL;
|
|
||||||
use activity_pub::inbox::Inbox;
|
use activity_pub::inbox::Inbox;
|
||||||
use db_conn::DbConn;
|
use db_conn::DbConn;
|
||||||
use models::{
|
use models::{
|
||||||
|
@ -33,31 +31,6 @@ fn index(conn: DbConn, user: Option<User>) -> Template {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/configure")]
|
|
||||||
fn configure() -> Template {
|
|
||||||
Template::render("instance/configure", json!({}))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(FromForm)]
|
|
||||||
struct NewInstanceForm {
|
|
||||||
name: String
|
|
||||||
}
|
|
||||||
|
|
||||||
#[post("/configure", data = "<data>")]
|
|
||||||
fn post_config(conn: DbConn, data: Form<NewInstanceForm>) -> Redirect {
|
|
||||||
let form = data.get();
|
|
||||||
let inst = Instance::insert(&*conn, NewInstance {
|
|
||||||
public_domain: BASE_URL.as_str().to_string(),
|
|
||||||
name: form.name.to_string(),
|
|
||||||
local: true
|
|
||||||
});
|
|
||||||
if inst.has_admin(&*conn) {
|
|
||||||
Redirect::to("/")
|
|
||||||
} else {
|
|
||||||
Redirect::to("/users/new")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[post("/inbox", data = "<data>")]
|
#[post("/inbox", data = "<data>")]
|
||||||
fn shared_inbox(conn: DbConn, data: String) -> String {
|
fn shared_inbox(conn: DbConn, data: String) -> String {
|
||||||
let act: serde_json::Value = serde_json::from_str(&data[..]).unwrap();
|
let act: serde_json::Value = serde_json::from_str(&data[..]).unwrap();
|
||||||
|
|
|
@ -164,7 +164,6 @@ struct NewUserForm {
|
||||||
|
|
||||||
#[post("/users/new", data = "<data>")]
|
#[post("/users/new", data = "<data>")]
|
||||||
fn create(conn: DbConn, data: Form<NewUserForm>) -> Result<Redirect, String> {
|
fn create(conn: DbConn, data: Form<NewUserForm>) -> Result<Redirect, String> {
|
||||||
let inst = Instance::get_local(&*conn).unwrap();
|
|
||||||
let form = data.get();
|
let form = data.get();
|
||||||
|
|
||||||
if form.username.clone().len() < 1 {
|
if form.username.clone().len() < 1 {
|
||||||
|
@ -174,15 +173,15 @@ fn create(conn: DbConn, data: Form<NewUserForm>) -> Result<Redirect, String> {
|
||||||
} else if form.password.clone().len() < 8 {
|
} else if form.password.clone().len() < 8 {
|
||||||
Err(String::from("Password should be at least 8 characters long"))
|
Err(String::from("Password should be at least 8 characters long"))
|
||||||
} else if form.password == form.password_confirmation {
|
} else if form.password == form.password_confirmation {
|
||||||
User::insert(&*conn, NewUser::new_local(
|
NewUser::new_local(
|
||||||
|
&*conn,
|
||||||
form.username.to_string(),
|
form.username.to_string(),
|
||||||
form.username.to_string(),
|
form.username.to_string(),
|
||||||
!inst.has_admin(&*conn),
|
false,
|
||||||
String::from(""),
|
String::from(""),
|
||||||
form.email.to_string(),
|
form.email.to_string(),
|
||||||
User::hash_pass(form.password.to_string()),
|
User::hash_pass(form.password.to_string())
|
||||||
inst.id
|
).update_boxes(&*conn);
|
||||||
)).update_boxes(&*conn);
|
|
||||||
Ok(Redirect::to(uri!(super::session::new)))
|
Ok(Redirect::to(uri!(super::session::new)))
|
||||||
} else {
|
} else {
|
||||||
Err(String::from("Passwords don't match"))
|
Err(String::from("Passwords don't match"))
|
||||||
|
|
|
@ -0,0 +1,261 @@
|
||||||
|
use colored::Colorize;
|
||||||
|
use diesel::{pg::PgConnection, r2d2::{ConnectionManager, Pool}};
|
||||||
|
use dotenv::dotenv;
|
||||||
|
use std::fs::{self, File};
|
||||||
|
use std::io;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::{exit, Command};
|
||||||
|
use rpassword;
|
||||||
|
|
||||||
|
use DB_URL;
|
||||||
|
use db_conn::DbConn;
|
||||||
|
use models::instance::*;
|
||||||
|
use models::users::*;
|
||||||
|
|
||||||
|
type PgPool = Pool<ConnectionManager<PgConnection>>;
|
||||||
|
|
||||||
|
/// Initializes a database pool.
|
||||||
|
fn init_pool() -> Option<PgPool> {
|
||||||
|
dotenv().ok();
|
||||||
|
|
||||||
|
let manager = ConnectionManager::<PgConnection>::new(DB_URL.as_str());
|
||||||
|
Pool::new(manager).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check() -> PgPool {
|
||||||
|
if let Some(pool) = init_pool() {
|
||||||
|
match pool.get() {
|
||||||
|
Ok(conn) => {
|
||||||
|
let db_conn = DbConn(conn);
|
||||||
|
if Instance::get_local(&*db_conn).is_none() {
|
||||||
|
run_setup(Some(db_conn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => panic!("Couldn't connect to database")
|
||||||
|
}
|
||||||
|
migrate();
|
||||||
|
pool
|
||||||
|
} else {
|
||||||
|
run_setup(None);
|
||||||
|
init_pool().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_setup(conn: Option<DbConn>) {
|
||||||
|
println!("\n\n");
|
||||||
|
println!("{}\n{}\n{}\n\n{}",
|
||||||
|
"Welcome in the Plume setup tool.".magenta(),
|
||||||
|
"It will help you setup your new instance, by asking you a few questions.".magenta(),
|
||||||
|
"Then you'll be able to enjoy Plume!".magenta(),
|
||||||
|
"First let's check that you have all the required dependencies. Press Enter to start."
|
||||||
|
);
|
||||||
|
read_line();
|
||||||
|
check_native_deps();
|
||||||
|
let conn = setup_db(conn);
|
||||||
|
setup_type(conn);
|
||||||
|
dotenv().ok();
|
||||||
|
|
||||||
|
println!("{}\n{}\n{}",
|
||||||
|
"Your Plume instance is now ready to be used.".magenta(),
|
||||||
|
"We hope you will enjoy it.".magenta(),
|
||||||
|
"If you ever encounter a problem, feel free to report it at https://github.com/Plume-org/Plume/issues/".magenta(),
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("\nPress Enter to start it.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_db(conn: Option<DbConn>) -> DbConn {
|
||||||
|
write_to_dotenv("DB_URL", DB_URL.as_str().to_string());
|
||||||
|
|
||||||
|
match conn {
|
||||||
|
Some(conn) => conn,
|
||||||
|
None => {
|
||||||
|
println!("\n{}\n", "We are going to setup the database.".magenta());
|
||||||
|
println!("{}\n", "About to create a new PostgreSQL user named 'plume'".blue());
|
||||||
|
Command::new("createuser")
|
||||||
|
.arg("-d")
|
||||||
|
.arg("-P")
|
||||||
|
.arg("plume")
|
||||||
|
.status()
|
||||||
|
.map(|s| {
|
||||||
|
if s.success() {
|
||||||
|
println!("{}\n", " ✔️ Done".green());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.expect("Couldn't create new user");
|
||||||
|
|
||||||
|
println!("{}\n", "About to create a new PostgreSQL database named 'plume'".blue());
|
||||||
|
Command::new("createdb")
|
||||||
|
.arg("-O")
|
||||||
|
.arg("plume")
|
||||||
|
.arg("plume")
|
||||||
|
.status()
|
||||||
|
.map(|s| {
|
||||||
|
if s.success() {
|
||||||
|
println!("{}\n", " ✔️ Done".green());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.expect("Couldn't create new table");
|
||||||
|
|
||||||
|
migrate();
|
||||||
|
|
||||||
|
init_pool()
|
||||||
|
.expect("Couldn't init DB pool")
|
||||||
|
.get()
|
||||||
|
.map(|c| DbConn(c))
|
||||||
|
.expect("Couldn't connect to the database")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn migrate() {
|
||||||
|
println!("{}\n", "Running migrations…".blue());
|
||||||
|
Command::new("diesel")
|
||||||
|
.arg("migration")
|
||||||
|
.arg("run")
|
||||||
|
.arg("--database-url")
|
||||||
|
.arg(DB_URL.as_str())
|
||||||
|
.status()
|
||||||
|
.map(|s| {
|
||||||
|
if s.success() {
|
||||||
|
println!("{}\n", " ✔️ Done".green());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.expect("Couldn't run migrations");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_type(conn: DbConn) {
|
||||||
|
println!("\nDo you prefer a simple setup, or to customize everything?\n");
|
||||||
|
println!(" 1 - Simple setup");
|
||||||
|
println!(" 2 - Complete setup");
|
||||||
|
match read_line().as_ref() {
|
||||||
|
"Simple" | "simple" | "s" | "S" |
|
||||||
|
"1" => quick_setup(conn),
|
||||||
|
"Complete" | "complete" | "c" | "C" |
|
||||||
|
"2" => complete_setup(conn),
|
||||||
|
x => {
|
||||||
|
println!("Invalid choice. Choose between '1' or '2'. {}", x);
|
||||||
|
setup_type(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quick_setup(conn: DbConn) {
|
||||||
|
println!("What is your instance domain?");
|
||||||
|
let domain = read_line();
|
||||||
|
write_to_dotenv("BASE_URL", domain.clone());
|
||||||
|
|
||||||
|
println!("\nWhat is your instance name?");
|
||||||
|
let name = read_line();
|
||||||
|
|
||||||
|
let instance = Instance::insert(&*conn, NewInstance {
|
||||||
|
public_domain: domain,
|
||||||
|
name: name,
|
||||||
|
local: true
|
||||||
|
});
|
||||||
|
|
||||||
|
println!("{}\n", " ✔️ Your instance was succesfully created!".green());
|
||||||
|
|
||||||
|
// Generate Rocket secret key.
|
||||||
|
let key = Command::new("openssl")
|
||||||
|
.arg("rand")
|
||||||
|
.arg("-base64")
|
||||||
|
.arg("32")
|
||||||
|
.output()
|
||||||
|
.map(|o| String::from_utf8(o.stdout).expect("Invalid output from openssl"))
|
||||||
|
.expect("Couldn't generate secret key.");
|
||||||
|
write_to_dotenv("ROCKET_SECRET_KEY", key);
|
||||||
|
|
||||||
|
create_admin(instance, conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete_setup(conn: DbConn) {
|
||||||
|
quick_setup(conn);
|
||||||
|
|
||||||
|
println!("\nOn which port should Plume listen? (default: 7878)");
|
||||||
|
let port = read_line_or("7878");
|
||||||
|
write_to_dotenv("ROCKET_PORT", port);
|
||||||
|
|
||||||
|
println!("\nOn which address should Plume listen? (default: 0.0.0.0)");
|
||||||
|
let address = read_line_or("0.0.0.0");
|
||||||
|
write_to_dotenv("ROCKET_ADDRESS", address);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_admin(instance: Instance, conn: DbConn) {
|
||||||
|
println!("{}\n\n", "You are now about to create your admin account".magenta());
|
||||||
|
|
||||||
|
println!("What is your username? (default: admin)");
|
||||||
|
let name = read_line_or("admin");
|
||||||
|
|
||||||
|
println!("What is your email?");
|
||||||
|
let email = read_line();
|
||||||
|
|
||||||
|
println!("What is your password?");
|
||||||
|
let password = rpassword::read_password().expect("Couldn't read your password.");
|
||||||
|
|
||||||
|
NewUser::new_local(
|
||||||
|
&*conn,
|
||||||
|
name.clone(),
|
||||||
|
name,
|
||||||
|
true,
|
||||||
|
format!("Admin of {}", instance.name),
|
||||||
|
email,
|
||||||
|
User::hash_pass(password),
|
||||||
|
).update_boxes(&*conn);
|
||||||
|
|
||||||
|
println!("{}\n", " ✔️ Your account was succesfully created!".green());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_native_deps() {
|
||||||
|
let mut not_found = Vec::new();
|
||||||
|
if !try_run("psql") {
|
||||||
|
not_found.push(("PostgreSQL", "sudo apt install postgres"));
|
||||||
|
}
|
||||||
|
if !try_run("gettext") {
|
||||||
|
not_found.push(("GetText", "sudo apt install gettext"))
|
||||||
|
}
|
||||||
|
if !try_run("diesel") {
|
||||||
|
not_found.push(("Diesel CLI", "cargo install diesel_cli"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if not_found.len() > 0 {
|
||||||
|
println!("{}\n", "Some native dependencies are missing:".red());
|
||||||
|
for (dep, install) in not_found.into_iter() {
|
||||||
|
println!("{}", format!(" - {} (can be installed with `{}`, on Debian based distributions)", dep, install).red())
|
||||||
|
}
|
||||||
|
println!("\nRetry once you have installed them.");
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
println!("{}", " ✔️ All native dependencies are present.".green())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_run(command: &'static str) -> bool {
|
||||||
|
Command::new(command)
|
||||||
|
.output()
|
||||||
|
.is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_line() -> String {
|
||||||
|
let mut input = String::new();
|
||||||
|
io::stdin().read_line(&mut input).expect("Unable to read line");
|
||||||
|
input.retain(|c| c != '\n');
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_line_or(or: &str) -> String {
|
||||||
|
let input = read_line();
|
||||||
|
if input.len() == 0 {
|
||||||
|
or.to_string()
|
||||||
|
} else {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_to_dotenv(var: &'static str, val: String) {
|
||||||
|
if !Path::new(".env").exists() {
|
||||||
|
File::create(".env").expect("Error while creating .env file");
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::write(".env", format!("{}\n{}={}", fs::read_to_string(".env").expect("Unable to read .env"), var, val)).expect("Unable to write .env");
|
||||||
|
}
|
Loading…
Reference in New Issue