Upgrade deps (#60)

* Upgrade dependencies

* fix tests

* ci config
This commit is contained in:
Nutomic 2024-10-02 14:47:44 +02:00 committed by GitHub
parent 706713be9d
commit fdda0f584a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 1689 additions and 1330 deletions

View File

@ -1,5 +1,5 @@
variables: variables:
- &rust_image "rust:1.75" - &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"
steps: steps:
@ -11,6 +11,8 @@ steps:
commands: commands:
- rustup component add rustfmt - rustup component add rustfmt
- cargo +nightly fmt -- --check - cargo +nightly fmt -- --check
when:
- event: pull_request
leptos_fmt: leptos_fmt:
image: *rust_image image: *rust_image

1537
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -26,60 +26,61 @@ dbg_macro = "deny"
unwrap_used = "deny" unwrap_used = "deny"
[dependencies] [dependencies]
activitypub_federation = { version = "0.5.2", features = [ activitypub_federation = { version = "0.6.0-alpha2", features = [
"axum", "axum",
"diesel", "diesel",
], default-features = false, optional = true } ], default-features = false, optional = true }
anyhow = "1.0.75" anyhow = "1.0.89"
async-trait = "0.1.74" async-trait = "0.1.83"
axum = { version = "0.6.20", optional = true } axum = { version = "0.7.7", optional = true }
axum-macros = { version = "0.3.8", optional = true } axum-macros = { version = "0.4.2", optional = true }
axum-extra = { version = "0.7.7", features = ["cookie"], optional = true } axum-extra = { version = "0.9.4", features = ["cookie"], optional = true }
leptos = "0.5.4" leptos = "0.6.15"
leptos_meta = "0.5.4" leptos_meta = "0.6.15"
leptos_router = "0.5.4" leptos_router = "0.6.15"
leptos_axum = { version = "0.5.4", optional = true } leptos_axum = { version = "0.6.15", optional = true }
bcrypt = "0.15.0" bcrypt = "0.15.1"
chrono = { version = "0.4.31", features = ["serde"] } chrono = { version = "0.4.38", features = ["serde"] }
diesel = { version = "2.1.4", features = [ diesel = { version = "2.2.4", features = [
"postgres", "postgres",
"chrono", "chrono",
"uuid", "uuid",
"r2d2", "r2d2",
], optional = true } ], optional = true }
diesel-derive-newtype = { version = "2.1.0", optional = true } diesel-derive-newtype = { version = "2.1.2", optional = true }
diesel_migrations = { version = "2.1.0", optional = true } diesel_migrations = { version = "2.2.0", optional = true }
diffy = "0.3.0" diffy = "0.4.0"
enum_delegate = "0.2.0" enum_delegate = "0.2.0"
env_logger = { version = "0.10.1", default-features = false } env_logger = { version = "0.11.5", default-features = false }
futures = "0.3.29" futures = "0.3.30"
hex = "0.4.3" hex = "0.4.3"
jsonwebtoken = { version = "9.2.0", optional = true } jsonwebtoken = { version = "9.3.0", optional = true }
rand = "0.8.5" rand = "0.8.5"
serde_json = "1.0.108" serde_json = "1.0.128"
sha2 = "0.10.8" sha2 = "0.10.8"
tokio = { version = "1.34.0", features = ["full"], optional = true } tokio = { version = "1.40.0", features = ["full"], optional = true }
uuid = { version = "1.6.1", features = ["serde"] } uuid = { version = "1.10.0", features = ["serde"] }
tower-http = { version = "0.4.0", features = ["cors", "fs"], optional = true } tower-http = { version = "0.6.1", features = ["cors", "fs"], optional = true }
serde = { version = "1.0.192", features = ["derive"] } serde = { version = "1.0.210", features = ["derive"] }
url = { version = "2.4.1", features = ["serde"] } url = { version = "2.5.2", features = ["serde"] }
reqwest = { version = "0.11.22", features = ["json", "cookies"] } reqwest = { version = "0.12.8", features = ["json", "cookies"] }
log = "0.4" log = "0.4"
tracing = "0.1.40" tracing = "0.1.40"
once_cell = "1.18.0" once_cell = "1.20.1"
wasm-bindgen = "0.2.89" wasm-bindgen = "0.2.93"
console_error_panic_hook = "0.1.7" console_error_panic_hook = "0.1.7"
console_log = "1.0.0" console_log = "1.0.0"
time = "0.3.31" time = "0.3.36"
tower = "0.4.13" tower = "0.5.1"
markdown-it = "0.6.0" markdown-it = "0.6.1"
web-sys = "0.3.68" web-sys = "0.3.70"
config = { version = "0.14.0", features = ["toml"] } config = { version = "0.14.0", features = ["toml"] }
doku = "0.21.1" doku = "0.21.1"
smart-default = "0.7.1" smart-default = "0.7.1"
tower-layer = "0.3.3"
[dev-dependencies] [dev-dependencies]
pretty_assertions = "1.4.0" pretty_assertions = "1.4.1"
[package.metadata.leptos] [package.metadata.leptos]
output-name = "ibis" output-name = "ibis"

View File

@ -9,5 +9,5 @@ IBIS__BIND="${IBIS_BIND:-"127.0.0.1:8081"}"
# start frontend # start frontend
CARGO_TARGET_DIR=target/frontend trunk serve -w src/frontend/ --proxy-backend http://$IBIS__BIND & CARGO_TARGET_DIR=target/frontend trunk serve -w src/frontend/ --proxy-backend http://$IBIS__BIND &
# start backend, with separate target folder to avoid rebuilds from arch change # start backend, with separate target folder to avoid rebuilds from arch change
cargo watch -x run bacon -j run
) )

View File

@ -29,6 +29,7 @@ use crate::{
}; };
use activitypub_federation::config::Data; use activitypub_federation::config::Data;
use axum::{ use axum::{
body::Body,
http::{Request, StatusCode}, http::{Request, StatusCode},
middleware::{self, Next}, middleware::{self, Next},
response::Response, response::Response,
@ -45,7 +46,7 @@ pub mod article;
pub mod instance; pub mod instance;
pub mod user; pub mod user;
pub fn api_routes() -> Router { pub fn api_routes() -> Router<()> {
Router::new() Router::new()
.route( .route(
"/article", "/article",
@ -68,11 +69,11 @@ pub fn api_routes() -> Router {
.route_layer(middleware::from_fn(auth)) .route_layer(middleware::from_fn(auth))
} }
async fn auth<B>( async fn auth(
data: Data<IbisData>, data: Data<IbisData>,
jar: CookieJar, jar: CookieJar,
mut request: Request<B>, mut request: Request<Body>,
next: Next<B>, next: Next,
) -> Result<Response, StatusCode> { ) -> Result<Response, StatusCode> {
if let Some(auth) = jar.get(AUTH_COOKIE) { if let Some(auth) = jar.get(AUTH_COOKIE) {
if let Ok(user) = validate(auth.value(), &data).await { if let Ok(user) = validate(auth.value(), &data).await {

View File

@ -98,7 +98,7 @@ fn create_cookie(jwt: String, data: &Data<IbisData>) -> Cookie<'static> {
if domain.contains(':') { if domain.contains(':') {
domain = domain.split(':').collect::<Vec<_>>()[0].to_string(); domain = domain.split(':').collect::<Vec<_>>()[0].to_string();
} }
Cookie::build(AUTH_COOKIE, jwt) Cookie::build((AUTH_COOKIE, jwt))
.domain(domain) .domain(domain)
.same_site(SameSite::Strict) .same_site(SameSite::Strict)
.path("/") .path("/")
@ -107,7 +107,7 @@ fn create_cookie(jwt: String, data: &Data<IbisData>) -> Cookie<'static> {
.expires(Expiration::DateTime( .expires(Expiration::DateTime(
OffsetDateTime::now_utc() + Duration::weeks(52), OffsetDateTime::now_utc() + Duration::weeks(52),
)) ))
.finish() .build()
} }
#[debug_handler] #[debug_handler]

View File

@ -42,7 +42,7 @@ use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url; use url::Url;
pub fn federation_routes() -> Router { pub fn federation_routes() -> Router<()> {
Router::new() Router::new()
.route("/", get(http_get_instance)) .route("/", get(http_get_instance))
.route("/user/:name", get(http_get_person)) .route("/user/:name", get(http_get_person))

View File

@ -23,27 +23,28 @@ use activitypub_federation::{
}; };
use api::api_routes; use api::api_routes;
use axum::{ use axum::{
debug_handler, body::Body,
headers::HeaderMap,
http::{HeaderValue, Request}, http::{HeaderValue, Request},
middleware::Next, middleware::Next,
response::{IntoResponse, Response}, response::{IntoResponse, Response},
routing::get, routing::get,
Router, Router,
Server,
ServiceExt, ServiceExt,
}; };
use axum_macros::{debug_handler, debug_middleware};
use chrono::Local; use chrono::Local;
use diesel::{ use diesel::{
r2d2::{ConnectionManager, Pool}, r2d2::{ConnectionManager, Pool},
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::leptos_config::get_config_from_str;
use leptos_axum::{generate_route_list, LeptosRoutes}; use leptos_axum::{generate_route_list, LeptosRoutes};
use log::info; use log::info;
use tower::Layer; use reqwest::header::HeaderMap;
use tokio::net::TcpListener;
use tower_http::cors::CorsLayer; use tower_http::cors::CorsLayer;
use tower_layer::Layer;
pub mod api; pub mod api;
pub mod config; pub mod config;
@ -81,15 +82,14 @@ pub async fn start(config: IbisConfig) -> MyResult<()> {
setup(&data.to_request_data()).await?; setup(&data.to_request_data()).await?;
} }
let conf = get_config_from_str(include_str!("../../Cargo.toml"))?; let mut conf = get_config_from_str(include_str!("../../Cargo.toml"))?;
let mut leptos_options = conf.leptos_options; conf.site_addr = data.config.bind;
leptos_options.site_addr = data.config.bind;
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(&leptos_options, routes, || view! { <App/> }) .leptos_routes(&conf, routes, App)
.with_state(leptos_options) .with_state(conf)
.nest("", asset_routes()?) .nest("", asset_routes()?)
.nest(FEDERATION_ROUTES_PREFIX, federation_routes()) .nest(FEDERATION_ROUTES_PREFIX, federation_routes())
.nest("/api/v1", api_routes()) .nest("/api/v1", api_routes())
@ -103,14 +103,13 @@ pub async fn start(config: IbisConfig) -> MyResult<()> {
let app_with_middleware = middleware.layer(app); let app_with_middleware = middleware.layer(app);
info!("Listening on {}", &data.config.bind); info!("Listening on {}", &data.config.bind);
Server::bind(&data.config.bind) let listener = TcpListener::bind(&data.config.bind).await?;
.serve(app_with_middleware.into_make_service()) axum::serve(listener, app_with_middleware.into_make_service()).await?;
.await?;
Ok(()) Ok(())
} }
pub fn asset_routes() -> MyResult<Router> { pub fn asset_routes() -> MyResult<Router<()>> {
let mut css_headers = HeaderMap::new(); let mut css_headers = HeaderMap::new();
css_headers.insert("Content-Type", "text/css".parse()?); css_headers.insert("Content-Type", "text/css".parse()?);
Ok(Router::new() Ok(Router::new()
@ -209,7 +208,8 @@ async fn setup(data: &Data<IbisData>) -> Result<(), Error> {
/// with frontend routes. If a request is an Activitypub fetch as indicated by /// with frontend routes. If a request is an Activitypub fetch as indicated by
/// `Accept: application/activity+json` header, use the federation routes. Otherwise /// `Accept: application/activity+json` header, use the federation routes. Otherwise
/// leave the path unchanged so it can go to frontend. /// leave the path unchanged so it can go to frontend.
async fn federation_routes_middleware<B>(request: Request<B>, next: Next<B>) -> Response { #[debug_middleware]
async fn federation_routes_middleware(request: Request<Body>, next: Next) -> Response {
let (mut parts, body) = request.into_parts(); let (mut parts, body) = request.into_parts();
// rewrite uri based on accept header // rewrite uri based on accept header
let mut uri = parts.uri.to_string(); let mut uri = parts.uri.to_string();

View File

@ -7,7 +7,7 @@ use axum::{routing::get, Json, Router};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url; use url::Url;
pub fn config() -> Router { pub fn config() -> Router<()> {
Router::new() Router::new()
.route("/nodeinfo/2.0.json", get(node_info)) .route("/nodeinfo/2.0.json", get(node_info))
.route("/.well-known/nodeinfo", get(node_info_well_known)) .route("/.well-known/nodeinfo", get(node_info_well_known))

View File

@ -91,26 +91,26 @@ pub fn App() -> impl IntoView {
view! { view! {
<> <>
<Stylesheet id="simple" href="/assets/simple.css"/> <Stylesheet id="simple" href="/assets/simple.css" />
<Stylesheet id="ibis" href="/assets/ibis.css"/> <Stylesheet id="ibis" href="/assets/ibis.css" />
<Router> <Router>
<Nav/> <Nav />
<main> <main>
<Routes> <Routes>
<Route path="/" view=ReadArticle/> <Route path="/" view=ReadArticle />
<Route path="/article/:title" view=ReadArticle/> <Route path="/article/:title" view=ReadArticle />
<Route path="/article/:title/history" view=ArticleHistory/> <Route path="/article/:title/history" view=ArticleHistory />
<Route path="/article/:title/edit/:conflict_id?" view=EditArticle/> <Route path="/article/:title/edit/:conflict_id?" view=EditArticle />
<Route path="/article/:title/actions" view=ArticleActions/> <Route path="/article/:title/actions" view=ArticleActions />
<Route path="/article/:title/diff/:hash" view=EditDiff/> <Route path="/article/:title/diff/:hash" view=EditDiff />
<Route path="/article/create" view=CreateArticle/> <Route path="/article/create" view=CreateArticle />
<Route path="/article/list" view=ListArticles/> <Route path="/article/list" view=ListArticles />
<Route path="/instance/:hostname" view=InstanceDetails/> <Route path="/instance/:hostname" view=InstanceDetails />
<Route path="/user/:name" view=UserProfile/> <Route path="/user/:name" view=UserProfile />
<Route path="/login" view=Login/> <Route path="/login" view=Login />
<Route path="/register" view=Register/> <Route path="/register" view=Register />
<Route path="/search" view=Search/> <Route path="/search" view=Search />
<Route path="/conflicts" view=Conflicts/> <Route path="/conflicts" view=Conflicts />
</Routes> </Routes>
</main> </main>
</Router> </Router>

View File

@ -48,12 +48,16 @@ pub fn ArticleNav(article: Resource<Option<String>, ArticleView>) -> impl IntoVi
}> }>
<A href=format!("{article_link}/edit")>"Edit"</A> <A href=format!("{article_link}/edit")>"Edit"</A>
</Show> </Show>
<Show when=move || global_state.with(|state| state.my_profile.is_some())> <Show when=move || {
global_state.with(|state| state.my_profile.is_some())
}>
<A href=format!("{article_link_}/actions")>"Actions"</A> <A href=format!("{article_link_}/actions")>"Actions"</A>
{instance {instance
.get() .get()
.map(|i| { .map(|i| {
view! { <InstanceFollowButton instance=i.instance.clone()/> } view! {
<InstanceFollowButton instance=i.instance.clone() />
}
})} })}
</Show> </Show>

View File

@ -52,7 +52,7 @@ pub fn ArticleActions() -> impl IntoView {
} }
}); });
view! { view! {
<ArticleNav article=article/> <ArticleNav article=article />
<Suspense fallback=|| { <Suspense fallback=|| {
view! { "Loading..." } view! { "Loading..." }
}> }>
@ -117,7 +117,7 @@ pub fn ArticleActions() -> impl IntoView {
</Suspense> </Suspense>
<Show when=move || fork_response.get().is_some()> <Show when=move || fork_response.get().is_some()>
<Redirect path=article_link(&fork_response.get().unwrap())/> <Redirect path=article_link(&fork_response.get().unwrap()) />
</Show> </Show>
<p>"TODO: add option for admin to delete article etc"</p> <p>"TODO: add option for admin to delete article etc"</p>
} }

View File

@ -63,8 +63,7 @@ pub fn CreateArticle() -> impl IntoView {
let val = event_target_value(&ev); let val = event_target_value(&ev);
set_text.update(|p| *p = val); set_text.update(|p| *p = val);
} }
> ></textarea>
</textarea>
<div> <div>
<a href="https://commonmark.org/help/" target="blank_"> <a href="https://commonmark.org/help/" target="blank_">
Markdown Markdown
@ -90,7 +89,9 @@ pub fn CreateArticle() -> impl IntoView {
<button <button
prop:disabled=move || button_is_disabled.get() prop:disabled=move || button_is_disabled.get()
on:click=move |_| submit_action.dispatch((title.get(), text.get(), summary.get())) on:click=move |_| {
submit_action.dispatch((title.get(), text.get(), summary.get()))
}
> >
Submit Submit
</button> </button>
@ -99,7 +100,7 @@ pub fn CreateArticle() -> impl IntoView {
} }
> >
<Redirect path=format!("/article/{}", title.get().replace(' ', "_"))/> <Redirect path=format!("/article/{}", title.get().replace(' ', "_")) />
</Show> </Show>
} }
} }

View File

@ -100,7 +100,7 @@ pub fn EditArticle() -> impl IntoView {
); );
view! { view! {
<ArticleNav article=article/> <ArticleNav article=article />
<Show <Show
when=move || edit_response.get() == EditResponse::Success when=move || edit_response.get() == EditResponse::Success
fallback=move || { fallback=move || {

View File

@ -12,7 +12,7 @@ pub fn ArticleHistory() -> impl IntoView {
let article = article_resource(); let article = article_resource();
view! { view! {
<ArticleNav article=article/> <ArticleNav article=article />
<Suspense fallback=|| { <Suspense fallback=|| {
view! { "Loading..." } view! { "Loading..." }
}> }>

View File

@ -28,9 +28,9 @@ pub fn ListArticles() -> impl IntoView {
let is_local_only = val == "only-local"; let is_local_only = val == "only-local";
set_only_local.update(|p| *p = is_local_only); set_only_local.update(|p| *p = is_local_only);
}> }>
<input type="radio" name="listing-type" id="only-local"/> <input type="radio" name="listing-type" id="only-local" />
<label for="only-local">Only Local</label> <label for="only-local">Only Local</label>
<input type="radio" name="listing-type" id="all" checked/> <input type="radio" name="listing-type" id="all" checked />
<label for="all">All</label> <label for="all">All</label>
</fieldset> </fieldset>
<ul> <ul>

View File

@ -11,7 +11,7 @@ pub fn ReadArticle() -> impl IntoView {
let article = article_resource(); let article = article_resource();
view! { view! {
<ArticleNav article=article/> <ArticleNav article=article />
<Suspense fallback=|| { <Suspense fallback=|| {
view! { "Loading..." } view! { "Loading..." }
}> }>
@ -25,7 +25,9 @@ pub fn ReadArticle() -> impl IntoView {
view! { view! {
<div class="item-view"> <div class="item-view">
<h1>{article_title(&article.article)}</h1> <h1>{article_title(&article.article)}</h1>
<div inner_html=parser.parse(&article.article.text).render()></div> <div inner_html=parser
.parse(&article.article.text)
.render()></div>
</div> </div>
} }
}) })

View File

@ -18,10 +18,16 @@ pub fn Conflicts() -> impl IntoView {
.map(|c| { .map(|c| {
c.into_iter() c.into_iter()
.map(|c| { .map(|c| {
let link = format!("{}/edit/{}", article_link(&c.article), c.id); let link = format!(
"{}/edit/{}",
article_link(&c.article),
c.id,
);
view! { view! {
<li> <li>
<a href=link>{article_title(&c.article)} " - " {c.summary}</a> <a href=link>
{article_title(&c.article)} " - " {c.summary}
</a>
</li> </li>
} }
}) })

View File

@ -8,7 +8,7 @@ pub fn EditDiff() -> impl IntoView {
let article = article_resource(); let article = article_resource();
view! { view! {
<ArticleNav article=article/> <ArticleNav article=article />
<Suspense fallback=|| { <Suspense fallback=|| {
view! { "Loading..." } view! { "Loading..." }
}> }>

View File

@ -31,15 +31,19 @@ pub fn InstanceDetails() -> impl IntoView {
view! { view! {
<h1>{instance.domain}</h1> <h1>{instance.domain}</h1>
<Show when=move || global_state.with(|state| state.my_profile.is_some())> <Show when=move || {
<InstanceFollowButton instance=instance_.clone()/> global_state.with(|state| state.my_profile.is_some())
}>
<InstanceFollowButton instance=instance_.clone() />
</Show> </Show>
<p>Follow the instance so that new edits are federated to your instance.</p> <p>
Follow the instance so that new edits are federated to your instance.
</p>
<p> <p>
"TODO: show a list of articles from the instance. For now you can use the " "TODO: show a list of articles from the instance. For now you can use the "
<a href="/article/list">Article list</a> . <a href="/article/list">Article list</a>.
</p> </p>
<hr/> <hr />
<h2>"Description:"</h2> <h2>"Description:"</h2>
<div>{instance.description}</div> <div>{instance.description}</div>
} }

View File

@ -53,7 +53,7 @@ pub fn Login() -> impl IntoView {
} }
> >
<Redirect path="/"/> <Redirect path="/" />
</Show> </Show>
} }
} }

View File

@ -93,8 +93,7 @@ pub fn Search() -> impl IntoView {
] ]
} else { } else {
vec![] vec![]
}} }} // render articles from resolve/search
// render articles from resolve/search
{search_results {search_results
.articles .articles
.iter() .iter()

View File

@ -28,6 +28,6 @@ fn main() {
_ = console_log::init_with_level(log::Level::Debug); _ = console_log::init_with_level(log::Level::Debug);
console_error_panic_hook::set_once(); console_error_panic_hook::set_once();
mount_to_body(|| { mount_to_body(|| {
view! { <App/> } view! { <App /> }
}); });
} }