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]]
|
[[package]]
|
||||||
name = "apb"
|
name = "apb"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|
|
@ -50,6 +50,8 @@ pub enum Relation {
|
||||||
on_delete = "NoAction"
|
on_delete = "NoAction"
|
||||||
)]
|
)]
|
||||||
Instances,
|
Instances,
|
||||||
|
#[sea_orm(has_many = "super::dislike::Entity")]
|
||||||
|
Dislikes,
|
||||||
#[sea_orm(has_many = "super::like::Entity")]
|
#[sea_orm(has_many = "super::like::Entity")]
|
||||||
Likes,
|
Likes,
|
||||||
#[sea_orm(has_many = "super::mention::Entity")]
|
#[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 {
|
impl Related<super::like::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::Likes.def()
|
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 relation;
|
||||||
pub mod announce;
|
pub mod announce;
|
||||||
pub mod like;
|
pub mod like;
|
||||||
|
pub mod dislike;
|
||||||
|
|
||||||
pub mod hashtag;
|
pub mod hashtag;
|
||||||
pub mod mention;
|
pub mod mention;
|
||||||
|
|
|
@ -50,6 +50,8 @@ pub enum Relation {
|
||||||
Announces,
|
Announces,
|
||||||
#[sea_orm(has_many = "super::attachment::Entity")]
|
#[sea_orm(has_many = "super::attachment::Entity")]
|
||||||
Attachments,
|
Attachments,
|
||||||
|
#[sea_orm(has_many = "super::dislike::Entity")]
|
||||||
|
Dislikes,
|
||||||
#[sea_orm(has_many = "super::hashtag::Entity")]
|
#[sea_orm(has_many = "super::hashtag::Entity")]
|
||||||
Hashtags,
|
Hashtags,
|
||||||
#[sea_orm(has_many = "super::like::Entity")]
|
#[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 {
|
impl Related<super::hashtag::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::Hashtags.def()
|
Relation::Hashtags.def()
|
||||||
|
|
|
@ -39,8 +39,8 @@ impl Processor for crate::Context {
|
||||||
async fn process(&self, activity: impl apb::Activity, tx: &DatabaseTransaction) -> Result<(), ProcessorError> {
|
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?
|
// TODO we could process Links and bare Objects maybe, but probably out of AP spec?
|
||||||
match activity.activity_type()? {
|
match activity.activity_type()? {
|
||||||
// TODO emojireacts are NOT likes, but let's process them like ones for now maybe?
|
apb::ActivityType::Like => Ok(like(self, activity, tx).await?),
|
||||||
apb::ActivityType::Like | apb::ActivityType::EmojiReact => 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::Create => Ok(create(self, activity, tx).await?),
|
||||||
apb::ActivityType::Follow => Ok(follow(self, activity, tx).await?),
|
apb::ActivityType::Follow => Ok(follow(self, activity, tx).await?),
|
||||||
apb::ActivityType::Announce => Ok(announce(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(())
|
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> {
|
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()?)
|
let source_actor = crate::model::actor::Entity::find_by_ap_id(activity.actor().id()?)
|
||||||
.one(tx)
|
.one(tx)
|
||||||
|
|
|
@ -10,6 +10,7 @@ mod m20240605_000001_add_jobs_table;
|
||||||
mod m20240606_000001_add_audience_to_objects;
|
mod m20240606_000001_add_audience_to_objects;
|
||||||
mod m20240607_000001_activity_ref_is_optional;
|
mod m20240607_000001_activity_ref_is_optional;
|
||||||
mod m20240609_000001_add_instance_field_to_relations;
|
mod m20240609_000001_add_instance_field_to_relations;
|
||||||
|
mod m20240623_000001_add_dislikes_table;
|
||||||
|
|
||||||
pub struct Migrator;
|
pub struct Migrator;
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ impl MigratorTrait for Migrator {
|
||||||
Box::new(m20240606_000001_add_audience_to_objects::Migration),
|
Box::new(m20240606_000001_add_audience_to_objects::Migration),
|
||||||
Box::new(m20240607_000001_activity_ref_is_optional::Migration),
|
Box::new(m20240607_000001_activity_ref_is_optional::Migration),
|
||||||
Box::new(m20240609_000001_add_instance_field_to_relations::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