forked from alemi/upub
feat: add dislikes table, process them
not displayed anywhere yet tho
This commit is contained in:
parent
523cb8b90f
commit
5302e4ad46
8 changed files with 188 additions and 3 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -140,7 +140,7 @@ checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c"
|
|||
|
||||
[[package]]
|
||||
name = "apb"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
|
|
|
@ -50,6 +50,8 @@ pub enum Relation {
|
|||
on_delete = "NoAction"
|
||||
)]
|
||||
Instances,
|
||||
#[sea_orm(has_many = "super::dislike::Entity")]
|
||||
Dislikes,
|
||||
#[sea_orm(has_many = "super::like::Entity")]
|
||||
Likes,
|
||||
#[sea_orm(has_many = "super::mention::Entity")]
|
||||
|
@ -98,6 +100,12 @@ impl Related<super::instance::Entity> for Entity {
|
|||
}
|
||||
}
|
||||
|
||||
impl Related<super::dislike::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Dislikes.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::like::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Likes.def()
|
||||
|
|
51
upub/core/src/model/dislike.rs
Normal file
51
upub/core/src/model/dislike.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "dislikes")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub internal: i64,
|
||||
pub actor: i64,
|
||||
pub object: i64,
|
||||
pub published: ChronoDateTimeUtc,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::actor::Entity",
|
||||
from = "Column::Actor",
|
||||
to = "super::actor::Column::Internal",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Actors,
|
||||
#[sea_orm(
|
||||
belongs_to = "super::object::Entity",
|
||||
from = "Column::Object",
|
||||
to = "super::object::Column::Internal",
|
||||
on_update = "Cascade",
|
||||
on_delete = "Cascade"
|
||||
)]
|
||||
Objects,
|
||||
}
|
||||
|
||||
impl Related<super::actor::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Actors.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::object::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Objects.def()
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ pub mod job;
|
|||
pub mod relation;
|
||||
pub mod announce;
|
||||
pub mod like;
|
||||
pub mod dislike;
|
||||
|
||||
pub mod hashtag;
|
||||
pub mod mention;
|
||||
|
|
|
@ -50,6 +50,8 @@ pub enum Relation {
|
|||
Announces,
|
||||
#[sea_orm(has_many = "super::attachment::Entity")]
|
||||
Attachments,
|
||||
#[sea_orm(has_many = "super::dislike::Entity")]
|
||||
Dislikes,
|
||||
#[sea_orm(has_many = "super::hashtag::Entity")]
|
||||
Hashtags,
|
||||
#[sea_orm(has_many = "super::like::Entity")]
|
||||
|
@ -96,6 +98,12 @@ impl Related<super::attachment::Entity> for Entity {
|
|||
}
|
||||
}
|
||||
|
||||
impl Related<super::dislike::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Dislikes.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::hashtag::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::Hashtags.def()
|
||||
|
|
|
@ -39,8 +39,8 @@ impl Processor for crate::Context {
|
|||
async fn process(&self, activity: impl apb::Activity, tx: &DatabaseTransaction) -> Result<(), ProcessorError> {
|
||||
// TODO we could process Links and bare Objects maybe, but probably out of AP spec?
|
||||
match activity.activity_type()? {
|
||||
// TODO emojireacts are NOT likes, but let's process them like ones for now maybe?
|
||||
apb::ActivityType::Like | apb::ActivityType::EmojiReact => Ok(like(self, activity, tx).await?),
|
||||
apb::ActivityType::Like => Ok(like(self, activity, tx).await?),
|
||||
apb::ActivityType::Dislike => Ok(dislike(self, activity, tx).await?),
|
||||
apb::ActivityType::Create => Ok(create(self, activity, tx).await?),
|
||||
apb::ActivityType::Follow => Ok(follow(self, activity, tx).await?),
|
||||
apb::ActivityType::Announce => Ok(announce(self, activity, tx).await?),
|
||||
|
@ -115,6 +115,36 @@ pub async fn like(ctx: &crate::Context, activity: impl apb::Activity, tx: &Datab
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// TODO basically same as like, can we make one function, maybe with const generic???
|
||||
pub async fn dislike(ctx: &crate::Context, activity: impl apb::Activity, tx: &DatabaseTransaction) -> Result<(), ProcessorError> {
|
||||
let actor = ctx.fetch_user(activity.actor().id()?, tx).await?;
|
||||
let obj = ctx.fetch_object(activity.object().id()?, tx).await?;
|
||||
if crate::model::like::Entity::find_by_uid_oid(actor.internal, obj.internal)
|
||||
.any(tx)
|
||||
.await?
|
||||
{
|
||||
return Err(ProcessorError::AlreadyProcessed);
|
||||
}
|
||||
|
||||
let dislike = crate::model::dislike::ActiveModel {
|
||||
internal: NotSet,
|
||||
actor: Set(actor.internal),
|
||||
object: Set(obj.internal),
|
||||
published: Set(activity.published().unwrap_or_else(|_|chrono::Utc::now())),
|
||||
};
|
||||
|
||||
crate::model::dislike::Entity::insert(dislike).exec(tx).await?;
|
||||
|
||||
// only dislikes mentioning local users are stored to generate notifications, everything else
|
||||
// produces side effects but no activity, and thus no notification
|
||||
if ctx.is_local(&actor.id) || activity.mentioning().iter().any(|x| ctx.is_local(x)) {
|
||||
ctx.insert_activity(activity, tx).await?;
|
||||
}
|
||||
|
||||
tracing::debug!("{} disliked {}", actor.id, obj.id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn follow(ctx: &crate::Context, activity: impl apb::Activity, tx: &DatabaseTransaction) -> Result<(), ProcessorError> {
|
||||
let source_actor = crate::model::actor::Entity::find_by_ap_id(activity.actor().id()?)
|
||||
.one(tx)
|
||||
|
|
|
@ -10,6 +10,7 @@ mod m20240605_000001_add_jobs_table;
|
|||
mod m20240606_000001_add_audience_to_objects;
|
||||
mod m20240607_000001_activity_ref_is_optional;
|
||||
mod m20240609_000001_add_instance_field_to_relations;
|
||||
mod m20240623_000001_add_dislikes_table;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
|
@ -27,6 +28,7 @@ impl MigratorTrait for Migrator {
|
|||
Box::new(m20240606_000001_add_audience_to_objects::Migration),
|
||||
Box::new(m20240607_000001_activity_ref_is_optional::Migration),
|
||||
Box::new(m20240609_000001_add_instance_field_to_relations::Migration),
|
||||
Box::new(m20240623_000001_add_dislikes_table::Migration),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
85
upub/migrations/src/m20240623_000001_add_dislikes_table.rs
Normal file
85
upub/migrations/src/m20240623_000001_add_dislikes_table.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
use sea_orm_migration::prelude::*;
|
||||
|
||||
use super::m20240524_000001_create_actor_activity_object_tables::{Actors, Objects};
|
||||
|
||||
#[derive(DeriveIden)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
pub enum Dislikes {
|
||||
Table,
|
||||
Internal,
|
||||
Actor,
|
||||
Object,
|
||||
Published,
|
||||
}
|
||||
|
||||
#[derive(DeriveMigrationName)]
|
||||
pub struct Migration;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(Dislikes::Table)
|
||||
.comment("all dislike events, joining actor to object")
|
||||
.col(
|
||||
ColumnDef::new(Dislikes::Internal)
|
||||
.big_integer()
|
||||
.not_null()
|
||||
.primary_key()
|
||||
.auto_increment()
|
||||
)
|
||||
.col(ColumnDef::new(Dislikes::Actor).big_integer().not_null())
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fkey-dislikes-actor")
|
||||
.from(Dislikes::Table, Dislikes::Actor)
|
||||
.to(Actors::Table, Actors::Internal)
|
||||
.on_update(ForeignKeyAction::Cascade)
|
||||
.on_delete(ForeignKeyAction::Cascade)
|
||||
)
|
||||
.col(ColumnDef::new(Dislikes::Object).big_integer().not_null())
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fkey-dislikes-object")
|
||||
.from(Dislikes::Table, Dislikes::Object)
|
||||
.to(Objects::Table, Objects::Internal)
|
||||
.on_update(ForeignKeyAction::Cascade)
|
||||
.on_delete(ForeignKeyAction::Cascade)
|
||||
)
|
||||
.col(ColumnDef::new(Dislikes::Published).timestamp_with_time_zone().not_null().default(Expr::current_timestamp()))
|
||||
.to_owned()
|
||||
)
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_index(Index::create().name("index-dislikes-actor").table(Dislikes::Table).col(Dislikes::Actor).to_owned())
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_index(Index::create().name("index-dislikes-object").table(Dislikes::Table).col(Dislikes::Object).to_owned())
|
||||
.await?;
|
||||
|
||||
manager
|
||||
.create_index(
|
||||
Index::create()
|
||||
.unique()
|
||||
.name("index-dislikes-actor-object")
|
||||
.table(Dislikes::Table)
|
||||
.col(Dislikes::Actor)
|
||||
.col(Dislikes::Object)
|
||||
.to_owned()
|
||||
).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(Dislikes::Table).to_owned())
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue