forked from alemi/upub
feat: store like aid, also .any(&db) bikeshed
This commit is contained in:
parent
c97b35a6a7
commit
0c203528df
5 changed files with 95 additions and 72 deletions
|
@ -58,3 +58,9 @@ impl Related<super::object::Entity> for Entity {
|
|||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl Entity {
|
||||
pub fn find_by_uid_oid(uid: i64, oid: i64) -> Select<Entity> {
|
||||
Entity::find().filter(Column::Actor.eq(uid)).filter(Column::Object.eq(oid))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,3 +63,22 @@ pub fn collection(id: &str, total_items: Option<u64>) -> crate::Result<JsonLD<se
|
|||
.ld_context()
|
||||
))
|
||||
}
|
||||
|
||||
#[axum::async_trait]
|
||||
pub trait AnyQuery {
|
||||
async fn any(self, db: &sea_orm::DatabaseConnection) -> crate::Result<bool>;
|
||||
}
|
||||
|
||||
#[axum::async_trait]
|
||||
impl<T : sea_orm::EntityTrait> AnyQuery for sea_orm::Select<T> {
|
||||
async fn any(self, db: &sea_orm::DatabaseConnection) -> crate::Result<bool> {
|
||||
Ok(self.one(db).await?.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
#[axum::async_trait]
|
||||
impl<T : sea_orm::SelectorTrait + Send> AnyQuery for sea_orm::Selector<T> {
|
||||
async fn any(self, db: &sea_orm::DatabaseConnection) -> crate::Result<bool> {
|
||||
Ok(self.one(db).await?.is_some())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use sea_orm::{ActiveValue::NotSet, ColumnTrait, DatabaseConnection, EntityTrait,
|
|||
use crate::{config::Config, errors::UpubError, model, server::fetcher::Fetcher};
|
||||
use uriproxy::UriClass;
|
||||
|
||||
use super::dispatcher::Dispatcher;
|
||||
use super::{builders::AnyQuery, dispatcher::Dispatcher};
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -181,43 +181,34 @@ impl Context {
|
|||
}
|
||||
|
||||
pub async fn is_local_internal_object(&self, internal: i64) -> crate::Result<bool> {
|
||||
Ok(
|
||||
model::object::Entity::find()
|
||||
.filter(model::object::Column::Internal.eq(internal))
|
||||
.select_only()
|
||||
.select_column(model::object::Column::Internal)
|
||||
.into_tuple::<i64>()
|
||||
.one(self.db())
|
||||
.await?
|
||||
.is_some()
|
||||
)
|
||||
model::object::Entity::find()
|
||||
.filter(model::object::Column::Internal.eq(internal))
|
||||
.select_only()
|
||||
.select_column(model::object::Column::Internal)
|
||||
.into_tuple::<i64>()
|
||||
.any(self.db())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn is_local_internal_activity(&self, internal: i64) -> crate::Result<bool> {
|
||||
Ok(
|
||||
model::activity::Entity::find()
|
||||
.filter(model::activity::Column::Internal.eq(internal))
|
||||
.select_only()
|
||||
.select_column(model::activity::Column::Internal)
|
||||
.into_tuple::<i64>()
|
||||
.one(self.db())
|
||||
.await?
|
||||
.is_some()
|
||||
)
|
||||
model::activity::Entity::find()
|
||||
.filter(model::activity::Column::Internal.eq(internal))
|
||||
.select_only()
|
||||
.select_column(model::activity::Column::Internal)
|
||||
.into_tuple::<i64>()
|
||||
.any(self.db())
|
||||
.await
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub async fn is_local_internal_actor(&self, internal: i64) -> crate::Result<bool> {
|
||||
Ok(
|
||||
model::actor::Entity::find()
|
||||
.filter(model::actor::Column::Internal.eq(internal))
|
||||
.select_only()
|
||||
.select_column(model::actor::Column::Internal)
|
||||
.into_tuple::<i64>()
|
||||
.one(self.db())
|
||||
.await?
|
||||
.is_some()
|
||||
)
|
||||
model::actor::Entity::find()
|
||||
.filter(model::actor::Column::Internal.eq(internal))
|
||||
.select_only()
|
||||
.select_column(model::actor::Column::Internal)
|
||||
.into_tuple::<i64>()
|
||||
.any(self.db())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn expand_addressing(&self, targets: Vec<String>) -> crate::Result<Vec<String>> {
|
||||
|
|
|
@ -2,7 +2,7 @@ use apb::{target::Addressed, Activity, Base, Object};
|
|||
use reqwest::StatusCode;
|
||||
use sea_orm::{sea_query::Expr, ActiveValue::{Set, NotSet}, ColumnTrait, Condition, EntityTrait, QueryFilter, QuerySelect, SelectColumns};
|
||||
|
||||
use crate::{errors::{LoggableError, UpubError}, model, server::normalizer::Normalizer};
|
||||
use crate::{errors::{LoggableError, UpubError}, model, server::{builders::AnyQuery, normalizer::Normalizer}};
|
||||
|
||||
use super::{fetcher::Fetcher, Context};
|
||||
|
||||
|
@ -31,43 +31,42 @@ impl apb::server::Inbox for Context {
|
|||
let internal_uid = model::actor::Entity::ap_to_internal(&uid, self.db()).await?;
|
||||
let object_uri = activity.object().id().ok_or(UpubError::bad_request())?;
|
||||
let obj = self.fetch_object(&object_uri).await?;
|
||||
if model::like::Entity::find_by_uid_oid(internal_uid, obj.internal)
|
||||
.any(self.db())
|
||||
.await?
|
||||
{
|
||||
return Err(UpubError::not_modified());
|
||||
}
|
||||
|
||||
let activity_model = self.insert_activity(activity, Some(server)).await?;
|
||||
let like = model::like::ActiveModel {
|
||||
internal: NotSet,
|
||||
actor: Set(internal_uid),
|
||||
object: Set(obj.internal),
|
||||
published: Set(activity.published().unwrap_or(chrono::Utc::now())),
|
||||
activity: Set(activity_model.internal),
|
||||
published: Set(activity_model.published),
|
||||
};
|
||||
match model::like::Entity::insert(like).exec(self.db()).await {
|
||||
Err(sea_orm::DbErr::RecordNotInserted) => Err(UpubError::not_modified()),
|
||||
Err(sea_orm::DbErr::Exec(_)) => Err(UpubError::not_modified()), // bad fix for sqlite
|
||||
Err(e) => {
|
||||
tracing::error!("unexpected error procesing like from {uid} to {}: {e}", obj.id);
|
||||
Err(UpubError::internal_server_error())
|
||||
}
|
||||
Ok(_) => {
|
||||
let activity_model = self.insert_activity(activity, Some(server)).await?;
|
||||
let mut expanded_addressing = self.expand_addressing(activity_model.addressed()).await?;
|
||||
if expanded_addressing.is_empty() { // WHY MASTODON!!!!!!!
|
||||
expanded_addressing.push(
|
||||
model::object::Entity::find_by_id(obj.internal)
|
||||
.select_only()
|
||||
.select_column(model::object::Column::AttributedTo)
|
||||
.into_tuple::<String>()
|
||||
.one(self.db())
|
||||
.await?
|
||||
.ok_or_else(UpubError::not_found)?
|
||||
);
|
||||
}
|
||||
self.address_to(Some(activity_model.internal), None, &expanded_addressing).await?;
|
||||
model::object::Entity::update_many()
|
||||
.col_expr(model::object::Column::Likes, Expr::col(model::object::Column::Likes).add(1))
|
||||
.filter(model::object::Column::Internal.eq(obj.internal))
|
||||
.exec(self.db())
|
||||
.await?;
|
||||
tracing::info!("{} liked {}", uid, obj.id);
|
||||
Ok(())
|
||||
},
|
||||
model::like::Entity::insert(like).exec(self.db()).await?;
|
||||
model::object::Entity::update_many()
|
||||
.col_expr(model::object::Column::Likes, Expr::col(model::object::Column::Likes).add(1))
|
||||
.filter(model::object::Column::Internal.eq(obj.internal))
|
||||
.exec(self.db())
|
||||
.await?;
|
||||
let mut expanded_addressing = self.expand_addressing(activity_model.addressed()).await?;
|
||||
if expanded_addressing.is_empty() { // WHY MASTODON!!!!!!!
|
||||
expanded_addressing.push(
|
||||
model::object::Entity::find_by_id(obj.internal)
|
||||
.select_only()
|
||||
.select_column(model::object::Column::AttributedTo)
|
||||
.into_tuple::<String>()
|
||||
.one(self.db())
|
||||
.await?
|
||||
.ok_or_else(UpubError::not_found)?
|
||||
);
|
||||
}
|
||||
self.address_to(Some(activity_model.internal), None, &expanded_addressing).await?;
|
||||
tracing::info!("{} liked {}", uid, obj.id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn follow(&self, _: String, activity: serde_json::Value) -> crate::Result<()> {
|
||||
|
|
|
@ -4,7 +4,7 @@ use sea_orm::{sea_query::Expr, ActiveValue::{Set, NotSet, Unchanged}, ColumnTrai
|
|||
|
||||
use crate::{errors::UpubError, model};
|
||||
|
||||
use super::{fetcher::Fetcher, normalizer::Normalizer, Context};
|
||||
use super::{builders::AnyQuery, fetcher::Fetcher, normalizer::Normalizer, Context};
|
||||
|
||||
|
||||
#[axum::async_trait]
|
||||
|
@ -114,25 +114,33 @@ impl apb::server::Outbox for Context {
|
|||
let activity_targets = activity.addressed();
|
||||
let oid = activity.object().id().ok_or_else(UpubError::bad_request)?;
|
||||
let obj_model = self.fetch_object(&oid).await?;
|
||||
let activity_model = model::activity::ActiveModel::new(
|
||||
&activity
|
||||
.set_id(Some(&aid))
|
||||
.set_actor(Node::link(uid.clone()))
|
||||
.set_published(Some(chrono::Utc::now()))
|
||||
)?;
|
||||
|
||||
let internal_uid = model::actor::Entity::ap_to_internal(&uid, self.db()).await?;
|
||||
|
||||
if model::like::Entity::find_by_uid_oid(internal_uid, obj_model.internal)
|
||||
.any(self.db())
|
||||
.await?
|
||||
{
|
||||
return Err(UpubError::not_modified());
|
||||
}
|
||||
|
||||
let activity_model = self.insert_activity(
|
||||
activity
|
||||
.set_id(Some(&aid))
|
||||
.set_actor(Node::link(uid.clone()))
|
||||
.set_published(Some(chrono::Utc::now())),
|
||||
Some(self.domain().to_string()),
|
||||
).await?;
|
||||
|
||||
let like_model = model::like::ActiveModel {
|
||||
internal: NotSet,
|
||||
actor: Set(internal_uid),
|
||||
object: Set(obj_model.internal),
|
||||
activity: Set(activity_model.internal),
|
||||
published: Set(chrono::Utc::now()),
|
||||
};
|
||||
|
||||
model::like::Entity::insert(like_model).exec(self.db()).await?;
|
||||
model::activity::Entity::insert(activity_model)
|
||||
.exec(self.db()).await?;
|
||||
model::object::Entity::update_many()
|
||||
.col_expr(model::object::Column::Likes, Expr::col(model::object::Column::Likes).add(1))
|
||||
.filter(model::object::Column::Internal.eq(obj_model.internal))
|
||||
|
|
Loading…
Reference in a new issue