Compare commits
3 commits
b72851fbfe
...
e3831650ca
Author | SHA1 | Date | |
---|---|---|---|
e3831650ca | |||
3fee57891d | |||
69cff08b5b |
14 changed files with 62 additions and 25 deletions
31
src/migrations/m20240529_000001_add_relation_unique_index.rs
Normal file
31
src/migrations/m20240529_000001_add_relation_unique_index.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use sea_orm_migration::prelude::*;
|
||||
|
||||
use super::m20240524_000002_create_relations_likes_shares::Relations;
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_index(
|
||||
Index::create()
|
||||
.unique()
|
||||
.name("index-relations-follower-following")
|
||||
.table(Relations::Table)
|
||||
.col(Relations::Following)
|
||||
.col(Relations::Follower)
|
||||
.to_owned()
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_index(Index::drop().name("index-relations-follower-following").table(Relations::Table).to_owned())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ mod m20240524_000002_create_relations_likes_shares;
|
|||
mod m20240524_000003_create_users_auth_and_config;
|
||||
mod m20240524_000004_create_addressing_deliveries;
|
||||
mod m20240524_000005_create_attachments_tags_mentions;
|
||||
mod m20240529_000001_add_relation_unique_index;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
|
@ -17,6 +18,7 @@ impl MigratorTrait for Migrator {
|
|||
Box::new(m20240524_000003_create_users_auth_and_config::Migration),
|
||||
Box::new(m20240524_000004_create_addressing_deliveries::Migration),
|
||||
Box::new(m20240524_000005_create_attachments_tags_mentions::Migration),
|
||||
Box::new(m20240529_000001_add_relation_unique_index::Migration),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,10 @@ pub async fn view(
|
|||
user = user.set_following_count(None);
|
||||
}
|
||||
|
||||
if let Some(ref fe) = ctx.cfg().instance.frontend {
|
||||
user = user.set_url(Node::link(format!("{fe}/actors/{id}")));
|
||||
}
|
||||
|
||||
Ok(JsonLD(user.ld_context()))
|
||||
},
|
||||
// remote user
|
||||
|
|
|
@ -111,7 +111,7 @@ impl Context {
|
|||
|
||||
/// get full user id uri
|
||||
pub fn uid(&self, id: &str) -> String {
|
||||
uriproxy::uri(self.base(), UriClass::User, id)
|
||||
uriproxy::uri(self.base(), UriClass::Actor, id)
|
||||
}
|
||||
|
||||
/// get full object id uri
|
||||
|
|
|
@ -2,7 +2,7 @@ use base64::Engine;
|
|||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum UriClass {
|
||||
User,
|
||||
Actor,
|
||||
Object,
|
||||
Activity,
|
||||
Context,
|
||||
|
@ -11,7 +11,7 @@ pub enum UriClass {
|
|||
impl AsRef<str> for UriClass {
|
||||
fn as_ref(&self) -> &str {
|
||||
match self {
|
||||
Self::User => "users",
|
||||
Self::Actor => "actors",
|
||||
Self::Object => "objects",
|
||||
Self::Activity => "activities",
|
||||
Self::Context => "context",
|
||||
|
@ -41,7 +41,7 @@ pub fn decompose_id(full_id: &str) -> String {
|
|||
full_id // https://example.org/actors/test/followers/page?offset=42
|
||||
.replace("https://", "")
|
||||
.replace("http://", "")
|
||||
.split('/') // ['example.org', 'users', 'test', 'followers', 'page?offset=42' ]
|
||||
.split('/') // ['example.org', 'actors', 'test', 'followers', 'page?offset=42' ]
|
||||
.nth(2) // 'test'
|
||||
.unwrap_or("")
|
||||
.to_string()
|
||||
|
|
|
@ -14,7 +14,7 @@ pub fn ActivityLine(activity: crate::Object) -> impl IntoView {
|
|||
let actor = CACHE.get_or(&actor_id, serde_json::Value::String(actor_id.clone()).into());
|
||||
let kind = activity.activity_type().unwrap_or(apb::ActivityType::Activity);
|
||||
let href = match kind {
|
||||
apb::ActivityType::Follow => Uri::web(U::User, &object_id),
|
||||
apb::ActivityType::Follow => Uri::web(U::Actor, &object_id),
|
||||
// TODO for update check what's being updated
|
||||
_ => Uri::web(U::Object, &object_id),
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ pub fn LoginBox(
|
|||
view! {
|
||||
<div>
|
||||
<div class="w-100" class:hidden=move || !auth.present() >
|
||||
"hi "<a href={move || Uri::web(U::User, &auth.username() )} >{move || auth.username() }</a>
|
||||
"hi "<a href={move || Uri::web(U::Actor, &auth.username() )} >{move || auth.username() }</a>
|
||||
<input style="float:right" type="submit" value="logout" on:click=move |_| {
|
||||
token_tx.set(None);
|
||||
home_tl.reset(format!("{URL_BASE}/outbox/page"));
|
||||
|
|
|
@ -86,7 +86,7 @@ pub fn PostBox(advanced: WriteSignal<bool>) -> impl IntoView {
|
|||
mentions.get()
|
||||
.map(|x| x.into_iter().map(|u| match CACHE.get(&u) {
|
||||
Some(u) => view! { <span class="nowrap"><span class="emoji mr-s ml-s">"📨"</span><ActorStrip object=u /></span> }.into_view(),
|
||||
None => view! { <span class="nowrap"><span class="emoji mr-s ml-s">"📨"</span><a href={Uri::web(U::User, &u)}>{u}</a></span> }.into_view(),
|
||||
None => view! { <span class="nowrap"><span class="emoji mr-s ml-s">"📨"</span><a href={Uri::web(U::Actor, &u)}>{u}</a></span> }.into_view(),
|
||||
})
|
||||
.collect_view())
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ async fn process_activities(activities: Vec<serde_json::Value>, auth: Auth) -> V
|
|||
if let Some(object_id) = activity.object().id() {
|
||||
if !gonna_fetch.contains(&object_id) {
|
||||
let fetch_kind = match activity_type {
|
||||
apb::ActivityType::Follow => U::User,
|
||||
apb::ActivityType::Follow => U::Actor,
|
||||
_ => U::Object,
|
||||
};
|
||||
gonna_fetch.insert(object_id.clone());
|
||||
|
@ -235,20 +235,20 @@ async fn process_activities(activities: Vec<serde_json::Value>, auth: Auth) -> V
|
|||
if let Some(uid) = activity.attributed_to().id() {
|
||||
if CACHE.get(&uid).is_none() && !gonna_fetch.contains(&uid) {
|
||||
gonna_fetch.insert(uid.clone());
|
||||
sub_tasks.push(Box::pin(fetch_and_update(U::User, uid, auth)));
|
||||
sub_tasks.push(Box::pin(fetch_and_update(U::Actor, uid, auth)));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(uid) = activity.actor().id() {
|
||||
if CACHE.get(&uid).is_none() && !gonna_fetch.contains(&uid) {
|
||||
gonna_fetch.insert(uid.clone());
|
||||
sub_tasks.push(Box::pin(fetch_and_update(U::User, uid, auth)));
|
||||
sub_tasks.push(Box::pin(fetch_and_update(U::Actor, uid, auth)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for user in actors_seen {
|
||||
sub_tasks.push(Box::pin(fetch_and_update(U::User, user, auth)));
|
||||
sub_tasks.push(Box::pin(fetch_and_update(U::Actor, user, auth)));
|
||||
}
|
||||
|
||||
futures::future::join_all(sub_tasks).await;
|
||||
|
@ -269,9 +269,9 @@ async fn fetch_and_update_with_user(kind: U, id: String, auth: Auth) {
|
|||
if let Some(actor_id) = match kind {
|
||||
U::Object => obj.attributed_to().id(),
|
||||
U::Activity => obj.actor().id(),
|
||||
U::User | U::Context => None,
|
||||
U::Actor | U::Context => None,
|
||||
} {
|
||||
fetch_and_update(U::User, actor_id, auth).await;
|
||||
fetch_and_update(U::Actor, actor_id, auth).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ pub fn ActorStrip(object: crate::Object) -> impl IntoView {
|
|||
let domain = object.id().unwrap_or_default().replace("https://", "").split('/').next().unwrap_or_default().to_string();
|
||||
let avatar = object.icon().get().map(|x| x.url().id().unwrap_or(DEFAULT_AVATAR_URL.into())).unwrap_or(DEFAULT_AVATAR_URL.into());
|
||||
view! {
|
||||
<a href={Uri::web(U::User, &actor_id)} class="clean hover">
|
||||
<a href={Uri::web(U::Actor, &actor_id)} class="clean hover">
|
||||
<img src={avatar} class="avatar inline mr-s" /><b>{username}</b><small>@{domain}</small>
|
||||
</a>
|
||||
}
|
||||
|
@ -20,11 +20,11 @@ pub fn ActorStrip(object: crate::Object) -> impl IntoView {
|
|||
pub fn ActorBanner(object: crate::Object) -> impl IntoView {
|
||||
match object.as_ref() {
|
||||
serde_json::Value::String(id) => view! {
|
||||
<div><b>?</b>" "<a class="clean hover" href={Uri::web(U::User, id)}>{Uri::pretty(id)}</a></div>
|
||||
<div><b>?</b>" "<a class="clean hover" href={Uri::web(U::Actor, id)}>{Uri::pretty(id)}</a></div>
|
||||
},
|
||||
serde_json::Value::Object(_) => {
|
||||
let uid = object.id().unwrap_or_default().to_string();
|
||||
let uri = Uri::web(U::User, &uid);
|
||||
let uri = Uri::web(U::Actor, &uid);
|
||||
let avatar_url = object.icon().get().map(|x| x.url().id().unwrap_or(DEFAULT_AVATAR_URL.into())).unwrap_or(DEFAULT_AVATAR_URL.into());
|
||||
let display_name = object.name().unwrap_or_default().to_string();
|
||||
let username = object.preferred_username().unwrap_or_default().to_string();
|
||||
|
|
|
@ -84,7 +84,7 @@ pub fn DebugPage() -> impl IntoView {
|
|||
" raw :: "
|
||||
<a href={move|| Uri::web(U::Object, &text.get())} >obj</a>
|
||||
" :: "
|
||||
<a href={move|| Uri::web(U::User, &text.get())} >usr</a>
|
||||
<a href={move|| Uri::web(U::Actor, &text.get())} >usr</a>
|
||||
" :: "
|
||||
<a href=move || cached_query().0 target="_blank" rel="nofollow noreferrer">ext</a>
|
||||
" :: "
|
||||
|
|
|
@ -21,9 +21,9 @@ pub fn ObjectPage(tl: Timeline) -> impl IntoView {
|
|||
let obj = Arc::new(obj);
|
||||
if let Some(author) = obj.attributed_to().id() {
|
||||
if let Ok(user) = Http::fetch::<serde_json::Value>(
|
||||
&Uri::api(U::User, &author, true), auth
|
||||
&Uri::api(U::Actor, &author, true), auth
|
||||
).await {
|
||||
CACHE.put(Uri::full(U::User, &author), Arc::new(user));
|
||||
CACHE.put(Uri::full(U::Actor, &author), Arc::new(user));
|
||||
}
|
||||
}
|
||||
CACHE.put(Uri::full(U::Object, &oid), obj.clone());
|
||||
|
|
|
@ -11,7 +11,7 @@ pub fn SearchPage() -> impl IntoView {
|
|||
let user = create_local_resource(
|
||||
move || use_query_map().get().get("q").cloned().unwrap_or_default(),
|
||||
move |q| {
|
||||
let user_fetch = Uri::api(U::User, &q, true);
|
||||
let user_fetch = Uri::api(U::Actor, &q, true);
|
||||
async move { Some(Arc::new(Http::fetch::<serde_json::Value>(&user_fetch, auth).await.ok()?)) }
|
||||
}
|
||||
);
|
||||
|
|
|
@ -27,16 +27,16 @@ pub fn UserPage(tl: Timeline) -> impl IntoView {
|
|||
.get("id")
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
let uid = uriproxy::uri(URL_BASE, uriproxy::UriClass::User, &id);
|
||||
let uid = uriproxy::uri(URL_BASE, uriproxy::UriClass::Actor, &id);
|
||||
let _uid = uid.clone();
|
||||
let actor = create_local_resource(move || _uid.clone(), move |id| {
|
||||
async move {
|
||||
match CACHE.get(&Uri::full(U::User, &id)) {
|
||||
match CACHE.get(&Uri::full(U::Actor, &id)) {
|
||||
Some(x) => Some(x.clone()),
|
||||
None => {
|
||||
let user : serde_json::Value = Http::fetch(&Uri::api(U::User, &id, true), auth).await.ok()?;
|
||||
let user : serde_json::Value = Http::fetch(&Uri::api(U::Actor, &id, true), auth).await.ok()?;
|
||||
let user = Arc::new(user);
|
||||
CACHE.put(Uri::full(U::User, &id), user.clone());
|
||||
CACHE.put(Uri::full(U::Actor, &id), user.clone());
|
||||
Some(user)
|
||||
},
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ pub fn UserPage(tl: Timeline) -> impl IntoView {
|
|||
let following = object.following_count().unwrap_or(0);
|
||||
let followers = object.followers_count().unwrap_or(0);
|
||||
let statuses = object.statuses_count().unwrap_or(0);
|
||||
let tl_url = format!("{}/outbox/page", Uri::api(U::User, &id.clone(), false));
|
||||
let tl_url = format!("{}/outbox/page", Uri::api(U::Actor, &id.clone(), false));
|
||||
if !tl.next.get().starts_with(&tl_url) {
|
||||
tl.reset(tl_url);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue