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

Rework how site data is fetched

This commit is contained in:
Felix Ableitner 2024-11-14 12:33:25 +01:00
parent 66f89d3bfd
commit 61806e12a6
19 changed files with 180 additions and 192 deletions

View file

@ -68,7 +68,7 @@ pub(in crate::backend::api) async fn create_article(
instance_id: local_instance.id, instance_id: local_instance.id,
local: true, local: true,
protected: false, protected: false,
approved: !data.config.article_approval, approved: !data.config.config.article_approval,
}; };
let article = DbArticle::create(form, &data)?; let article = DbArticle::create(form, &data)?;
@ -214,7 +214,7 @@ pub(in crate::backend::api) async fn fork_article(
instance_id: local_instance.id, instance_id: local_instance.id,
local: true, local: true,
protected: false, protected: false,
approved: !data.config.article_approval, approved: !data.config.config.article_approval,
}; };
let article = DbArticle::create(form, &data)?; let article = DbArticle::create(form, &data)?;

View file

@ -12,12 +12,12 @@ use crate::{
search_article, search_article,
}, },
instance::{follow_instance, get_instance, resolve_instance}, instance::{follow_instance, get_instance, resolve_instance},
user::{get_user, login_user, logout_user, my_profile, register_user, validate}, user::{get_user, login_user, logout_user, register_user, validate},
}, },
database::IbisData, database::IbisData,
error::MyResult, error::MyResult,
}, },
common::{LocalUserView, AUTH_COOKIE}, common::{LocalUserView, SiteView, AUTH_COOKIE},
}; };
use activitypub_federation::config::Data; use activitypub_federation::config::Data;
use anyhow::anyhow; use anyhow::anyhow;
@ -28,9 +28,12 @@ use axum::{
middleware::{self, Next}, middleware::{self, Next},
response::Response, response::Response,
routing::{get, post}, routing::{get, post},
Extension,
Json,
Router, Router,
}; };
use axum_extra::extract::CookieJar; use axum_extra::extract::CookieJar;
use axum_macros::debug_handler;
use instance::list_remote_instances; use instance::list_remote_instances;
use user::{count_notifications, list_notifications}; use user::{count_notifications, list_notifications};
@ -59,8 +62,8 @@ pub fn api_routes() -> Router<()> {
.route("/user/notifications/count", get(count_notifications)) .route("/user/notifications/count", get(count_notifications))
.route("/account/register", post(register_user)) .route("/account/register", post(register_user))
.route("/account/login", post(login_user)) .route("/account/login", post(login_user))
.route("/account/my_profile", get(my_profile))
.route("/account/logout", get(logout_user)) .route("/account/logout", get(logout_user))
.route("/site", get(site_view))
.route_layer(middleware::from_fn(auth)) .route_layer(middleware::from_fn(auth))
} }
@ -73,8 +76,7 @@ async fn auth(
let auth = request let auth = request
.headers() .headers()
.get(AUTH_COOKIE) .get(AUTH_COOKIE)
.map(|h| h.to_str().ok()) .and_then(|h| h.to_str().ok())
.flatten()
.or(jar.get(AUTH_COOKIE).map(|c| c.value())); .or(jar.get(AUTH_COOKIE).map(|c| c.value()));
if let Some(auth) = auth { if let Some(auth) = auth {
@ -92,3 +94,14 @@ fn check_is_admin(user: &LocalUserView) -> MyResult<()> {
} }
Ok(()) Ok(())
} }
#[debug_handler]
pub(in crate::backend::api) async fn site_view(
data: Data<IbisData>,
user: Option<Extension<LocalUserView>>,
) -> MyResult<Json<SiteView>> {
Ok(Json(SiteView {
my_profile: user.map(|u| u.0),
config: data.config.config.clone(),
}))
}

View file

@ -76,7 +76,7 @@ pub(in crate::backend::api) async fn register_user(
jar: CookieJar, jar: CookieJar,
Form(form): Form<RegisterUserForm>, Form(form): Form<RegisterUserForm>,
) -> MyResult<(CookieJar, Json<LocalUserView>)> { ) -> MyResult<(CookieJar, Json<LocalUserView>)> {
if !data.config.registration_open { if !data.config.config.registration_open {
return Err(anyhow!("Registration is closed").into()); return Err(anyhow!("Registration is closed").into());
} }
let user = DbPerson::create_local(form.username, form.password, false, &data)?; let user = DbPerson::create_local(form.username, form.password, false, &data)?;
@ -121,19 +121,6 @@ fn create_cookie(jwt: String, data: &Data<IbisData>) -> Cookie<'static> {
.build() .build()
} }
#[debug_handler]
pub(in crate::backend::api) async fn my_profile(
data: Data<IbisData>,
jar: CookieJar,
) -> MyResult<Json<LocalUserView>> {
let jwt = jar.get(AUTH_COOKIE).map(|c| c.value());
if let Some(jwt) = jwt {
Ok(Json(validate(jwt, &data).await?))
} else {
Err(anyhow!("invalid/missing auth").into())
}
}
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn logout_user( pub(in crate::backend::api) async fn logout_user(
data: Data<IbisData>, data: Data<IbisData>,

View file

@ -1,4 +1,4 @@
use crate::backend::error::MyResult; use crate::{backend::error::MyResult, common::SharedConfig};
use config::Config; use config::Config;
use doku::Document; use doku::Document;
use serde::Deserialize; use serde::Deserialize;
@ -10,17 +10,10 @@ use smart_default::SmartDefault;
pub struct IbisConfig { pub struct IbisConfig {
/// Details about the PostgreSQL database connection /// Details about the PostgreSQL database connection
pub database: IbisConfigDatabase, pub database: IbisConfigDatabase,
/// Whether users can create new accounts
#[default = true]
#[doku(example = "true")]
pub registration_open: bool,
/// Whether admins need to approve new articles
#[default = false]
#[doku(example = "false")]
pub article_approval: bool,
/// Details of the initial admin account /// Details of the initial admin account
pub setup: IbisConfigSetup, pub setup: IbisConfigSetup,
pub federation: IbisConfigFederation, pub federation: IbisConfigFederation,
pub config: SharedConfig,
} }
impl IbisConfig { impl IbisConfig {

View file

@ -86,7 +86,6 @@ impl DbInstance {
Ok(InstanceView { Ok(InstanceView {
instance, instance,
followers, followers,
registration_open: data.config.registration_open,
}) })
} }

View file

@ -136,7 +136,7 @@ async fn leptos_routes_handler(
let cookie = jar.get(AUTH_COOKIE).map(|c| c.value().to_string()); let cookie = jar.get(AUTH_COOKIE).map(|c| c.value().to_string());
provide_context(Auth(cookie)); provide_context(Auth(cookie));
}, },
move || view! { <App/> }, move || view! { <App /> },
); );
handler(req).await.into_response() handler(req).await.into_response()

View file

@ -34,7 +34,7 @@ async fn node_info(data: Data<IbisData>) -> MyResult<Json<NodeInfo>> {
version: env!("CARGO_PKG_VERSION").to_string(), version: env!("CARGO_PKG_VERSION").to_string(),
}, },
protocols: vec!["activitypub".to_string()], protocols: vec!["activitypub".to_string()],
open_registrations: data.config.registration_open, open_registrations: data.config.config.registration_open,
})) }))
} }

View file

@ -6,6 +6,7 @@ use chrono::{DateTime, Utc};
use newtypes::{ArticleId, ConflictId, EditId, InstanceId, PersonId}; use newtypes::{ArticleId, ConflictId, EditId, InstanceId, PersonId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use smart_default::SmartDefault;
use url::Url; use url::Url;
use uuid::Uuid; use uuid::Uuid;
#[cfg(feature = "ssr")] #[cfg(feature = "ssr")]
@ -17,6 +18,7 @@ use {
}, },
activitypub_federation::fetch::{collection_id::CollectionId, object_id::ObjectId}, activitypub_federation::fetch::{collection_id::CollectionId, object_id::ObjectId},
diesel::{Identifiable, Queryable, Selectable}, diesel::{Identifiable, Queryable, Selectable},
doku::Document,
}; };
pub const MAIN_PAGE_NAME: &str = "Main_Page"; pub const MAIN_PAGE_NAME: &str = "Main_Page";
@ -311,7 +313,6 @@ impl DbInstance {
pub struct InstanceView { pub struct InstanceView {
pub instance: DbInstance, pub instance: DbInstance,
pub followers: Vec<DbPerson>, pub followers: Vec<DbPerson>,
pub registration_open: bool,
} }
#[derive(Deserialize, Serialize, Clone, Debug)] #[derive(Deserialize, Serialize, Clone, Debug)]
@ -320,6 +321,30 @@ pub struct GetUserForm {
pub domain: Option<String>, pub domain: Option<String>,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, SmartDefault)]
#[serde(default)]
#[serde(deny_unknown_fields)]
#[cfg_attr(feature = "ssr", derive(Queryable, Document))]
#[cfg_attr(feature = "ssr", diesel(check_for_backend(diesel::pg::Pg)))]
pub struct SharedConfig {
/// Whether users can create new accounts
#[default = true]
#[cfg_attr(feature = "ssr", doku(example = "true"))]
pub registration_open: bool,
/// Whether admins need to approve new articles
#[default = false]
#[cfg_attr(feature = "ssr", doku(example = "false"))]
pub article_approval: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)]
#[cfg_attr(feature = "ssr", derive(Queryable))]
#[cfg_attr(feature = "ssr", diesel(check_for_backend(diesel::pg::Pg)))]
pub struct SiteView {
pub my_profile: Option<LocalUserView>,
pub config: SharedConfig,
}
#[test] #[test]
fn test_edit_versions() { fn test_edit_versions() {
let default = EditVersion::default(); let default = EditVersion::default();

View file

@ -24,6 +24,7 @@ use crate::{
RegisterUserForm, RegisterUserForm,
ResolveObject, ResolveObject,
SearchArticleForm, SearchArticleForm,
SiteView,
}, },
frontend::error::MyResult, frontend::error::MyResult,
}; };
@ -210,10 +211,8 @@ impl ApiClient {
} }
} }
pub async fn my_profile(&self) -> MyResult<LocalUserView> { pub async fn site(&self) -> MyResult<SiteView> {
let req = self let req = self.client.get(self.request_endpoint("/api/v1/site"));
.client
.get(self.request_endpoint("/api/v1/account/my_profile"));
handle_json_res(req).await handle_json_res(req).await
} }

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
common::LocalUserView, common::SiteView,
frontend::{ frontend::{
api::CLIENT, api::CLIENT,
components::nav::Nav, components::nav::Nav,
@ -23,60 +23,51 @@ use crate::{
}, },
}, },
}; };
use leptos::{ use leptos::*;
component,
create_local_resource,
create_rw_signal,
expect_context,
provide_context,
use_context,
view,
DynAttrs,
IntoView,
RwSignal,
SignalGet,
SignalUpdate,
};
use leptos_meta::{provide_meta_context, *}; use leptos_meta::{provide_meta_context, *};
use leptos_router::{Route, Router, Routes}; use leptos_router::{Route, Router, Routes};
// https://book.leptos.dev/15_global_state.html pub fn site() -> Resource<(), SiteView> {
#[derive(Clone)] use_context::<Resource<(), SiteView>>().unwrap()
pub struct GlobalState {
pub(crate) my_profile: Option<LocalUserView>,
} }
impl GlobalState { pub fn is_logged_in() -> bool {
pub fn update_my_profile() { site().with_default(|site| site.my_profile.is_some())
create_local_resource( }
move || (), pub fn is_admin() -> bool {
|_| async move { site().with_default(|site| {
let my_profile = CLIENT.my_profile().await.ok(); site.my_profile
expect_context::<RwSignal<GlobalState>>() .as_ref()
.update(|state| state.my_profile = my_profile.clone());
},
);
}
pub fn is_admin() -> fn() -> bool {
move || {
use_context::<RwSignal<GlobalState>>()
.expect("global state is provided")
.get()
.my_profile
.map(|p| p.local_user.admin) .map(|p| p.local_user.admin)
.unwrap_or(false) .unwrap_or(false)
} })
}
pub trait DefaultResource<T> {
fn with_default<O>(&self, f: impl FnOnce(&T) -> O) -> O;
}
impl<T: Default> DefaultResource<T> for Resource<(), T> {
fn with_default<O>(&self, f: impl FnOnce(&T) -> O) -> O {
self.with(|x| match x {
Some(x) => f(x),
None => f(&T::default()),
})
} }
} }
#[component] #[component]
pub fn App() -> impl IntoView { pub fn App() -> impl IntoView {
// TODO: should create_resource() but then things break
let site_resource = create_local_resource(
move || (),
|_| async move {
let site = CLIENT.site().await.unwrap();
site
},
);
provide_context(site_resource);
provide_meta_context(); provide_meta_context();
let global_state = GlobalState { my_profile: None };
// Load user profile in case we are already logged in
GlobalState::update_my_profile();
provide_context(create_rw_signal(global_state));
let darkmode = DarkMode::init(); let darkmode = DarkMode::init();
provide_context(darkmode.clone()); provide_context(darkmode.clone());

View file

@ -2,7 +2,7 @@ use crate::{
common::{validation::can_edit_article, ArticleView, GetInstance}, common::{validation::can_edit_article, ArticleView, GetInstance},
frontend::{ frontend::{
api::CLIENT, api::CLIENT,
app::GlobalState, app::{is_admin, is_logged_in},
article_link, article_link,
article_title, article_title,
components::instance_follow_button::InstanceFollowButton, components::instance_follow_button::InstanceFollowButton,
@ -32,7 +32,7 @@ pub fn ArticleNav(
.get() .get()
.map(|article_| { .map(|article_| {
let title = article_title(&article_.article); let title = article_title(&article_.article);
let instance = create_local_resource( let instance = create_resource(
move || article_.article.instance_id, move || article_.article.instance_id,
move |instance_id| async move { move |instance_id| async move {
let form = GetInstance { let form = GetInstance {
@ -41,7 +41,6 @@ pub fn ArticleNav(
CLIENT.get_instance(&form).await.unwrap() CLIENT.get_instance(&form).await.unwrap()
}, },
); );
let global_state = use_context::<RwSignal<GlobalState>>().unwrap();
let article_link = article_link(&article_.article); let article_link = article_link(&article_.article);
let article_link_ = article_link.clone(); let article_link_ = article_link.clone();
let protected = article_.article.protected; let protected = article_.article.protected;
@ -54,24 +53,14 @@ pub fn ArticleNav(
"History" "History"
</A> </A>
<Show when=move || { <Show when=move || {
global_state is_logged_in()
.with(|state| { && can_edit_article(&article_.article, is_admin()).is_ok()
let is_admin = state
.my_profile
.as_ref()
.map(|p| p.local_user.admin)
.unwrap_or(false);
state.my_profile.is_some()
&& can_edit_article(&article_.article, is_admin).is_ok()
})
}> }>
<A class=tab_classes.edit href=format!("{article_link}/edit")> <A class=tab_classes.edit href=format!("{article_link}/edit")>
"Edit" "Edit"
</A> </A>
</Show> </Show>
<Show when=move || { <Show when=is_logged_in>
global_state.with(|state| state.my_profile.is_some())
}>
<A <A
class=tab_classes.actions class=tab_classes.actions
href=format!("{article_link_}/actions") href=format!("{article_link_}/actions")

View file

@ -1,24 +1,28 @@
use crate::{ use crate::{
common::{newtypes::InstanceId, DbInstance, FollowInstance}, common::{newtypes::InstanceId, DbInstance, FollowInstance},
frontend::{api::CLIENT, app::GlobalState}, frontend::{
api::CLIENT,
app::{site, DefaultResource},
},
}; };
use leptos::{component, *}; use leptos::{component, *};
#[component] #[component]
pub fn InstanceFollowButton(instance: DbInstance) -> impl IntoView { pub fn InstanceFollowButton(instance: DbInstance) -> impl IntoView {
let global_state = use_context::<RwSignal<GlobalState>>().unwrap();
let follow_action = create_action(move |instance_id: &InstanceId| { let follow_action = create_action(move |instance_id: &InstanceId| {
let instance_id = *instance_id; let instance_id = *instance_id;
async move { async move {
let form = FollowInstance { id: instance_id }; let form = FollowInstance { id: instance_id };
CLIENT.follow_instance(form).await.unwrap(); CLIENT.follow_instance(form).await.unwrap();
GlobalState::update_my_profile(); site().refetch();
} }
}); });
let is_following = global_state let is_following = site()
.get_untracked() .with_default(|site| {
site.clone()
.my_profile .my_profile
.map(|p| p.following.contains(&instance)) .map(|p| p.following.contains(&instance))
})
.unwrap_or(false); .unwrap_or(false);
let follow_text = if is_following { let follow_text = if is_following {
"Following instance" "Following instance"

View file

@ -1,24 +1,17 @@
use crate::frontend::{api::CLIENT, app::GlobalState, dark_mode::DarkMode}; use crate::frontend::{
use leptos::{component, use_context, view, IntoView, RwSignal, SignalWith, *}; api::CLIENT,
app::{is_logged_in, site, DefaultResource},
dark_mode::DarkMode,
};
use leptos::{component, view, IntoView, *};
use leptos_router::*; use leptos_router::*;
#[component] #[component]
pub fn Nav() -> impl IntoView { pub fn Nav() -> impl IntoView {
let global_state = use_context::<RwSignal<GlobalState>>().unwrap();
let logout_action = create_action(move |_| async move { let logout_action = create_action(move |_| async move {
CLIENT.logout().await.unwrap(); CLIENT.logout().await.unwrap();
GlobalState::update_my_profile(); site().refetch();
}); });
let registration_open = create_local_resource(
|| (),
move |_| async move {
CLIENT
.get_local_instance()
.await
.map(|i| i.registration_open)
.unwrap_or_default()
},
);
let notification_count = create_resource( let notification_count = create_resource(
|| (), || (),
move |_| async move { CLIENT.notifications_count().await.unwrap_or_default() }, move |_| async move { CLIENT.notifications_count().await.unwrap_or_default() },
@ -56,7 +49,8 @@ pub fn Nav() -> impl IntoView {
<li> <li>
<A href="/article/list">"Articles"</A> <A href="/article/list">"Articles"</A>
</li> </li>
<Show when=move || global_state.with(|state| state.my_profile.is_some())> <Transition>
<Show when=is_logged_in>
<li> <li>
<A href="/article/create">"Create Article"</A> <A href="/article/create">"Create Article"</A>
</li> </li>
@ -64,11 +58,12 @@ pub fn Nav() -> impl IntoView {
<A href="/notifications"> <A href="/notifications">
"Notifications " "Notifications "
<span class="indicator-item indicator-end badge badge-neutral"> <span class="indicator-item indicator-end badge badge-neutral">
{notification_count} {move || notification_count.get()}
</span> </span>
</A> </A>
</li> </li>
</Show> </Show>
</Transition>
<li> <li>
<form <form
class="form-control m-0 p-1" class="form-control m-0 p-1"
@ -96,14 +91,17 @@ pub fn Nav() -> impl IntoView {
</form> </form>
</li> </li>
<div class="divider"></div> <div class="divider"></div>
<Transition>
<Show <Show
when=move || global_state.with(|state| state.my_profile.is_some()) when=is_logged_in
fallback=move || { fallback=move || {
view! { view! {
<li> <li>
<A href="/login">"Login"</A> <A href="/login">"Login"</A>
</li> </li>
<Show when=move || registration_open.get().unwrap_or_default()> <Show when=move || {
site().with_default(|s| s.config.registration_open)
}>
<li> <li>
<A href="/register">"Register"</A> <A href="/register">"Register"</A>
</li> </li>
@ -113,8 +111,8 @@ pub fn Nav() -> impl IntoView {
> >
{ {
let my_profile = global_state let my_profile = site()
.with(|state| state.my_profile.clone().unwrap()); .with_default(|site| site.clone().my_profile.unwrap());
let profile_link = format!("/user/{}", my_profile.person.username); let profile_link = format!("/user/{}", my_profile.person.username);
view! { view! {
<p class="self-center pb-2"> <p class="self-center pb-2">
@ -132,6 +130,7 @@ pub fn Nav() -> impl IntoView {
} }
</Show> </Show>
</Transition>
<div class="flex-grow min-h-2"></div> <div class="flex-grow min-h-2"></div>
<div class="m-1 grid gap-2"> <div class="m-1 grid gap-2">
<label class="flex cursor-pointer gap-2"> <label class="flex cursor-pointer gap-2">

View file

@ -2,7 +2,7 @@ use crate::{
common::{newtypes::ArticleId, ForkArticleForm, ProtectArticleForm}, common::{newtypes::ArticleId, ForkArticleForm, ProtectArticleForm},
frontend::{ frontend::{
api::CLIENT, api::CLIENT,
app::GlobalState, app::is_admin,
article_link, article_link,
components::article_nav::{ActiveTab, ArticleNav}, components::article_nav::{ActiveTab, ArticleNav},
pages::article_resource, pages::article_resource,
@ -14,7 +14,6 @@ use leptos_router::Redirect;
#[component] #[component]
pub fn ArticleActions() -> impl IntoView { pub fn ArticleActions() -> impl IntoView {
let global_state = use_context::<RwSignal<GlobalState>>().unwrap();
let article = article_resource(); let article = article_resource();
let (new_title, set_new_title) = create_signal(String::new()); let (new_title, set_new_title) = create_signal(String::new());
let (fork_response, set_fork_response) = create_signal(Option::<DbArticle>::None); let (fork_response, set_fork_response) = create_signal(Option::<DbArticle>::None);
@ -68,17 +67,7 @@ pub fn ArticleActions() -> impl IntoView {
.map(|err| { .map(|err| {
view! { <p class="alert">{err}</p> } view! { <p class="alert">{err}</p> }
}) })
}} }} <Show when=move || { is_admin() && article.article.local }>
<Show when=move || {
global_state
.with(|state| {
state
.my_profile
.as_ref()
.map(|p| p.local_user.admin)
.unwrap_or_default() && article.article.local
})
}>
<button <button
class="btn btn-secondary" class="btn btn-secondary"
on:click=move |_| { on:click=move |_| {

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
common::LoginUserForm, common::LoginUserForm,
frontend::{api::CLIENT, app::GlobalState, components::credentials::*}, frontend::{api::CLIENT, app::site, components::credentials::*},
}; };
use leptos::*; use leptos::*;
use leptos_router::Redirect; use leptos_router::Redirect;
@ -20,9 +20,8 @@ pub fn Login() -> impl IntoView {
let result = CLIENT.login(credentials).await; let result = CLIENT.login(credentials).await;
set_wait_for_response.update(|w| *w = false); set_wait_for_response.update(|w| *w = false);
match result { match result {
Ok(res) => { Ok(_res) => {
expect_context::<RwSignal<GlobalState>>() site().refetch();
.update(|state| state.my_profile = Some(res));
set_login_response.update(|v| *v = Some(())); set_login_response.update(|v| *v = Some(()));
set_login_error.update(|e| *e = None); set_login_error.update(|e| *e = None);
} }

View file

@ -6,7 +6,7 @@ use leptos::*;
#[component] #[component]
pub fn Notifications() -> impl IntoView { pub fn Notifications() -> impl IntoView {
let notifications = create_local_resource( let notifications = create_resource(
move || {}, move || {},
|_| async move { CLIENT.notifications_list().await.unwrap() }, |_| async move { CLIENT.notifications_list().await.unwrap() },
); );

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
common::{LocalUserView, RegisterUserForm}, common::{LocalUserView, RegisterUserForm},
frontend::{api::CLIENT, app::GlobalState, components::credentials::*, error::MyResult}, frontend::{api::CLIENT, app::site, components::credentials::*, error::MyResult},
}; };
use leptos::{logging::log, *}; use leptos::{logging::log, *};
@ -20,9 +20,8 @@ pub fn Register() -> impl IntoView {
let result: MyResult<LocalUserView> = CLIENT.register(credentials).await; let result: MyResult<LocalUserView> = CLIENT.register(credentials).await;
set_wait_for_response.update(|w| *w = false); set_wait_for_response.update(|w| *w = false);
match result { match result {
Ok(res) => { Ok(_res) => {
expect_context::<RwSignal<GlobalState>>() site().refetch();
.update(|state| state.my_profile = Some(res));
set_register_response.update(|v| *v = Some(())); set_register_response.update(|v| *v = Some(()));
set_register_error.update(|e| *e = None); set_register_error.update(|e| *e = None);
} }

View file

@ -5,7 +5,7 @@ use ibis::{
config::{IbisConfig, IbisConfigDatabase, IbisConfigFederation}, config::{IbisConfig, IbisConfigDatabase, IbisConfigFederation},
start, start,
}, },
common::RegisterUserForm, common::{RegisterUserForm, SharedConfig},
frontend::{api::ApiClient, error::MyResult}, frontend::{api::ApiClient, error::MyResult},
}; };
use reqwest::ClientBuilder; use reqwest::ClientBuilder;
@ -124,12 +124,14 @@ impl IbisInstance {
connection_url, connection_url,
..Default::default() ..Default::default()
}, },
registration_open: true,
federation: IbisConfigFederation { federation: IbisConfigFederation {
domain: domain.clone(), domain: domain.clone(),
..Default::default() ..Default::default()
}, },
config: SharedConfig {
registration_open: true,
article_approval, article_approval,
},
..Default::default() ..Default::default()
}; };
let client = ClientBuilder::new().cookie_store(true).build().unwrap(); let client = ClientBuilder::new().cookie_store(true).build().unwrap();

View file

@ -112,7 +112,7 @@ async fn test_follow_instance() -> MyResult<()> {
let data = TestData::start(false).await; let data = TestData::start(false).await;
// check initial state // check initial state
let alpha_user = data.alpha.my_profile().await?; let alpha_user = data.alpha.site().await?.my_profile.unwrap();
assert_eq!(0, alpha_user.following.len()); assert_eq!(0, alpha_user.following.len());
let beta_instance = data.beta.get_local_instance().await?; let beta_instance = data.beta.get_local_instance().await?;
assert_eq!(0, beta_instance.followers.len()); assert_eq!(0, beta_instance.followers.len());
@ -122,7 +122,7 @@ async fn test_follow_instance() -> MyResult<()> {
.await?; .await?;
// check that follow was federated // check that follow was federated
let alpha_user = data.alpha.my_profile().await?; let alpha_user = data.alpha.site().await?.my_profile.unwrap();
assert_eq!(1, alpha_user.following.len()); assert_eq!(1, alpha_user.following.len());
assert_eq!(beta_instance.instance.ap_id, alpha_user.following[0].ap_id); assert_eq!(beta_instance.instance.ap_id, alpha_user.following[0].ap_id);
@ -610,13 +610,13 @@ async fn test_user_registration_login() -> MyResult<()> {
}; };
data.alpha.login(login_data).await?; data.alpha.login(login_data).await?;
let my_profile = data.alpha.my_profile().await?; let my_profile = data.alpha.site().await?.my_profile.unwrap();
assert_eq!(username, my_profile.person.username); assert_eq!(username, my_profile.person.username);
data.alpha.logout().await?; data.alpha.logout().await?;
let my_profile_after_logout = data.alpha.my_profile().await; let my_profile_after_logout = data.alpha.site().await?.my_profile;
assert!(my_profile_after_logout.is_err()); assert!(my_profile_after_logout.is_none());
data.stop() data.stop()
} }
@ -635,7 +635,7 @@ async fn test_user_profile() -> MyResult<()> {
data.beta data.beta
.resolve_article(create_res.article.ap_id.into_inner()) .resolve_article(create_res.article.ap_id.into_inner())
.await?; .await?;
let domain = extract_domain(&data.alpha.my_profile().await?.person.ap_id); let domain = extract_domain(&data.alpha.site().await?.my_profile.unwrap().person.ap_id);
// Now we can fetch the remote user from local api // Now we can fetch the remote user from local api
let params = GetUserForm { let params = GetUserForm {