mirror of
https://github.com/Nutomic/ibis.git
synced 2024-11-22 07:01:09 +00:00
Merge branch 'master' into tailwind-css
This commit is contained in:
commit
b7e490be9e
63 changed files with 977 additions and 803 deletions
|
@ -1,7 +1,7 @@
|
||||||
variables:
|
variables:
|
||||||
- &rust_image "rust:1.81"
|
- &rust_image "rust:1.81"
|
||||||
- &install_binstall "wget https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-x86_64-unknown-linux-musl.tgz && tar -xvf cargo-binstall-x86_64-unknown-linux-musl.tgz && cp cargo-binstall /usr/local/cargo/bin"
|
- &install_binstall "wget https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-x86_64-unknown-linux-musl.tgz && tar -xvf cargo-binstall-x86_64-unknown-linux-musl.tgz && cp cargo-binstall /usr/local/cargo/bin"
|
||||||
- &install_trunk "cargo-binstall -y trunk@0.21.1"
|
- &install_cargo_leptos "cargo-binstall -y cargo-leptos@0.2.20"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
cargo_fmt:
|
cargo_fmt:
|
||||||
|
@ -50,14 +50,6 @@ steps:
|
||||||
- diesel print-schema --config-file=diesel.toml > tmp.schema
|
- diesel print-schema --config-file=diesel.toml > tmp.schema
|
||||||
- diff tmp.schema src/backend/database/schema.rs
|
- diff tmp.schema src/backend/database/schema.rs
|
||||||
|
|
||||||
frontend_wasm_build:
|
|
||||||
image: *rust_image
|
|
||||||
environment:
|
|
||||||
CARGO_HOME: .cargo_home
|
|
||||||
commands:
|
|
||||||
- "rustup target add wasm32-unknown-unknown"
|
|
||||||
- "cargo check --target wasm32-unknown-unknown --features csr,hydrate --no-default-features"
|
|
||||||
|
|
||||||
cargo_clippy:
|
cargo_clippy:
|
||||||
image: *rust_image
|
image: *rust_image
|
||||||
environment:
|
environment:
|
||||||
|
@ -89,7 +81,7 @@ steps:
|
||||||
commands:
|
commands:
|
||||||
- *install_binstall
|
- *install_binstall
|
||||||
- rustup target add wasm32-unknown-unknown
|
- rustup target add wasm32-unknown-unknown
|
||||||
- *install_trunk
|
- *install_cargo_leptos
|
||||||
- export PATH="$PATH:$(pwd)/.cargo_home/bin/"
|
- export PATH="$PATH:$(pwd)/.cargo_home/bin/"
|
||||||
- ./scripts/build_release.sh
|
- ./scripts/build_release.sh
|
||||||
when:
|
when:
|
||||||
|
|
1252
Cargo.lock
generated
1252
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
51
Cargo.toml
51
Cargo.toml
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "ibis"
|
name = "ibis"
|
||||||
version = "0.1.3"
|
version = "0.1.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -18,9 +18,32 @@ ssr = [
|
||||||
"activitypub_federation",
|
"activitypub_federation",
|
||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
"katex/duktape",
|
"katex/duktape",
|
||||||
|
"leptos/ssr",
|
||||||
|
"leptos-use/ssr",
|
||||||
]
|
]
|
||||||
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr", "katex/wasm-js"]
|
hydrate = [
|
||||||
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
|
"leptos/hydrate",
|
||||||
|
"leptos_meta/hydrate",
|
||||||
|
"leptos_router/hydrate",
|
||||||
|
"katex/wasm-js",
|
||||||
|
]
|
||||||
|
|
||||||
|
# This profile significantly speeds up build time. If debug info is needed you can comment the line
|
||||||
|
# out temporarily, but make sure to leave this in the main branch.
|
||||||
|
[profile.dev]
|
||||||
|
debug = 0
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = "thin"
|
||||||
|
strip = true
|
||||||
|
|
||||||
|
# Defines a size-optimized profile for the WASM bundle in release mode
|
||||||
|
[profile.wasm-release]
|
||||||
|
inherits = "release"
|
||||||
|
opt-level = 'z'
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
panic = "abort"
|
||||||
|
|
||||||
[lints.clippy]
|
[lints.clippy]
|
||||||
dbg_macro = "deny"
|
dbg_macro = "deny"
|
||||||
|
@ -80,25 +103,23 @@ doku = "0.21.1"
|
||||||
smart-default = "0.7.1"
|
smart-default = "0.7.1"
|
||||||
tower-layer = "0.3.3"
|
tower-layer = "0.3.3"
|
||||||
katex = { version = "0.4", default-features = false }
|
katex = { version = "0.4", default-features = false }
|
||||||
|
include_dir = "0.7.4"
|
||||||
|
markdown-it-block-spoiler = "1.0.0"
|
||||||
|
markdown-it-heading-anchors = "0.3.0"
|
||||||
|
markdown-it-footnote = "0.2.0"
|
||||||
|
markdown-it-sub = "1.0.0"
|
||||||
|
markdown-it-sup = "1.0.0"
|
||||||
|
leptos-use = "0.13.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "1.4.1"
|
pretty_assertions = "1.4.1"
|
||||||
|
|
||||||
[package.metadata.leptos]
|
[package.metadata.leptos]
|
||||||
output-name = "ibis"
|
output-name = "ibis"
|
||||||
|
assets-dir = "assets"
|
||||||
bin-features = ["ssr"]
|
bin-features = ["ssr"]
|
||||||
lib-features = ["csr"]
|
lib-features = ["hydrate"]
|
||||||
|
lib-profile-release = "wasm-release"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "ibis_lib"
|
|
||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
# This profile significantly speeds up build time. If debug info is needed you can comment the line
|
|
||||||
# out temporarily, but make sure to leave this in the main branch.
|
|
||||||
[profile.dev]
|
|
||||||
debug = 0
|
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
lto = "thin"
|
|
||||||
strip = true # Automatically strip symbols from the binary.
|
|
||||||
#opt-level = "z" # Optimize for size.
|
|
||||||
|
|
19
README.md
19
README.md
|
@ -7,6 +7,13 @@ The project uses the same technology as [Lemmy](https://join-lemmy.org/) and ben
|
||||||
|
|
||||||
Read the [Project Announcement](https://ibis.wiki/article/Announcing_Ibis,_the_federated_Wikipedia_Alternative) for more information.
|
Read the [Project Announcement](https://ibis.wiki/article/Announcing_Ibis,_the_federated_Wikipedia_Alternative) for more information.
|
||||||
|
|
||||||
|
## Community
|
||||||
|
|
||||||
|
Discuss with other Ibis users on Matrix or Lemmy:
|
||||||
|
|
||||||
|
- [Matrix](https://matrix.to/#/#ibis:matrix.org)
|
||||||
|
- [Lemmy](https://lemmy.ml/c/ibis)
|
||||||
|
|
||||||
## Useful links
|
## Useful links
|
||||||
|
|
||||||
- [Usage Instructions](https://ibis.wiki/article/Usage_Instructions)
|
- [Usage Instructions](https://ibis.wiki/article/Usage_Instructions)
|
||||||
|
@ -24,14 +31,22 @@ psql -c "CREATE USER ibis WITH PASSWORD 'ibis' SUPERUSER;" -U postgres
|
||||||
psql -c "CREATE DATABASE ibis WITH OWNER ibis;" -U postgres
|
psql -c "CREATE DATABASE ibis WITH OWNER ibis;" -U postgres
|
||||||
```
|
```
|
||||||
|
|
||||||
You need to install [cargo](https://rustup.rs/), [trunk](https://trunkrs.dev) and [cargo watch](https://github.com/watchexec/cargo-watch). Run `./scripts/watch.sh` which automatically rebuilds the project after changes. Then open the site at [127.0.0.1:8080](http://127.0.0.1:8080/). Then login with user `ibis` and password `ibis`.
|
You need to install [cargo](https://rustup.rs/), and [cargo-leptos](https://github.com/leptos-rs/cargo-leptos). Run `cargo leptos watch` which automatically rebuilds the project after changes. Then open the site at [localhost:3000](http://localhost:3000/). You can login with user `ibis` and password `ibis`.
|
||||||
|
|
||||||
By default the frontend runs on port 8080, which can be changed with env var `TRUNK_SERVE_PORT`. The backend port is 8081 and can be changed with `IBIS_BACKEND_PORT`.
|
By default the frontend runs on port 3000, which can be changed with env var `TRUNK_SERVE_PORT`. The backend port is 8081 and can be changed with `IBIS_BACKEND_PORT`.
|
||||||
|
|
||||||
## Federation
|
## Federation
|
||||||
|
|
||||||
Main objects in terms of federation are the `Instance` and `Article`. Each article belongs to a single origin instance, the one where it was originally created. Articles have a collection of `Edit`s a custom ActivityPub type containing a diff. The text of any article can be built by starting from empty string and applying all associated edits in order. Instances can synchronize their articles with each other, and follow each other to receive updates about articles. Edits are done with diffs which are generated on the backend, and allow for conflict resolution similar to git. Editing also works over federation. In this case an activity `Update/Edit` is sent to the origin instance. If the diff applies cleanly, the origin instance sends the new text in an `Update/Article` activity to its followers. In case there is a conflict, a `Reject` activity is sent back, the editor needs to resolve and resubmit the edit.
|
Main objects in terms of federation are the `Instance` and `Article`. Each article belongs to a single origin instance, the one where it was originally created. Articles have a collection of `Edit`s a custom ActivityPub type containing a diff. The text of any article can be built by starting from empty string and applying all associated edits in order. Instances can synchronize their articles with each other, and follow each other to receive updates about articles. Edits are done with diffs which are generated on the backend, and allow for conflict resolution similar to git. Editing also works over federation. In this case an activity `Update/Edit` is sent to the origin instance. If the diff applies cleanly, the origin instance sends the new text in an `Update/Article` activity to its followers. In case there is a conflict, a `Reject` activity is sent back, the editor needs to resolve and resubmit the edit.
|
||||||
|
|
||||||
|
## Donate
|
||||||
|
|
||||||
|
Developing a project like this takes a significant amount of work. You can help funding it with donations:
|
||||||
|
|
||||||
|
- [Liberapay](https://liberapay.com/Ibis/)
|
||||||
|
- [Bitcoin](bitcoin:bc1q6mqlqc84q2h55jkkjvex4kc6h9h534rj87rv2l)
|
||||||
|
- [Monero](monero:84xnACZv82UNTEGNkttLTH8sCeV9Cdr8dHMJSNP6V2hEJW7C17S9xQTUCghwG8TePrRD9wfiPRWcwYvSTHUNoyJ4AXnQYLD)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[AGPL](LICENSE)
|
[AGPL](LICENSE)
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
[build]
|
|
||||||
filehash = false
|
|
||||||
target = "assets/index.html"
|
|
||||||
dist = "assets/dist"
|
|
||||||
minify = "on_release"
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -5,8 +5,12 @@
|
||||||
href=".."
|
href=".."
|
||||||
data-bin="ibis"
|
data-bin="ibis"
|
||||||
data-cargo-no-default-features
|
data-cargo-no-default-features
|
||||||
|
<<<<<<< HEAD
|
||||||
data-cargo-features="csr,hydrate" />
|
data-cargo-features="csr,hydrate" />
|
||||||
<link data-trunk rel="tailwind-css" href="/daisyui.css" />
|
<link data-trunk rel="tailwind-css" href="/daisyui.css" />
|
||||||
|
=======
|
||||||
|
data-cargo-features="hydrate" />
|
||||||
|
>>>>>>> master
|
||||||
</head>
|
</head>
|
||||||
<body></body>
|
<body></body>
|
||||||
</html>
|
</html>
|
85
assets/tailwind.js
Normal file
85
assets/tailwind.js
Normal file
File diff suppressed because one or more lines are too long
20
build.rs
20
build.rs
|
@ -1,20 +0,0 @@
|
||||||
use std::{
|
|
||||||
fs::{create_dir_all, File},
|
|
||||||
io::Result,
|
|
||||||
path::Path,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Create placeholders for wasm files so that `cargo check` etc work without explicitly building
|
|
||||||
/// frontend.
|
|
||||||
fn main() -> Result<()> {
|
|
||||||
create_dir_all("assets/dist/")?;
|
|
||||||
let js = "assets/dist/ibis.js";
|
|
||||||
if !Path::new(js).exists() {
|
|
||||||
File::create(js)?;
|
|
||||||
}
|
|
||||||
let wasm = "assets/dist/ibis_bg.wasm";
|
|
||||||
if !Path::new(wasm).exists() {
|
|
||||||
File::create(wasm)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,6 +1,3 @@
|
||||||
# Address where ibis should listen for incoming requests
|
|
||||||
bind = "127.0.0.1:8081"
|
|
||||||
|
|
||||||
# Whether users can create new accounts
|
# Whether users can create new accounts
|
||||||
registration_open = true
|
registration_open = true
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
CARGO_TARGET_DIR=target/frontend trunk build --release
|
cargo leptos build --release
|
||||||
cargo build --release
|
|
||||||
gzip target/release/ibis -c > ibis.gz
|
gzip target/release/ibis -c > ibis.gz
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
|
|
||||||
IBIS__BIND="${IBIS_BIND:-"127.0.0.1:8081"}"
|
|
||||||
|
|
||||||
killall trunk || true
|
|
||||||
|
|
||||||
# run processes in parallel
|
|
||||||
# https://stackoverflow.com/a/52033580
|
|
||||||
(trap 'kill 0' INT;
|
|
||||||
# start frontend
|
|
||||||
CARGO_TARGET_DIR=target/frontend trunk serve -w src/frontend/ -w assets/ --proxy-backend http://$IBIS__BIND &
|
|
||||||
# start backend, with separate target folder to avoid rebuilds from arch change
|
|
||||||
cargo watch --ignore assets/ibis.css --exec run
|
|
||||||
)
|
|
|
@ -1,91 +1,61 @@
|
||||||
use super::error::MyResult;
|
use crate::frontend::app::App;
|
||||||
use anyhow::anyhow;
|
|
||||||
use axum::{
|
use axum::{
|
||||||
body::Body,
|
body::Body,
|
||||||
extract::Path,
|
extract::{Request, State},
|
||||||
|
http::StatusCode,
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
routing::get,
|
|
||||||
Router,
|
|
||||||
};
|
};
|
||||||
use axum_macros::debug_handler;
|
use axum_macros::debug_handler;
|
||||||
use once_cell::sync::OnceCell;
|
use leptos::LeptosOptions;
|
||||||
use reqwest::header::HeaderMap;
|
use tower::ServiceExt;
|
||||||
use std::fs::read_to_string;
|
use tower_http::services::ServeDir;
|
||||||
|
|
||||||
pub fn asset_routes() -> MyResult<Router<()>> {
|
// from https://github.com/leptos-rs/start-axum
|
||||||
Ok(Router::new()
|
|
||||||
.route("/assets/ibis.css", get(ibis_css))
|
|
||||||
.route(
|
|
||||||
"/assets/simple.css",
|
|
||||||
get((css_headers(), include_str!("../../assets/simple.css"))),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/assets/daisyui.css",
|
|
||||||
get((css_headers(), include_str!("../../assets/daisyui.css"))),
|
|
||||||
)
|
|
||||||
.route(
|
|
||||||
"/assets/katex.min.css",
|
|
||||||
get((css_headers(), include_str!("../../assets/katex.min.css"))),
|
|
||||||
)
|
|
||||||
.route("/assets/fonts/*font", get(get_font))
|
|
||||||
.route(
|
|
||||||
"/assets/index.html",
|
|
||||||
get(include_str!("../../assets/index.html")),
|
|
||||||
)
|
|
||||||
.route("/pkg/ibis.js", get(serve_js))
|
|
||||||
.route("/pkg/ibis_bg.wasm", get(serve_wasm)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn css_headers() -> HeaderMap {
|
#[debug_handler]
|
||||||
static INSTANCE: OnceCell<HeaderMap> = OnceCell::new();
|
pub async fn file_and_error_handler(
|
||||||
INSTANCE
|
State(options): State<LeptosOptions>,
|
||||||
.get_or_init(|| {
|
req: Request<Body>,
|
||||||
let mut css_headers = HeaderMap::new();
|
) -> Result<Response<Body>, (StatusCode, String)> {
|
||||||
let val = "text/css".parse().expect("valid header value");
|
let root = options.site_root.clone();
|
||||||
css_headers.insert("Content-Type", val);
|
let (parts, body) = req.into_parts();
|
||||||
css_headers
|
|
||||||
})
|
|
||||||
.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn ibis_css() -> MyResult<(HeaderMap, Response<Body>)> {
|
let mut static_parts = parts.clone();
|
||||||
let res = if cfg!(debug_assertions) {
|
static_parts.headers.clear();
|
||||||
read_to_string("assets/ibis.css")?.into_response()
|
if let Some(encodings) = parts.headers.get("accept-encoding") {
|
||||||
|
static_parts
|
||||||
|
.headers
|
||||||
|
.insert("accept-encoding", encodings.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = get_static_file(Request::from_parts(static_parts, Body::empty()), &root).await?;
|
||||||
|
|
||||||
|
if res.status() == StatusCode::OK {
|
||||||
|
Ok(res.into_response())
|
||||||
} else {
|
} else {
|
||||||
include_str!("../../assets/ibis.css").into_response()
|
let handler = leptos_axum::render_app_to_stream(options.to_owned(), App);
|
||||||
};
|
Ok(handler(Request::from_parts(parts, body))
|
||||||
Ok((css_headers(), res))
|
.await
|
||||||
|
.into_response())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_handler]
|
async fn get_static_file(
|
||||||
async fn serve_js() -> MyResult<impl IntoResponse> {
|
request: Request<Body>,
|
||||||
let mut headers = HeaderMap::new();
|
root: &str,
|
||||||
headers.insert("Content-Type", "application/javascript".parse()?);
|
) -> Result<Response<Body>, (StatusCode, String)> {
|
||||||
let content = include_str!("../../assets/dist/ibis.js");
|
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
|
||||||
Ok((headers, content))
|
// This path is relative to the cargo root
|
||||||
}
|
match ServeDir::new(root)
|
||||||
|
.precompressed_gzip()
|
||||||
#[debug_handler]
|
.precompressed_br()
|
||||||
async fn serve_wasm() -> MyResult<impl IntoResponse> {
|
.oneshot(request)
|
||||||
let mut headers = HeaderMap::new();
|
.await
|
||||||
headers.insert("Content-Type", "application/wasm".parse()?);
|
{
|
||||||
let content = include_bytes!("../../assets/dist/ibis_bg.wasm");
|
Ok(res) => Ok(res.into_response()),
|
||||||
Ok((headers, content))
|
Err(err) => Err((
|
||||||
}
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
format!("Error serving files: {err}"),
|
||||||
#[debug_handler]
|
)),
|
||||||
async fn get_font(Path(font): Path<String>) -> MyResult<impl IntoResponse> {
|
}
|
||||||
let mut headers = HeaderMap::new();
|
|
||||||
let content_type = if font.ends_with(".ttf") {
|
|
||||||
"font/ttf"
|
|
||||||
} else if font.ends_with(".woff") {
|
|
||||||
"font/woff"
|
|
||||||
} else if font.ends_with(".woff2") {
|
|
||||||
"font/woff2"
|
|
||||||
} else {
|
|
||||||
return Err(anyhow!("invalid font").into());
|
|
||||||
};
|
|
||||||
headers.insert("Content-type", content_type.parse()?);
|
|
||||||
let content = std::fs::read("assets/fonts/".to_owned() + &font)?;
|
|
||||||
Ok((headers, content))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,11 @@ use config::Config;
|
||||||
use doku::Document;
|
use doku::Document;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use smart_default::SmartDefault;
|
use smart_default::SmartDefault;
|
||||||
use std::net::SocketAddr;
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Document, SmartDefault)]
|
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Document, SmartDefault)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct IbisConfig {
|
pub struct IbisConfig {
|
||||||
/// Address where ibis should listen for incoming requests
|
|
||||||
#[default("127.0.0.1:8081".parse().expect("parse config bind"))]
|
|
||||||
#[doku(as = "String", example = "127.0.0.1:8081")]
|
|
||||||
pub bind: SocketAddr,
|
|
||||||
/// Details about the PostgreSQL database connection
|
/// Details about the PostgreSQL database connection
|
||||||
pub database: IbisConfigDatabase,
|
pub database: IbisConfigDatabase,
|
||||||
/// Whether users can create new accounts
|
/// Whether users can create new accounts
|
||||||
|
@ -37,6 +33,7 @@ impl IbisConfig {
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Document, SmartDefault)]
|
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Document, SmartDefault)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct IbisConfigDatabase {
|
pub struct IbisConfigDatabase {
|
||||||
/// Database connection url
|
/// Database connection url
|
||||||
#[default("postgres://ibis:password@localhost:5432/ibis")]
|
#[default("postgres://ibis:password@localhost:5432/ibis")]
|
||||||
|
@ -50,6 +47,7 @@ pub struct IbisConfigDatabase {
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Document, SmartDefault)]
|
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Document, SmartDefault)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct IbisConfigSetup {
|
pub struct IbisConfigSetup {
|
||||||
#[default("ibis")]
|
#[default("ibis")]
|
||||||
#[doku(example = "ibis")]
|
#[doku(example = "ibis")]
|
||||||
|
@ -61,6 +59,7 @@ pub struct IbisConfigSetup {
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Document, SmartDefault)]
|
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Document, SmartDefault)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct IbisConfigFederation {
|
pub struct IbisConfigFederation {
|
||||||
/// Domain name of the instance, mandatory for federation
|
/// Domain name of the instance, mandatory for federation
|
||||||
#[default("example.com")]
|
#[default("example.com")]
|
||||||
|
|
|
@ -22,7 +22,7 @@ use activitypub_federation::{
|
||||||
http_signatures::generate_actor_keypair,
|
http_signatures::generate_actor_keypair,
|
||||||
};
|
};
|
||||||
use api::api_routes;
|
use api::api_routes;
|
||||||
use assets::asset_routes;
|
use assets::file_and_error_handler;
|
||||||
use axum::{
|
use axum::{
|
||||||
body::Body,
|
body::Body,
|
||||||
http::{HeaderValue, Request},
|
http::{HeaderValue, Request},
|
||||||
|
@ -38,9 +38,10 @@ use diesel::{
|
||||||
PgConnection,
|
PgConnection,
|
||||||
};
|
};
|
||||||
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
|
use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
|
||||||
use leptos::leptos_config::get_config_from_str;
|
use leptos::get_configuration;
|
||||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use std::net::SocketAddr;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tower_http::cors::CorsLayer;
|
use tower_http::cors::CorsLayer;
|
||||||
use tower_layer::Layer;
|
use tower_layer::Layer;
|
||||||
|
@ -58,7 +59,7 @@ const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");
|
||||||
|
|
||||||
const FEDERATION_ROUTES_PREFIX: &str = "/federation_routes";
|
const FEDERATION_ROUTES_PREFIX: &str = "/federation_routes";
|
||||||
|
|
||||||
pub async fn start(config: IbisConfig) -> MyResult<()> {
|
pub async fn start(config: IbisConfig, override_hostname: Option<SocketAddr>) -> MyResult<()> {
|
||||||
let manager = ConnectionManager::<PgConnection>::new(&config.database.connection_url);
|
let manager = ConnectionManager::<PgConnection>::new(&config.database.connection_url);
|
||||||
let db_pool = Pool::builder()
|
let db_pool = Pool::builder()
|
||||||
.max_size(config.database.pool_size)
|
.max_size(config.database.pool_size)
|
||||||
|
@ -82,15 +83,18 @@ pub async fn start(config: IbisConfig) -> MyResult<()> {
|
||||||
setup(&data.to_request_data()).await?;
|
setup(&data.to_request_data()).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut conf = get_config_from_str(include_str!("../../Cargo.toml"))?;
|
let leptos_options = get_configuration(Some("Cargo.toml")).await?.leptos_options;
|
||||||
conf.site_addr = data.config.bind;
|
let mut addr = leptos_options.site_addr;
|
||||||
|
if let Some(override_hostname) = override_hostname {
|
||||||
|
addr = override_hostname;
|
||||||
|
}
|
||||||
let routes = generate_route_list(App);
|
let routes = generate_route_list(App);
|
||||||
|
|
||||||
let config = data.clone();
|
let config = data.clone();
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.leptos_routes(&conf, routes, App)
|
.leptos_routes(&leptos_options, routes, App)
|
||||||
.with_state(conf)
|
.fallback(file_and_error_handler)
|
||||||
.nest("", asset_routes()?)
|
.with_state(leptos_options)
|
||||||
.nest(FEDERATION_ROUTES_PREFIX, federation_routes())
|
.nest(FEDERATION_ROUTES_PREFIX, federation_routes())
|
||||||
.nest("/api/v1", api_routes())
|
.nest("/api/v1", api_routes())
|
||||||
.nest("", nodeinfo::config())
|
.nest("", nodeinfo::config())
|
||||||
|
@ -102,8 +106,8 @@ pub async fn start(config: IbisConfig) -> MyResult<()> {
|
||||||
let middleware = axum::middleware::from_fn(federation_routes_middleware);
|
let middleware = axum::middleware::from_fn(federation_routes_middleware);
|
||||||
let app_with_middleware = middleware.layer(app);
|
let app_with_middleware = middleware.layer(app);
|
||||||
|
|
||||||
info!("Listening on {}", &data.config.bind);
|
info!("Listening on {}", &addr);
|
||||||
let listener = TcpListener::bind(&data.config.bind).await?;
|
let listener = TcpListener::bind(&addr).await?;
|
||||||
axum::serve(listener, app_with_middleware.into_make_service()).await?;
|
axum::serve(listener, app_with_middleware.into_make_service()).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -47,10 +47,9 @@ impl ApiClient {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
{
|
{
|
||||||
hostname = crate::backend::config::IbisConfig::read()
|
use leptos::leptos_config::get_config_from_str;
|
||||||
.unwrap()
|
let leptos_options = get_config_from_str(include_str!("../../Cargo.toml")).unwrap();
|
||||||
.bind
|
hostname = leptos_options.site_addr.to_string();
|
||||||
.to_string();
|
|
||||||
ssl = false;
|
ssl = false;
|
||||||
}
|
}
|
||||||
// required for tests
|
// required for tests
|
||||||
|
|
|
@ -91,10 +91,10 @@ pub fn App() -> impl IntoView {
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<>
|
<>
|
||||||
<Stylesheet id="daisyui" href="/assets/daisyui.css" />
|
<Stylesheet id="daisyui" href="/daisyui.css" />
|
||||||
<Stylesheet id="ibis" href="/assets/ibis.css" />
|
<Stylesheet id="ibis" href="/ibis.css" />
|
||||||
<Stylesheet id="katex" href="/assets/katex.min.css" />
|
<Stylesheet id="katex" href="/katex.min.css" />
|
||||||
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio,container-queries"></script>
|
<script src="/tailwind.js"></script>
|
||||||
<Router>
|
<Router>
|
||||||
<Nav />
|
<Nav />
|
||||||
<main>
|
<main>
|
||||||
|
|
|
@ -29,10 +29,14 @@ pub fn render_markdown(text: &str) -> String {
|
||||||
fn markdown_parser() -> MarkdownIt {
|
fn markdown_parser() -> MarkdownIt {
|
||||||
let mut parser = MarkdownIt::new();
|
let mut parser = MarkdownIt::new();
|
||||||
markdown_it::plugins::cmark::add(&mut parser);
|
markdown_it::plugins::cmark::add(&mut parser);
|
||||||
markdown_it::plugins::extra::linkify::add(&mut parser);
|
markdown_it_heading_anchors::add(&mut parser);
|
||||||
|
markdown_it_footnote::add(&mut parser);
|
||||||
markdown_it::plugins::extra::strikethrough::add(&mut parser);
|
markdown_it::plugins::extra::strikethrough::add(&mut parser);
|
||||||
markdown_it::plugins::extra::tables::add(&mut parser);
|
markdown_it::plugins::extra::tables::add(&mut parser);
|
||||||
markdown_it::plugins::extra::typographer::add(&mut parser);
|
markdown_it::plugins::extra::typographer::add(&mut parser);
|
||||||
|
markdown_it_block_spoiler::add(&mut parser);
|
||||||
|
markdown_it_sub::add(&mut parser);
|
||||||
|
markdown_it_sup::add(&mut parser);
|
||||||
parser.inline.add_rule::<ArticleLinkScanner>();
|
parser.inline.add_rule::<ArticleLinkScanner>();
|
||||||
parser.inline.add_rule::<MathEquationScanner>();
|
parser.inline.add_rule::<MathEquationScanner>();
|
||||||
parser
|
parser
|
||||||
|
@ -115,7 +119,7 @@ impl InlineRule for MathEquationScanner {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let mut display_mode = false;
|
let mut display_mode = false;
|
||||||
if input.starts_with("$$\n") {
|
if input.starts_with("$$\n") || input.starts_with("$$ ") {
|
||||||
display_mode = true;
|
display_mode = true;
|
||||||
}
|
}
|
||||||
const SEPARATOR_LENGTH: usize = 2;
|
const SEPARATOR_LENGTH: usize = 2;
|
||||||
|
|
|
@ -11,7 +11,17 @@ pub mod pages;
|
||||||
|
|
||||||
#[cfg(feature = "hydrate")]
|
#[cfg(feature = "hydrate")]
|
||||||
#[wasm_bindgen::prelude::wasm_bindgen]
|
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||||
pub fn hydrate() {}
|
pub fn hydrate() {
|
||||||
|
use crate::frontend::app::App;
|
||||||
|
console_error_panic_hook::set_once();
|
||||||
|
leptos::mount_to_body(App);
|
||||||
|
|
||||||
|
// set theme
|
||||||
|
// https://daisyui.com/docs/themes/
|
||||||
|
let document = web_sys::window().unwrap().document().unwrap();
|
||||||
|
let html_element = document.document_element().unwrap();
|
||||||
|
html_element.set_attribute("data-theme", "emerald").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
fn article_link(article: &DbArticle) -> String {
|
fn article_link(article: &DbArticle) -> String {
|
||||||
if article.local {
|
if article.local {
|
||||||
|
|
|
@ -1,12 +1,24 @@
|
||||||
use crate::{common::CreateArticleForm, frontend::app::GlobalState};
|
use crate::{
|
||||||
|
common::CreateArticleForm,
|
||||||
|
frontend::{app::GlobalState, markdown::render_markdown},
|
||||||
|
};
|
||||||
|
use html::Textarea;
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use leptos_router::Redirect;
|
use leptos_router::Redirect;
|
||||||
|
use leptos_use::{use_textarea_autosize, UseTextareaAutosizeReturn};
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn CreateArticle() -> impl IntoView {
|
pub fn CreateArticle() -> impl IntoView {
|
||||||
let (title, set_title) = create_signal(String::new());
|
let (title, set_title) = create_signal(String::new());
|
||||||
let (text, set_text) = create_signal(String::new());
|
let textarea = create_node_ref::<Textarea>();
|
||||||
|
let UseTextareaAutosizeReturn {
|
||||||
|
content,
|
||||||
|
set_content,
|
||||||
|
trigger_resize: _,
|
||||||
|
} = use_textarea_autosize(textarea);
|
||||||
let (summary, set_summary) = create_signal(String::new());
|
let (summary, set_summary) = create_signal(String::new());
|
||||||
|
let (show_preview, set_show_preview) = create_signal(false);
|
||||||
|
let (preview, set_preview) = create_signal(String::new());
|
||||||
let (create_response, set_create_response) = create_signal(None::<()>);
|
let (create_response, set_create_response) = create_signal(None::<()>);
|
||||||
let (create_error, set_create_error) = create_signal(None::<String>);
|
let (create_error, set_create_error) = create_signal(None::<String>);
|
||||||
let (wait_for_response, set_wait_for_response) = create_signal(false);
|
let (wait_for_response, set_wait_for_response) = create_signal(false);
|
||||||
|
@ -58,12 +70,21 @@ pub fn CreateArticle() -> impl IntoView {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
|
value=content
|
||||||
placeholder="Article text..."
|
placeholder="Article text..."
|
||||||
on:keyup=move |ev| {
|
on:input=move |evt| {
|
||||||
let val = event_target_value(&ev);
|
let val = event_target_value(&evt);
|
||||||
set_text.update(|p| *p = val);
|
set_preview.set(render_markdown(&val));
|
||||||
|
set_content.set(val);
|
||||||
}
|
}
|
||||||
|
node_ref=textarea
|
||||||
></textarea>
|
></textarea>
|
||||||
|
<button on:click=move |_| {
|
||||||
|
set_show_preview.update(|s| *s = !*s)
|
||||||
|
}>Preview</button>
|
||||||
|
<Show when=move || { show_preview.get() }>
|
||||||
|
<div id="preview" inner_html=move || preview.get()></div>
|
||||||
|
</Show>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://commonmark.org/help/" target="blank_">
|
<a href="https://commonmark.org/help/" target="blank_">
|
||||||
Markdown
|
Markdown
|
||||||
|
@ -90,7 +111,7 @@ pub fn CreateArticle() -> impl IntoView {
|
||||||
<button
|
<button
|
||||||
prop:disabled=move || button_is_disabled.get()
|
prop:disabled=move || button_is_disabled.get()
|
||||||
on:click=move |_| {
|
on:click=move |_| {
|
||||||
submit_action.dispatch((title.get(), text.get(), summary.get()))
|
submit_action.dispatch((title.get(), content.get(), summary.get()))
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Submit
|
Submit
|
||||||
|
|
|
@ -7,8 +7,10 @@ use crate::{
|
||||||
pages::article_resource,
|
pages::article_resource,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use html::Textarea;
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use leptos_router::use_params_map;
|
use leptos_router::use_params_map;
|
||||||
|
use leptos_use::{use_textarea_autosize, UseTextareaAutosizeReturn};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
enum EditResponse {
|
enum EditResponse {
|
||||||
|
@ -44,7 +46,12 @@ pub fn EditArticle() -> impl IntoView {
|
||||||
.dispatch(conflict_id);
|
.dispatch(conflict_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (text, set_text) = create_signal(String::new());
|
let textarea = create_node_ref::<Textarea>();
|
||||||
|
let UseTextareaAutosizeReturn {
|
||||||
|
content,
|
||||||
|
set_content,
|
||||||
|
trigger_resize: _,
|
||||||
|
} = use_textarea_autosize(textarea);
|
||||||
let (summary, set_summary) = create_signal(String::new());
|
let (summary, set_summary) = create_signal(String::new());
|
||||||
let (show_preview, set_show_preview) = create_signal(false);
|
let (show_preview, set_show_preview) = create_signal(false);
|
||||||
let (preview, set_preview) = create_signal(String::new());
|
let (preview, set_preview) = create_signal(String::new());
|
||||||
|
@ -118,10 +125,9 @@ pub fn EditArticle() -> impl IntoView {
|
||||||
article.article.text = conflict.three_way_merge;
|
article.article.text = conflict.three_way_merge;
|
||||||
set_summary.set(conflict.summary);
|
set_summary.set(conflict.summary);
|
||||||
}
|
}
|
||||||
set_text.set(article.article.text.clone());
|
set_content.set(article.article.text.clone());
|
||||||
set_preview.set(render_markdown(&article.article.text));
|
set_preview.set(render_markdown(&article.article.text));
|
||||||
let article_ = article.clone();
|
let article_ = article.clone();
|
||||||
let rows = article.article.text.lines().count() + 1;
|
|
||||||
view! {
|
view! {
|
||||||
// set initial text, otherwise submit with no changes results in empty text
|
// set initial text, otherwise submit with no changes results in empty text
|
||||||
<div>
|
<div>
|
||||||
|
@ -133,14 +139,15 @@ pub fn EditArticle() -> impl IntoView {
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
<textarea
|
<textarea
|
||||||
|
value=content
|
||||||
id="edit-article-textarea"
|
id="edit-article-textarea"
|
||||||
class="textarea textarea-bordered textarea-primary min-w-full"
|
class="textarea textarea-bordered textarea-primary min-w-full"
|
||||||
rows=rows
|
on:input=move |evt| {
|
||||||
on:keyup=move |ev| {
|
let val = event_target_value(&evt);
|
||||||
let val = event_target_value(&ev);
|
|
||||||
set_preview.set(render_markdown(&val));
|
set_preview.set(render_markdown(&val));
|
||||||
set_text.set(val);
|
set_content.set(val);
|
||||||
}
|
}
|
||||||
|
node_ref=textarea
|
||||||
>
|
>
|
||||||
{article.article.text.clone()}
|
{article.article.text.clone()}
|
||||||
</textarea>
|
</textarea>
|
||||||
|
@ -174,7 +181,7 @@ pub fn EditArticle() -> impl IntoView {
|
||||||
on:click=move |_| {
|
on:click=move |_| {
|
||||||
submit_action
|
submit_action
|
||||||
.dispatch((
|
.dispatch((
|
||||||
text.get(),
|
content.get(),
|
||||||
summary.get(),
|
summary.get(),
|
||||||
article_.clone(),
|
article_.clone(),
|
||||||
edit_response.get(),
|
edit_response.get(),
|
||||||
|
|
24
src/main.rs
24
src/main.rs
|
@ -1,7 +1,7 @@
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
pub async fn main() -> ibis_lib::backend::error::MyResult<()> {
|
pub async fn main() -> ibis::backend::error::MyResult<()> {
|
||||||
use ibis_lib::backend::config::IbisConfig;
|
use ibis::backend::config::IbisConfig;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
|
|
||||||
if std::env::args().collect::<Vec<_>>().get(1) == Some(&"--print-config".to_string()) {
|
if std::env::args().collect::<Vec<_>>().get(1) == Some(&"--print-config".to_string()) {
|
||||||
|
@ -16,24 +16,6 @@ pub async fn main() -> ibis_lib::backend::error::MyResult<()> {
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let ibis_config = IbisConfig::read()?;
|
let ibis_config = IbisConfig::read()?;
|
||||||
ibis_lib::backend::start(ibis_config).await?;
|
ibis::backend::start(ibis_config, None).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "ssr"))]
|
|
||||||
fn main() {
|
|
||||||
use ibis_lib::frontend::app::App;
|
|
||||||
use leptos::{mount_to_body, view};
|
|
||||||
|
|
||||||
_ = console_log::init_with_level(log::Level::Debug);
|
|
||||||
console_error_panic_hook::set_once();
|
|
||||||
mount_to_body(|| {
|
|
||||||
view! { <App /> }
|
|
||||||
});
|
|
||||||
|
|
||||||
// set theme
|
|
||||||
// https://daisyui.com/docs/themes/
|
|
||||||
let document = web_sys::window().unwrap().document().unwrap();
|
|
||||||
let html_element = document.document_element().unwrap();
|
|
||||||
html_element.set_attribute("data-theme", "emerald").unwrap();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![allow(clippy::unwrap_used)]
|
#![allow(clippy::unwrap_used)]
|
||||||
|
|
||||||
use ibis_lib::{
|
use ibis::{
|
||||||
backend::{
|
backend::{
|
||||||
config::{IbisConfig, IbisConfigDatabase, IbisConfigFederation},
|
config::{IbisConfig, IbisConfigDatabase, IbisConfigFederation},
|
||||||
start,
|
start,
|
||||||
|
@ -21,7 +21,7 @@ use std::{
|
||||||
thread::{sleep, spawn},
|
thread::{sleep, spawn},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use tokio::task::JoinHandle;
|
use tokio::{join, task::JoinHandle};
|
||||||
use tracing::log::LevelFilter;
|
use tracing::log::LevelFilter;
|
||||||
|
|
||||||
pub struct TestData {
|
pub struct TestData {
|
||||||
|
@ -66,11 +66,13 @@ impl TestData {
|
||||||
j.join().unwrap();
|
j.join().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
let (alpha, beta, gamma) = join!(
|
||||||
alpha: IbisInstance::start(alpha_db_path, port_alpha, "alpha").await,
|
IbisInstance::start(alpha_db_path, port_alpha, "alpha"),
|
||||||
beta: IbisInstance::start(beta_db_path, port_beta, "beta").await,
|
IbisInstance::start(beta_db_path, port_beta, "beta"),
|
||||||
gamma: IbisInstance::start(gamma_db_path, port_gamma, "gamma").await,
|
IbisInstance::start(gamma_db_path, port_gamma, "gamma")
|
||||||
}
|
);
|
||||||
|
|
||||||
|
Self { alpha, beta, gamma }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop(self) -> MyResult<()> {
|
pub fn stop(self) -> MyResult<()> {
|
||||||
|
@ -115,23 +117,26 @@ impl IbisInstance {
|
||||||
|
|
||||||
async fn start(db_path: String, port: i32, username: &str) -> Self {
|
async fn start(db_path: String, port: i32, username: &str) -> Self {
|
||||||
let connection_url = format!("postgresql://ibis:password@/ibis?host={db_path}");
|
let connection_url = format!("postgresql://ibis:password@/ibis?host={db_path}");
|
||||||
let hostname = format!("localhost:{port}");
|
let hostname = format!("127.0.0.1:{port}");
|
||||||
let bind = format!("127.0.0.1:{port}").parse().unwrap();
|
let domain = format!("localhost:{port}");
|
||||||
let config = IbisConfig {
|
let config = IbisConfig {
|
||||||
bind,
|
|
||||||
database: IbisConfigDatabase {
|
database: IbisConfigDatabase {
|
||||||
connection_url,
|
connection_url,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
registration_open: true,
|
registration_open: true,
|
||||||
federation: IbisConfigFederation {
|
federation: IbisConfigFederation {
|
||||||
domain: hostname.clone(),
|
domain: domain.clone(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
let client = ClientBuilder::new().cookie_store(true).build().unwrap();
|
||||||
|
let api_client = ApiClient::new(client, Some(domain));
|
||||||
let handle = tokio::task::spawn(async move {
|
let handle = tokio::task::spawn(async move {
|
||||||
start(config).await.unwrap();
|
start(config, Some(hostname.parse().unwrap()))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
});
|
});
|
||||||
// wait a moment for the backend to start
|
// wait a moment for the backend to start
|
||||||
tokio::time::sleep(Duration::from_millis(5000)).await;
|
tokio::time::sleep(Duration::from_millis(5000)).await;
|
||||||
|
@ -139,8 +144,6 @@ impl IbisInstance {
|
||||||
username: username.to_string(),
|
username: username.to_string(),
|
||||||
password: "hunter2".to_string(),
|
password: "hunter2".to_string(),
|
||||||
};
|
};
|
||||||
let client = ClientBuilder::new().cookie_store(true).build().unwrap();
|
|
||||||
let api_client = ApiClient::new(client, Some(hostname));
|
|
||||||
api_client.register(form).await.unwrap();
|
api_client.register(form).await.unwrap();
|
||||||
Self {
|
Self {
|
||||||
api_client,
|
api_client,
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
#![allow(clippy::unwrap_used)]
|
#![allow(clippy::unwrap_used)]
|
||||||
|
|
||||||
extern crate ibis_lib;
|
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
use crate::common::{TestData, TEST_ARTICLE_DEFAULT_TEXT};
|
use crate::common::{TestData, TEST_ARTICLE_DEFAULT_TEXT};
|
||||||
use ibis_lib::{
|
use ibis::{
|
||||||
common::{
|
common::{
|
||||||
utils::extract_domain,
|
utils::extract_domain,
|
||||||
ArticleView,
|
ArticleView,
|
||||||
|
|
Loading…
Reference in a new issue