1
0
Fork 0
mirror of https://github.com/Nutomic/ibis.git synced 2024-11-22 01:31:09 +00:00

Merge branch 'master' into tailwind-css

This commit is contained in:
Felix Ableitner 2024-10-29 15:21:02 +01:00
commit b7e490be9e
63 changed files with 977 additions and 803 deletions

View file

@ -1,7 +1,7 @@
variables:
- &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_trunk "cargo-binstall -y trunk@0.21.1"
- &install_cargo_leptos "cargo-binstall -y cargo-leptos@0.2.20"
steps:
cargo_fmt:
@ -50,14 +50,6 @@ steps:
- diesel print-schema --config-file=diesel.toml > tmp.schema
- 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:
image: *rust_image
environment:
@ -89,7 +81,7 @@ steps:
commands:
- *install_binstall
- rustup target add wasm32-unknown-unknown
- *install_trunk
- *install_cargo_leptos
- export PATH="$PATH:$(pwd)/.cargo_home/bin/"
- ./scripts/build_release.sh
when:

1252
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
[package]
name = "ibis"
version = "0.1.3"
version = "0.1.4"
edition = "2021"
[features]
@ -18,9 +18,32 @@ ssr = [
"activitypub_federation",
"jsonwebtoken",
"katex/duktape",
"leptos/ssr",
"leptos-use/ssr",
]
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr", "katex/wasm-js"]
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
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]
dbg_macro = "deny"
@ -80,25 +103,23 @@ doku = "0.21.1"
smart-default = "0.7.1"
tower-layer = "0.3.3"
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]
pretty_assertions = "1.4.1"
[package.metadata.leptos]
output-name = "ibis"
assets-dir = "assets"
bin-features = ["ssr"]
lib-features = ["csr"]
lib-features = ["hydrate"]
lib-profile-release = "wasm-release"
[lib]
name = "ibis_lib"
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.

View file

@ -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.
## 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
- [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
```
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
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
[AGPL](LICENSE)

View file

@ -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.

View file

@ -5,8 +5,12 @@
href=".."
data-bin="ibis"
data-cargo-no-default-features
<<<<<<< HEAD
data-cargo-features="csr,hydrate" />
<link data-trunk rel="tailwind-css" href="/daisyui.css" />
=======
data-cargo-features="hydrate" />
>>>>>>> master
</head>
<body></body>
</html>

85
assets/tailwind.js Normal file

File diff suppressed because one or more lines are too long

View file

@ -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(())
}

View file

@ -1,6 +1,3 @@
# Address where ibis should listen for incoming requests
bind = "127.0.0.1:8081"
# Whether users can create new accounts
registration_open = true

View file

@ -1,6 +1,5 @@
#!/bin/sh
set -e
CARGO_TARGET_DIR=target/frontend trunk build --release
cargo build --release
cargo leptos build --release
gzip target/release/ibis -c > ibis.gz

View file

@ -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
)

View file

@ -1,91 +1,61 @@
use super::error::MyResult;
use anyhow::anyhow;
use crate::frontend::app::App;
use axum::{
body::Body,
extract::Path,
extract::{Request, State},
http::StatusCode,
response::{IntoResponse, Response},
routing::get,
Router,
};
use axum_macros::debug_handler;
use once_cell::sync::OnceCell;
use reqwest::header::HeaderMap;
use std::fs::read_to_string;
use leptos::LeptosOptions;
use tower::ServiceExt;
use tower_http::services::ServeDir;
pub fn asset_routes() -> MyResult<Router<()>> {
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)))
}
// from https://github.com/leptos-rs/start-axum
fn css_headers() -> HeaderMap {
static INSTANCE: OnceCell<HeaderMap> = OnceCell::new();
INSTANCE
.get_or_init(|| {
let mut css_headers = HeaderMap::new();
let val = "text/css".parse().expect("valid header value");
css_headers.insert("Content-Type", val);
css_headers
})
.clone()
}
#[debug_handler]
pub async fn file_and_error_handler(
State(options): State<LeptosOptions>,
req: Request<Body>,
) -> Result<Response<Body>, (StatusCode, String)> {
let root = options.site_root.clone();
let (parts, body) = req.into_parts();
async fn ibis_css() -> MyResult<(HeaderMap, Response<Body>)> {
let res = if cfg!(debug_assertions) {
read_to_string("assets/ibis.css")?.into_response()
let mut static_parts = parts.clone();
static_parts.headers.clear();
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 {
include_str!("../../assets/ibis.css").into_response()
};
Ok((css_headers(), res))
let handler = leptos_axum::render_app_to_stream(options.to_owned(), App);
Ok(handler(Request::from_parts(parts, body))
.await
.into_response())
}
}
#[debug_handler]
async fn serve_js() -> MyResult<impl IntoResponse> {
let mut headers = HeaderMap::new();
headers.insert("Content-Type", "application/javascript".parse()?);
let content = include_str!("../../assets/dist/ibis.js");
Ok((headers, content))
}
#[debug_handler]
async fn serve_wasm() -> MyResult<impl IntoResponse> {
let mut headers = HeaderMap::new();
headers.insert("Content-Type", "application/wasm".parse()?);
let content = include_bytes!("../../assets/dist/ibis_bg.wasm");
Ok((headers, content))
}
#[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))
async fn get_static_file(
request: Request<Body>,
root: &str,
) -> Result<Response<Body>, (StatusCode, String)> {
// `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot`
// This path is relative to the cargo root
match ServeDir::new(root)
.precompressed_gzip()
.precompressed_br()
.oneshot(request)
.await
{
Ok(res) => Ok(res.into_response()),
Err(err) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Error serving files: {err}"),
)),
}
}

View file

@ -3,15 +3,11 @@ use config::Config;
use doku::Document;
use serde::Deserialize;
use smart_default::SmartDefault;
use std::net::SocketAddr;
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Document, SmartDefault)]
#[serde(default)]
#[serde(deny_unknown_fields)]
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
pub database: IbisConfigDatabase,
/// Whether users can create new accounts
@ -37,6 +33,7 @@ impl IbisConfig {
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Document, SmartDefault)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct IbisConfigDatabase {
/// Database connection url
#[default("postgres://ibis:password@localhost:5432/ibis")]
@ -50,6 +47,7 @@ pub struct IbisConfigDatabase {
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Document, SmartDefault)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct IbisConfigSetup {
#[default("ibis")]
#[doku(example = "ibis")]
@ -61,6 +59,7 @@ pub struct IbisConfigSetup {
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Document, SmartDefault)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct IbisConfigFederation {
/// Domain name of the instance, mandatory for federation
#[default("example.com")]

View file

@ -22,7 +22,7 @@ use activitypub_federation::{
http_signatures::generate_actor_keypair,
};
use api::api_routes;
use assets::asset_routes;
use assets::file_and_error_handler;
use axum::{
body::Body,
http::{HeaderValue, Request},
@ -38,9 +38,10 @@ use diesel::{
PgConnection,
};
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 log::info;
use std::net::SocketAddr;
use tokio::net::TcpListener;
use tower_http::cors::CorsLayer;
use tower_layer::Layer;
@ -58,7 +59,7 @@ const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");
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 db_pool = Pool::builder()
.max_size(config.database.pool_size)
@ -82,15 +83,18 @@ pub async fn start(config: IbisConfig) -> MyResult<()> {
setup(&data.to_request_data()).await?;
}
let mut conf = get_config_from_str(include_str!("../../Cargo.toml"))?;
conf.site_addr = data.config.bind;
let leptos_options = get_configuration(Some("Cargo.toml")).await?.leptos_options;
let mut addr = leptos_options.site_addr;
if let Some(override_hostname) = override_hostname {
addr = override_hostname;
}
let routes = generate_route_list(App);
let config = data.clone();
let app = Router::new()
.leptos_routes(&conf, routes, App)
.with_state(conf)
.nest("", asset_routes()?)
.leptos_routes(&leptos_options, routes, App)
.fallback(file_and_error_handler)
.with_state(leptos_options)
.nest(FEDERATION_ROUTES_PREFIX, federation_routes())
.nest("/api/v1", api_routes())
.nest("", nodeinfo::config())
@ -102,8 +106,8 @@ pub async fn start(config: IbisConfig) -> MyResult<()> {
let middleware = axum::middleware::from_fn(federation_routes_middleware);
let app_with_middleware = middleware.layer(app);
info!("Listening on {}", &data.config.bind);
let listener = TcpListener::bind(&data.config.bind).await?;
info!("Listening on {}", &addr);
let listener = TcpListener::bind(&addr).await?;
axum::serve(listener, app_with_middleware.into_make_service()).await?;
Ok(())

View file

@ -47,10 +47,9 @@ impl ApiClient {
}
#[cfg(feature = "ssr")]
{
hostname = crate::backend::config::IbisConfig::read()
.unwrap()
.bind
.to_string();
use leptos::leptos_config::get_config_from_str;
let leptos_options = get_config_from_str(include_str!("../../Cargo.toml")).unwrap();
hostname = leptos_options.site_addr.to_string();
ssl = false;
}
// required for tests

View file

@ -91,10 +91,10 @@ pub fn App() -> impl IntoView {
view! {
<>
<Stylesheet id="daisyui" href="/assets/daisyui.css" />
<Stylesheet id="ibis" href="/assets/ibis.css" />
<Stylesheet id="katex" href="/assets/katex.min.css" />
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio,container-queries"></script>
<Stylesheet id="daisyui" href="/daisyui.css" />
<Stylesheet id="ibis" href="/ibis.css" />
<Stylesheet id="katex" href="/katex.min.css" />
<script src="/tailwind.js"></script>
<Router>
<Nav />
<main>

View file

@ -29,10 +29,14 @@ pub fn render_markdown(text: &str) -> String {
fn markdown_parser() -> MarkdownIt {
let mut parser = MarkdownIt::new();
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::tables::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::<MathEquationScanner>();
parser
@ -115,7 +119,7 @@ impl InlineRule for MathEquationScanner {
return None;
}
let mut display_mode = false;
if input.starts_with("$$\n") {
if input.starts_with("$$\n") || input.starts_with("$$ ") {
display_mode = true;
}
const SEPARATOR_LENGTH: usize = 2;

View file

@ -11,7 +11,17 @@ pub mod pages;
#[cfg(feature = "hydrate")]
#[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 {
if article.local {

View file

@ -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_router::Redirect;
use leptos_use::{use_textarea_autosize, UseTextareaAutosizeReturn};
#[component]
pub fn CreateArticle() -> impl IntoView {
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 (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_error, set_create_error) = create_signal(None::<String>);
let (wait_for_response, set_wait_for_response) = create_signal(false);
@ -58,12 +70,21 @@ pub fn CreateArticle() -> impl IntoView {
/>
<textarea
value=content
placeholder="Article text..."
on:keyup=move |ev| {
let val = event_target_value(&ev);
set_text.update(|p| *p = val);
on:input=move |evt| {
let val = event_target_value(&evt);
set_preview.set(render_markdown(&val));
set_content.set(val);
}
node_ref=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>
<a href="https://commonmark.org/help/" target="blank_">
Markdown
@ -90,7 +111,7 @@ pub fn CreateArticle() -> impl IntoView {
<button
prop:disabled=move || button_is_disabled.get()
on:click=move |_| {
submit_action.dispatch((title.get(), text.get(), summary.get()))
submit_action.dispatch((title.get(), content.get(), summary.get()))
}
>
Submit

View file

@ -7,8 +7,10 @@ use crate::{
pages::article_resource,
},
};
use html::Textarea;
use leptos::*;
use leptos_router::use_params_map;
use leptos_use::{use_textarea_autosize, UseTextareaAutosizeReturn};
#[derive(Clone, PartialEq)]
enum EditResponse {
@ -44,7 +46,12 @@ pub fn EditArticle() -> impl IntoView {
.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 (show_preview, set_show_preview) = create_signal(false);
let (preview, set_preview) = create_signal(String::new());
@ -118,10 +125,9 @@ pub fn EditArticle() -> impl IntoView {
article.article.text = conflict.three_way_merge;
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));
let article_ = article.clone();
let rows = article.article.text.lines().count() + 1;
view! {
// set initial text, otherwise submit with no changes results in empty text
<div>
@ -133,14 +139,15 @@ pub fn EditArticle() -> impl IntoView {
})
}}
<textarea
value=content
id="edit-article-textarea"
class="textarea textarea-bordered textarea-primary min-w-full"
rows=rows
on:keyup=move |ev| {
let val = event_target_value(&ev);
on:input=move |evt| {
let val = event_target_value(&evt);
set_preview.set(render_markdown(&val));
set_text.set(val);
set_content.set(val);
}
node_ref=textarea
>
{article.article.text.clone()}
</textarea>
@ -174,7 +181,7 @@ pub fn EditArticle() -> impl IntoView {
on:click=move |_| {
submit_action
.dispatch((
text.get(),
content.get(),
summary.get(),
article_.clone(),
edit_response.get(),

View file

@ -1,7 +1,7 @@
#[cfg(feature = "ssr")]
#[tokio::main]
pub async fn main() -> ibis_lib::backend::error::MyResult<()> {
use ibis_lib::backend::config::IbisConfig;
pub async fn main() -> ibis::backend::error::MyResult<()> {
use ibis::backend::config::IbisConfig;
use log::LevelFilter;
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();
let ibis_config = IbisConfig::read()?;
ibis_lib::backend::start(ibis_config).await?;
ibis::backend::start(ibis_config, None).await?;
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();
}

View file

@ -1,6 +1,6 @@
#![allow(clippy::unwrap_used)]
use ibis_lib::{
use ibis::{
backend::{
config::{IbisConfig, IbisConfigDatabase, IbisConfigFederation},
start,
@ -21,7 +21,7 @@ use std::{
thread::{sleep, spawn},
time::Duration,
};
use tokio::task::JoinHandle;
use tokio::{join, task::JoinHandle};
use tracing::log::LevelFilter;
pub struct TestData {
@ -66,11 +66,13 @@ impl TestData {
j.join().unwrap();
}
Self {
alpha: IbisInstance::start(alpha_db_path, port_alpha, "alpha").await,
beta: IbisInstance::start(beta_db_path, port_beta, "beta").await,
gamma: IbisInstance::start(gamma_db_path, port_gamma, "gamma").await,
}
let (alpha, beta, gamma) = join!(
IbisInstance::start(alpha_db_path, port_alpha, "alpha"),
IbisInstance::start(beta_db_path, port_beta, "beta"),
IbisInstance::start(gamma_db_path, port_gamma, "gamma")
);
Self { alpha, beta, gamma }
}
pub fn stop(self) -> MyResult<()> {
@ -115,23 +117,26 @@ impl IbisInstance {
async fn start(db_path: String, port: i32, username: &str) -> Self {
let connection_url = format!("postgresql://ibis:password@/ibis?host={db_path}");
let hostname = format!("localhost:{port}");
let bind = format!("127.0.0.1:{port}").parse().unwrap();
let hostname = format!("127.0.0.1:{port}");
let domain = format!("localhost:{port}");
let config = IbisConfig {
bind,
database: IbisConfigDatabase {
connection_url,
..Default::default()
},
registration_open: true,
federation: IbisConfigFederation {
domain: hostname.clone(),
domain: domain.clone(),
..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 {
start(config).await.unwrap();
start(config, Some(hostname.parse().unwrap()))
.await
.unwrap();
});
// wait a moment for the backend to start
tokio::time::sleep(Duration::from_millis(5000)).await;
@ -139,8 +144,6 @@ impl IbisInstance {
username: username.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();
Self {
api_client,

View file

@ -1,11 +1,9 @@
#![allow(clippy::unwrap_used)]
extern crate ibis_lib;
mod common;
use crate::common::{TestData, TEST_ARTICLE_DEFAULT_TEXT};
use ibis_lib::{
use ibis::{
common::{
utils::extract_domain,
ArticleView,