diff --git a/README.md b/README.md index 81eceb74..fb99d301 100644 --- a/README.md +++ b/README.md @@ -165,3 +165,9 @@ ts-node translation_report.ts ## Credits Logo made by Andy Cuccaro (@andycuccaro) under the CC-BY-SA 4.0 license. + +## License + +All code is licensed under AGPLv3 unless otherwise indicated. + +The code in `server/src/activitypub` is taken from the [Aardwolf/activitypub](https://crates.io/crates/activitypub) crate and licensed under GPLv3. diff --git a/server/Cargo.lock b/server/Cargo.lock index 12531920..242fa789 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -1493,11 +1493,15 @@ name = "lemmy_server" version = "0.0.1" dependencies = [ "activitypub 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "activitystreams-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "activitystreams-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "activitystreams-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "actix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "actix-files 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "actix-rt 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "actix-web 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "actix-web-actors 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "bcrypt 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "config 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1517,6 +1521,7 @@ dependencies = [ "reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", "rss 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "strum 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/server/Cargo.toml b/server/Cargo.toml index 82823057..1b6ea305 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -13,6 +13,7 @@ activitypub = "0.2.0" chrono = { version = "0.4.7", features = ["serde"] } failure = "0.1.5" serde_json = { version = "1.0.45", features = ["preserve_order"]} +serde_derive = "1.0" serde = { version = "1.0.94", features = ["derive"] } actix = "0.9.0" actix-web = "2.0.0" @@ -33,4 +34,11 @@ rss = "1.9.0" htmlescape = "0.3.1" config = "0.10.1" hjson = "0.8.2" -reqwest = "0.9.24" \ No newline at end of file +reqwest = "0.9.24" +activitystreams-derive = "0.2" +activitystreams-traits = "0.2" +activitystreams-types = "0.3" + + +[dev-dependencies] +anyhow = "1.0" diff --git a/server/src/activitypub/activity.rs b/server/src/activitypub/activity.rs new file mode 100644 index 00000000..c92b6eaf --- /dev/null +++ b/server/src/activitypub/activity.rs @@ -0,0 +1,1496 @@ +/* + * This file is part of ActivityPub. + * + * Copyright © 2018 Riley Trautman + * + * ActivityPub is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ActivityPub is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ActivityPub. If not, see . + */ + +//! Activity traits and types + +pub use activitystreams_traits::{Activity, IntransitiveActivity}; +pub use activitystreams_types::activity::{kind, properties, ActivityExt}; +use serde_derive::{Deserialize, Serialize}; + +use self::{kind::*, properties::*}; +use activitypub::object::{ + properties::{ApObjectProperties, ObjectProperties}, + ApObjectExt, Object, ObjectExt, +}; + +/// Indicates that the actor accepts the object. +/// +/// The target property can be used in certain circumstances to indicate the context into which the +/// object has been accepted. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Accept { + #[serde(rename = "type")] + kind: AcceptType, + + #[serde(flatten)] + pub accept_props: AcceptProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Accept {} +impl ObjectExt for Accept { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Accept { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Accept {} +impl ActivityExt for Accept { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor has added the object to the target. +/// +/// If the target property is not explicitly specified, the target would need to be determined +/// implicitly by context. The origin can be used to identify the context from which the object +/// originated. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Add { + #[serde(rename = "type")] + kind: AddType, + + #[serde(flatten)] + pub add_props: AddProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Add {} +impl ObjectExt for Add { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Add { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Add {} +impl ActivityExt for Add { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor has moved object from origin to target. +/// +/// If the origin or target are not specified, either can be determined by context. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AMove { + #[serde(rename = "type")] + kind: MoveType, + + #[serde(flatten)] + pub move_props: MoveProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for AMove {} +impl ObjectExt for AMove { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for AMove { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for AMove {} +impl ActivityExt for AMove { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor is calling the target's attention the object. +/// +/// The origin typically has no defined meaning. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Announce { + #[serde(rename = "type")] + kind: AnnounceType, + + #[serde(flatten)] + pub announce_props: AnnounceProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Announce {} +impl ObjectExt for Announce { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Announce { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Announce {} +impl ActivityExt for Announce { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// An IntransitiveActivity that indicates that the actor has arrived at the location. +/// +/// The origin can be used to identify the context from which the actor originated. The target +/// typically has no defined meaning. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Arrive { + #[serde(rename = "type")] + kind: ArriveType, + + #[serde(flatten)] + pub arrive_props: ArriveProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Arrive {} +impl ObjectExt for Arrive { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Arrive { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Arrive {} +impl ActivityExt for Arrive { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} +impl IntransitiveActivity for Arrive {} + +/// Indicates that the actor is blocking the object. +/// +/// Blocking is a stronger form of Ignore. The typical use is to support social systems that allow +/// one user to block activities or content of other users. The target and origin typically have no +/// defined meaning. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Block { + #[serde(rename = "type")] + kind: BlockType, + + #[serde(flatten)] + pub block_props: BlockProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Block {} +impl ObjectExt for Block { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Block { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Block {} +impl ActivityExt for Block { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor has created the object. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Create { + #[serde(rename = "type")] + kind: CreateType, + + #[serde(flatten)] + pub create_props: CreateProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Create {} +impl ObjectExt for Create { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Create { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Create {} +impl ActivityExt for Create { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor has deleted the object. +/// +/// If specified, the origin indicates the context from which the object was deleted. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Delete { + #[serde(rename = "type")] + kind: DeleteType, + + #[serde(flatten)] + pub delete_props: DeleteProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Delete {} +impl ObjectExt for Delete { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Delete { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Delete {} +impl ActivityExt for Delete { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor dislikes the object. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Dislike { + #[serde(rename = "type")] + kind: DislikeType, + + #[serde(flatten)] + pub dislike_props: DislikeProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Dislike {} +impl ObjectExt for Dislike { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Dislike { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Dislike {} +impl ActivityExt for Dislike { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor is "flagging" the object. +/// +/// Flagging is defined in the sense common to many social platforms as reporting content as being +/// inappropriate for any number of reasons. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Flag { + #[serde(rename = "type")] + kind: FlagType, + + #[serde(flatten)] + pub flag_props: FlagProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Flag {} +impl ObjectExt for Flag { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Flag { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Flag {} +impl ActivityExt for Flag { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor is "following" the object. +/// +/// Following is defined in the sense typically used within Social systems in which the actor is +/// interested in any activity performed by or on the object. The target and origin typically have +/// no defined meaning. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Follow { + #[serde(rename = "type")] + kind: FollowType, + + #[serde(flatten)] + pub follow_props: FollowProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Follow {} +impl ObjectExt for Follow { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Follow { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Follow {} +impl ActivityExt for Follow { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor is ignoring the object. +/// +/// The target and origin typically have no defined meaning. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Ignore { + #[serde(rename = "type")] + kind: IgnoreType, + + #[serde(flatten)] + pub ignore_props: IgnoreProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Ignore {} +impl ObjectExt for Ignore { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Ignore { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Ignore {} +impl ActivityExt for Ignore { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// A specialization of Offer in which the actor is extending an invitation for the object to the +/// target. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Invite { + #[serde(rename = "type")] + kind: InviteType, + + #[serde(flatten)] + pub invite_props: InviteProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Invite {} +impl ObjectExt for Invite { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Invite { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Invite {} +impl ActivityExt for Invite { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor has joined the object. +/// +/// The target and origin typically have no defined meaning +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Join { + #[serde(rename = "type")] + kind: JoinType, + + #[serde(flatten)] + pub join_props: JoinProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Join {} +impl ObjectExt for Join { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Join { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Join {} +impl ActivityExt for Join { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor has left the object. +/// +/// The target and origin typically have no meaning. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Leave { + #[serde(rename = "type")] + kind: LeaveType, + + #[serde(flatten)] + pub leave_props: LeaveProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Leave {} +impl ObjectExt for Leave { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Leave { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Leave {} +impl ActivityExt for Leave { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor likes, recommends or endorses the object. +/// +/// The target and origin typically have no defined meaning. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Like { + #[serde(rename = "type")] + kind: LikeType, + + #[serde(flatten)] + pub like_props: LikeProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Like {} +impl ObjectExt for Like { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Like { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Like {} +impl ActivityExt for Like { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor has listened to the object. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Listen { + #[serde(rename = "type")] + kind: ListenType, + + #[serde(flatten)] + pub listen_props: ListenProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Listen {} +impl ObjectExt for Listen { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Listen { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Listen {} +impl ActivityExt for Listen { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor is offering the object. +/// +/// If specified, the target indicates the entity to which the object is being offered. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Offer { + #[serde(rename = "type")] + kind: OfferType, + + #[serde(flatten)] + pub offer_props: OfferProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Offer {} +impl ObjectExt for Offer { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Offer { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Offer {} +impl ActivityExt for Offer { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Represents a question being asked. +/// +/// Question objects are an extension of IntransitiveActivity. That is, the Question object is an +/// Activity, but the direct object is the question itself and therefore it would not contain an +/// object property. +/// +/// Either of the anyOf and oneOf properties MAY be used to express possible answers, but a +/// Question object MUST NOT have both properties. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Question { + #[serde(rename = "type")] + kind: QuestionType, + + #[serde(flatten)] + pub question_props: QuestionProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Question {} +impl ObjectExt for Question { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Question { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Question {} +impl ActivityExt for Question { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} +impl IntransitiveActivity for Question {} + +/// Indicates that the actor has read the object. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Read { + #[serde(rename = "type")] + kind: ReadType, + + #[serde(flatten)] + pub read_props: ReadProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Read {} +impl ObjectExt for Read { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Read { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Read {} +impl ActivityExt for Read { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor is rejecting the object. +/// +/// The target and origin typically have no defined meaning. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Reject { + #[serde(rename = "type")] + kind: RejectType, + + #[serde(flatten)] + pub reject_props: RejectProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Reject {} +impl ObjectExt for Reject { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Reject { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Reject {} +impl ActivityExt for Reject { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor is removing the object. +/// +/// If specified, the origin indicates the context from which the object is being removed. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Remove { + #[serde(rename = "type")] + kind: RemoveType, + + #[serde(flatten)] + pub remove_props: RemoveProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Remove {} +impl ObjectExt for Remove { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Remove { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Remove {} +impl ActivityExt for Remove { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// A specialization of Accept indicating that the acceptance is tentative. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TentativeAccept { + #[serde(rename = "type")] + kind: TentativeAcceptType, + + #[serde(flatten)] + pub tentative_accept_props: TentativeAcceptProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for TentativeAccept {} +impl ObjectExt for TentativeAccept { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for TentativeAccept { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for TentativeAccept {} +impl ActivityExt for TentativeAccept { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// A specialization of Reject in which the rejection is considered tentative. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TentativeReject { + #[serde(rename = "type")] + kind: TentativeRejectType, + + #[serde(flatten)] + pub tentative_reject_props: TentativeRejectProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for TentativeReject {} +impl ObjectExt for TentativeReject { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for TentativeReject { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for TentativeReject {} +impl ActivityExt for TentativeReject { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor is traveling to target from origin. +/// +/// Travel is an IntransitiveObject whose actor specifies the direct object. If the target or +/// origin are not specified, either can be determined by context. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Travel { + #[serde(rename = "type")] + kind: TravelType, + + #[serde(flatten)] + pub travel_props: TravelProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Travel {} +impl ObjectExt for Travel { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Travel { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Travel {} +impl ActivityExt for Travel { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} +impl IntransitiveActivity for Travel {} + +/// Indicates that the actor is undoing the object. +/// +/// In most cases, the object will be an Activity describing some previously performed action (for +/// instance, a person may have previously "liked" an article but, for whatever reason, might +/// choose to undo that like at some later point in time). +/// +/// The target and origin typically have no defined meaning. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Undo { + #[serde(rename = "type")] + kind: UndoType, + + #[serde(flatten)] + pub undo_props: UndoProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Undo {} +impl ObjectExt for Undo { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Undo { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Undo {} +impl ActivityExt for Undo { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor has updated the object. +/// +/// Note, however, that this vocabulary does not define a mechanism for describing the actual set +/// of modifications made to object. +/// +/// The target and origin typically have no defined meaning. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Update { + #[serde(rename = "type")] + kind: UpdateType, + + #[serde(flatten)] + pub update_props: UpdateProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for Update {} +impl ObjectExt for Update { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Update { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for Update {} +impl ActivityExt for Update { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} + +/// Indicates that the actor has viewed the object. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct View { + #[serde(rename = "type")] + kind: ViewType, + + #[serde(flatten)] + pub view_props: ViewProperties, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Object for View {} +impl ObjectExt for View { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for View { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Activity for View {} +impl ActivityExt for View { + fn props(&self) -> &ActivityProperties { + &self.activity_props + } + + fn props_mut(&mut self) -> &mut ActivityProperties { + &mut self.activity_props + } +} diff --git a/server/src/activitypub/actor/mod.rs b/server/src/activitypub/actor/mod.rs new file mode 100644 index 00000000..adb0b2d5 --- /dev/null +++ b/server/src/activitypub/actor/mod.rs @@ -0,0 +1,291 @@ +/* + * This file is part of ActivityPub. + * + * Copyright © 2018 Riley Trautman + * + * ActivityPub is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ActivityPub is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ActivityPub. If not, see . + */ + +//! Actor traits and types + +use activitystreams_derive::Properties; +pub use activitystreams_traits::Actor; +pub use activitystreams_types::actor::kind; +use serde_derive::{Deserialize, Serialize}; + +pub mod properties; + +use self::{kind::*, properties::*}; +use activitypub::object::{ + properties::{ApObjectProperties, ObjectProperties}, + ApObjectExt, Object, ObjectExt, +}; + +/// The ActivityPub Actor Extension Trait +/// +/// This trait provides generic access to an activitypub actor's properties +pub trait ApActorExt: Actor { + fn props(&self) -> &ApActorProperties; + fn props_mut(&mut self) -> &mut ApActorProperties; +} + +/// Describes a software application. +#[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] +#[serde(rename_all = "camelCase")] +pub struct Application { + #[serde(rename = "type")] + kind: ApplicationType, + + /// Adds all valid object properties to this struct + #[serde(flatten)] + pub object_props: ObjectProperties, + + /// Adds all valid activitypub object properties to this struct + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + /// Adds all valid activitypub actor properties to this struct + #[serde(flatten)] + pub ap_actor_props: ApActorProperties, +} + +impl Object for Application {} +impl ObjectExt for Application { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Application { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Actor for Application {} +impl ApActorExt for Application { + fn props(&self) -> &ApActorProperties { + &self.ap_actor_props + } + + fn props_mut(&mut self) -> &mut ApActorProperties { + &mut self.ap_actor_props + } +} + +/// Represents a formal or informal collective of Actors. +#[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] +#[serde(rename_all = "camelCase")] +pub struct Group { + #[serde(rename = "type")] + kind: GroupType, + + /// Adds all valid object properties to this struct + #[serde(flatten)] + pub object_props: ObjectProperties, + + /// Adds all valid activitypub object properties to this struct + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + /// Adds all valid activitypub actor properties to this struct + #[serde(flatten)] + pub ap_actor_props: ApActorProperties, +} + +impl Object for Group {} +impl ObjectExt for Group { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Group { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Actor for Group {} +impl ApActorExt for Group { + fn props(&self) -> &ApActorProperties { + &self.ap_actor_props + } + + fn props_mut(&mut self) -> &mut ApActorProperties { + &mut self.ap_actor_props + } +} + +/// Represents an organization. +#[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] +#[serde(rename_all = "camelCase")] +pub struct Organization { + #[serde(rename = "type")] + kind: OrganizationType, + + /// Adds all valid object properties to this struct + #[serde(flatten)] + pub object_props: ObjectProperties, + + /// Adds all valid activitypub object properties to this struct + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + /// Adds all valid activitypub actor properties to this struct + #[serde(flatten)] + pub ap_actor_props: ApActorProperties, +} + +impl Object for Organization {} +impl ObjectExt for Organization { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Organization { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Actor for Organization {} +impl ApActorExt for Organization { + fn props(&self) -> &ApActorProperties { + &self.ap_actor_props + } + + fn props_mut(&mut self) -> &mut ApActorProperties { + &mut self.ap_actor_props + } +} + +/// Represents an individual person. +#[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] +#[serde(rename_all = "camelCase")] +pub struct Person { + #[serde(rename = "type")] + kind: PersonType, + + /// Adds all valid object properties to this struct + #[serde(flatten)] + pub object_props: ObjectProperties, + + /// Adds all valid activitypub object properties to this struct + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + /// Adds all valid activitypub actor properties to this struct + #[serde(flatten)] + pub ap_actor_props: ApActorProperties, +} + +impl Object for Person {} +impl ObjectExt for Person { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Person { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Actor for Person {} +impl ApActorExt for Person { + fn props(&self) -> &ApActorProperties { + &self.ap_actor_props + } + + fn props_mut(&mut self) -> &mut ApActorProperties { + &mut self.ap_actor_props + } +} + +/// Represents a service of any kind. +#[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] +#[serde(rename_all = "camelCase")] +pub struct Service { + #[serde(rename = "type")] + kind: ServiceType, + + /// Adds all valid object properties to this struct + #[serde(flatten)] + pub object_props: ObjectProperties, + + /// Adds all valid activitypub object properties to this struct + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + /// Adds all valid activitypub actor properties to this struct + #[serde(flatten)] + pub ap_actor_props: ApActorProperties, +} + +impl Object for Service {} +impl ObjectExt for Service { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Service { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Actor for Service {} +impl ApActorExt for Service { + fn props(&self) -> &ApActorProperties { + &self.ap_actor_props + } + + fn props_mut(&mut self) -> &mut ApActorProperties { + &mut self.ap_actor_props + } +} diff --git a/server/src/activitypub/actor/properties.rs b/server/src/activitypub/actor/properties.rs new file mode 100644 index 00000000..9b7f38aa --- /dev/null +++ b/server/src/activitypub/actor/properties.rs @@ -0,0 +1,129 @@ +/* + * This file is part of ActivityPub. + * + * Copyright © 2018 Riley Trautman + * + * ActivityPub is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ActivityPub is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ActivityPub. If not, see . + */ + +//! Namespace for properties of standard Actor types +//! +//! To use these properties in your own types, you can flatten them into your struct with serde: +//! +//! ```rust +//! use activitypub::{Object, Actor, actor::properties::ApActorProperties}; +//! use serde_derive::{Deserialize, Serialize}; +//! +//! #[derive(Clone, Debug, Serialize, Deserialize)] +//! #[serde(rename_all = "camelCase")] +//! pub struct MyActor { +//! #[serde(rename = "type")] +//! pub kind: String, +//! +//! /// Define a require property for the MyActor type +//! pub my_property: String, +//! +//! #[serde(flatten)] +//! pub actor_props: ApActorProperties, +//! } +//! +//! impl Object for MyActor {} +//! impl Actor for MyActor {} +//! # +//! # fn main() {} +//! ``` + +use activitystreams_derive::Properties; +use serde_derive::{Deserialize, Serialize}; + +use crate::activitypub::endpoint::Endpoint; + +/// Define activitypub properties for the Actor type as described by the Activity Pub vocabulary. +#[derive(Clone, Debug, Default, Deserialize, Properties, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ApActorProperties { + // TODO: IRI + /// A reference to an [[ActivityStreams](https://www.w3.org/ns/activitystreams)] + /// OrderedCollection comprised of all the messages received by the actor. + /// + /// - Range: `anyUri` + /// - Functional: true + #[activitystreams(concrete(String), functional)] + pub inbox: serde_json::Value, + + // TODO: IRI + /// An [ActivityStreams](https://www.w3.org/ns/activitystreams)] OrderedCollection comprised of + /// all the messages produced by the actor. + /// + /// - Range: `anyUri` + /// - Functional: true + #[activitystreams(concrete(String), functional)] + pub outbox: serde_json::Value, + + // TODO: IRI + /// A link to an [[ActivityStreams](https://www.w3.org/ns/activitystreams)] collection of the + /// actors that this actor is following. + /// + /// - Range: `anyUri` + /// - Functional: true + #[activitystreams(concrete(String), functional)] + pub following: Option, + + // TODO: IRI + /// A link to an [[ActivityStreams](https://www.w3.org/ns/activitystreams)] collection of the + /// actors that follow this actor. + /// + /// - Range: `anyUri` + /// - Functional: true + #[activitystreams(concrete(String), functional)] + pub followers: Option, + + // TODO: IRI + /// A link to an [[ActivityStreams](https://www.w3.org/ns/activitystreams)] collection of + /// objects this actor has liked. + /// + /// - Range: `anyUri` + /// - Functional: true + #[activitystreams(concrete(String), functional)] + pub liked: Option, + + // TODO: IRI + /// A list of supplementary Collections which may be of interest. + /// + /// - Range: `anyUri` + /// - Functional: false + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(concrete(String))] + pub streams: Option, + + /// A short username which may be used to refer to the actor, with no uniqueness guarantees. + /// + /// - Range: `anyUri` + /// - Functional: true + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(concrete(String), functional)] + pub preferred_username: Option, + + /// A json object which maps additional (typically server/domain-wide) endpoints which may be + /// useful either for this actor or someone referencing this actor. + /// + /// This mapping may be nested inside the actor document as the value or may be a link to a + /// JSON-LD document with these properties. + /// + /// - Range: `Endpoint` + /// - Functional: true + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(concrete(Endpoint), functional)] + pub endpoints: Option, +} diff --git a/server/src/activitypub/collection.rs b/server/src/activitypub/collection.rs new file mode 100644 index 00000000..8a25cce4 --- /dev/null +++ b/server/src/activitypub/collection.rs @@ -0,0 +1,264 @@ +/* + * This file is part of ActivityPub. + * + * Copyright © 2018 Riley Trautman + * + * ActivityPub is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ActivityPub is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ActivityPub. If not, see . + */ + +//! Collection traits and types + +use activitystreams_derive::Properties; +pub use activitystreams_traits::{Collection, CollectionPage}; +pub use activitystreams_types::collection::{kind, properties, CollectionExt, CollectionPageExt}; +use serde_derive::{Deserialize, Serialize}; + +use self::{kind::*, properties::*}; +use activitypub::object::{ + properties::{ApObjectProperties, ObjectProperties}, + ApObjectExt, Object, ObjectExt, +}; + +/// The default `Collection` type. +#[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] +#[serde(rename_all = "camelCase")] +pub struct UnorderedCollection { + #[serde(rename = "type")] + kind: CollectionType, + + /// Adds all valid object properties to this struct + #[serde(flatten)] + pub object_props: ObjectProperties, + + /// Adds all valid ap object properties to this struct + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + /// Adds all valid collection properties to this struct + #[serde(flatten)] + pub collection_props: CollectionProperties, +} + +impl Object for UnorderedCollection {} +impl ObjectExt for UnorderedCollection { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for UnorderedCollection { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Collection for UnorderedCollection {} +impl CollectionExt for UnorderedCollection { + fn props(&self) -> &CollectionProperties { + &self.collection_props + } + + fn props_mut(&mut self) -> &mut CollectionProperties { + &mut self.collection_props + } +} + +/// Used to represent distinct subsets of items from a `Collection`. +#[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] +#[serde(rename_all = "camelCase")] +pub struct UnorderedCollectionPage { + #[serde(rename = "type")] + kind: CollectionPageType, + + /// Adds all valid object properties to this struct + #[serde(flatten)] + pub object_props: ObjectProperties, + + /// Adds all valid ap object properties to this struct + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + /// Adds all valid collection properties to this struct + #[serde(flatten)] + pub collection_props: CollectionProperties, + + /// Adds all valid collection page properties to this struct + #[serde(flatten)] + pub collection_page_props: CollectionPageProperties, +} + +impl Object for UnorderedCollectionPage {} +impl ObjectExt for UnorderedCollectionPage { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for UnorderedCollectionPage { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Collection for UnorderedCollectionPage {} +impl CollectionExt for UnorderedCollectionPage { + fn props(&self) -> &CollectionProperties { + &self.collection_props + } + + fn props_mut(&mut self) -> &mut CollectionProperties { + &mut self.collection_props + } +} +impl CollectionPage for UnorderedCollectionPage {} +impl CollectionPageExt for UnorderedCollectionPage { + fn props(&self) -> &CollectionPageProperties { + &self.collection_page_props + } + + fn props_mut(&mut self) -> &mut CollectionPageProperties { + &mut self.collection_page_props + } +} + +/// A subtype of `Collection` in which members of the logical collection are assumed to always be +/// strictly ordered. +#[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] +#[serde(rename_all = "camelCase")] +pub struct OrderedCollection { + #[serde(rename = "type")] + kind: OrderedCollectionType, + + /// Adds all valid object properties to this struct + #[serde(flatten)] + pub object_props: ObjectProperties, + + /// Adds all valid ap object properties to this struct + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + /// Adds all valid collection properties to this struct + #[serde(flatten)] + pub collection_props: CollectionProperties, +} + +impl Object for OrderedCollection {} +impl ObjectExt for OrderedCollection { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for OrderedCollection { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Collection for OrderedCollection {} +impl CollectionExt for OrderedCollection { + fn props(&self) -> &CollectionProperties { + &self.collection_props + } + + fn props_mut(&mut self) -> &mut CollectionProperties { + &mut self.collection_props + } +} + +/// Used to represent ordered subsets of items from an `OrderedCollection`. +#[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] +#[serde(rename_all = "camelCase")] +pub struct OrderedCollectionPage { + #[serde(rename = "type")] + kind: OrderedCollectionPageType, + + /// Adds all valid object properties to this struct + #[serde(flatten)] + pub object_props: ObjectProperties, + + /// Adds all valid ap object properties to this struct + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + /// Adds all valid collection properties to this struct + #[serde(flatten)] + pub collection_props: CollectionProperties, + + /// Adds all valid collection page properties to this struct + #[serde(flatten)] + pub collection_page_props: CollectionPageProperties, + + /// Adds all valid ordered collection page properties to this struct + #[serde(flatten)] + pub ordered_collection_page_props: OrderedCollectionPageProperties, +} + +impl Object for OrderedCollectionPage {} +impl ObjectExt for OrderedCollectionPage { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for OrderedCollectionPage { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} +impl Collection for OrderedCollectionPage {} +impl CollectionExt for OrderedCollectionPage { + fn props(&self) -> &CollectionProperties { + &self.collection_props + } + + fn props_mut(&mut self) -> &mut CollectionProperties { + &mut self.collection_props + } +} +impl CollectionPage for OrderedCollectionPage {} +impl CollectionPageExt for OrderedCollectionPage { + fn props(&self) -> &CollectionPageProperties { + &self.collection_page_props + } + + fn props_mut(&mut self) -> &mut CollectionPageProperties { + &mut self.collection_page_props + } +} diff --git a/server/src/activitypub/endpoint.rs b/server/src/activitypub/endpoint.rs new file mode 100644 index 00000000..639860cf --- /dev/null +++ b/server/src/activitypub/endpoint.rs @@ -0,0 +1,107 @@ +/* + * This file is part of ActivityPub. + * + * Copyright © 2018 Riley Trautman + * + * ActivityPub is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ActivityPub is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ActivityPub. If not, see . + */ + +//! Endpoint traits and types + +use activitystreams_derive::Properties; +use serde_derive::{Deserialize, Serialize}; + +/// A json object which maps additional (typically server/domain-wide) endpoints which may be +/// useful either for this actor or someone referencing this actor. +/// +/// This mapping may be nested inside the actor document as the value or may be a link to a JSON-LD +/// document with these properties. +#[derive(Clone, Debug, Default, Deserialize, Properties, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Endpoint { + // TODO: IRI + /// Endpoint URI so this actor's clients may access remote ActivityStreams objects which + /// require authentication to access. + /// + /// To use this endpoint, the client posts an x-www-form-urlencoded id parameter with the value + /// being the id of the requested ActivityStreams object. + /// + /// - Range: `anyUri` + /// - Functional: true + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(concrete(String))] + pub proxy_url: Option, + + // TODO: IRI + /// If OAuth 2.0 bearer tokens [[RFC6749](https://tools.ietf.org/html/rfc6749)] + /// [[RFC6750](https://tools.ietf.org/html/rfc6750)] are being used for authenticating client + /// to server interactions, this endpoint specifies a URI at which a browser-authenticated user + /// may obtain a new authorization grant. + /// + /// - Range: `anyUri` + /// - Functional: true + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(concrete(String))] + pub oauth_authorization_endpoint: Option, + + // TODO: IRI + /// If OAuth 2.0 bearer tokens [[RFC6749](https://tools.ietf.org/html/rfc6749)] + /// [[RFC6750](https://tools.ietf.org/html/rfc6750)] are being used for authenticating client + /// to server interactions, this endpoint specifies a URI at which a client may acquire an + /// access token. + /// + /// - Range: `anyUri` + /// - Functional: true + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(concrete(String))] + pub oauth_token_endpoint: Option, + + // TODO: IRI + /// If Linked Data Signatures and HTTP Signatures are being used for authentication and + /// authorization, this endpoint specifies a URI at which browser-authenticated users may + /// authorize a client's public key for client to server interactions. + /// + /// - Range: `anyUri` + /// - Functional: true + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(concrete(String))] + pub provide_client_key: Option, + + // TODO: IRI + /// If Linked Data Signatures and HTTP Signatures are being used for authentication and + /// authorization, this endpoint specifies a URI at which a client key may be signed by the + /// actor's key for a time window to act on behalf of the actor in interacting with foreign + /// servers. + /// + /// - Range: `anyUri` + /// - Functional: true + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(concrete(String))] + pub sign_client_key: Option, + + // TODO: IRI + /// An optional endpoint used for wide delivery of publicly addressed activities and activities + /// sent to followers. + /// + /// `shared_inbox`endpoints SHOULD also be publicly readable `OrderedCollection` objects + /// containing objects addressed to the Public special collection. Reading from the + /// `shared_inbox` endpoint MUST NOT present objects which are not addressed to the Public + /// endpoint. + /// + /// - Range: `anyUri` + /// - Functional: true + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(concrete(String))] + pub shared_inbox: Option, +} diff --git a/server/src/activitypub/link.rs b/server/src/activitypub/link.rs new file mode 100644 index 00000000..5de09fd8 --- /dev/null +++ b/server/src/activitypub/link.rs @@ -0,0 +1,23 @@ +/* + * This file is part of ActivityPub. + * + * Copyright © 2018 Riley Trautman + * + * ActivityPub is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ActivityPub is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ActivityPub. If not, see . + */ + +//! Link traits and types + +pub use activitystreams_traits::Link; +pub use activitystreams_types::link::{kind, properties, LinkExt, Mention}; diff --git a/server/src/activitypub/mod.rs b/server/src/activitypub/mod.rs new file mode 100644 index 00000000..9e990329 --- /dev/null +++ b/server/src/activitypub/mod.rs @@ -0,0 +1,57 @@ +/* + * This file is part of ActivityPub. + * + * Copyright © 2018 Riley Trautman + * + * ActivityPub is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ActivityPub is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ActivityPub. If not, see . + */ + +//! ActivityPub +//! +//! This crate defines the base set of types from the ActivityPub specification. +//! +//! ## Example Usage +//! ```rust +//! use activitypub::{context, object::Video}; +//! use anyhow::Error; +//! +//! fn run() -> Result<(), Error> { +//! let mut video = Video::default(); +//! video.object_props.set_context_object(context())?; +//! video.ap_object_props.set_likes_string("https://my-instance.com/likes".to_owned()); +//! +//! let video_string = serde_json::to_string(&video)?; +//! +//! let video: Video = serde_json::from_str(&video_string)?; +//! +//! Ok(()) +//! } +//! ``` +pub mod activity; +pub mod actor; +pub mod collection; +mod endpoint; +pub mod link; +pub mod object; + +pub use self::{ + activity::{Activity, IntransitiveActivity}, + actor::Actor, + collection::{Collection, CollectionPage}, + endpoint::Endpoint, + link::Link, + object::Object, +}; +pub use activitystreams_traits::{properties, Error, Result}; +pub use activitystreams_types::{context, ContextObject, CustomLink, CustomObject}; diff --git a/server/src/activitypub/object/mod.rs b/server/src/activitypub/object/mod.rs new file mode 100644 index 00000000..07aa99e8 --- /dev/null +++ b/server/src/activitypub/object/mod.rs @@ -0,0 +1,444 @@ +/* + * This file is part of ActivityPub. + * + * Copyright © 2018 Riley Trautman + * + * ActivityPub is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ActivityPub is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ActivityPub. If not, see . + */ + +//! Object traits and types + +pub use activitystreams_traits::Object; +pub use activitystreams_types::object::{kind, ObjectExt}; +use serde_derive::{Deserialize, Serialize}; + +pub mod properties; + +use self::{kind::*, properties::*}; + +/// The ActivityPub Object Extension Trait +/// +/// This trait provides generic access to an activitypub object's properties +pub trait ApObjectExt: Object { + fn props(&self) -> &ApObjectProperties; + fn props_mut(&mut self) -> &mut ApObjectProperties; +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Article { + #[serde(rename = "type")] + kind: ArticleType, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, +} + +impl Object for Article {} +impl ObjectExt for Article { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Article { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Audio { + #[serde(rename = "type")] + kind: AudioType, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, +} + +impl Object for Audio {} +impl ObjectExt for Audio { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Audio { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Document { + #[serde(rename = "type")] + kind: DocumentType, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, +} + +impl Object for Document {} +impl ObjectExt for Document { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Document { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Event { + #[serde(rename = "type")] + kind: EventType, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, +} + +impl Object for Event {} +impl ObjectExt for Event { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Event { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Image { + #[serde(rename = "type")] + kind: ImageType, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, +} + +impl Object for Image {} +impl ObjectExt for Image { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Image { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Note { + #[serde(rename = "type")] + kind: NoteType, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, +} + +impl Object for Note {} +impl ObjectExt for Note { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Note { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Page { + #[serde(rename = "type")] + kind: PageType, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, +} + +impl Object for Page {} +impl ObjectExt for Page { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Page { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Place { + #[serde(rename = "type")] + kind: PlaceType, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub place_props: PlaceProperties, +} + +impl Object for Place {} +impl ObjectExt for Place { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Place { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Profile { + #[serde(rename = "type")] + kind: ProfileType, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub profile_props: ProfileProperties, +} + +impl Object for Profile {} +impl ObjectExt for Profile { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Profile { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Relationship { + #[serde(rename = "type")] + kind: RelationshipType, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub relationship_props: RelationshipProperties, +} + +impl Object for Relationship {} +impl ObjectExt for Relationship { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Relationship { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Tombstone { + #[serde(rename = "type")] + kind: TombstoneType, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, + + #[serde(flatten)] + pub tombstone_props: TombstoneProperties, +} + +impl Object for Tombstone {} +impl ObjectExt for Tombstone { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Tombstone { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Video { + #[serde(rename = "type")] + kind: VideoType, + + #[serde(flatten)] + pub object_props: ObjectProperties, + + #[serde(flatten)] + pub ap_object_props: ApObjectProperties, +} + +impl Object for Video {} +impl ObjectExt for Video { + fn props(&self) -> &ObjectProperties { + &self.object_props + } + + fn props_mut(&mut self) -> &mut ObjectProperties { + &mut self.object_props + } +} +impl ApObjectExt for Video { + fn props(&self) -> &ApObjectProperties { + &self.ap_object_props + } + + fn props_mut(&mut self) -> &mut ApObjectProperties { + &mut self.ap_object_props + } +} diff --git a/server/src/activitypub/object/properties.rs b/server/src/activitypub/object/properties.rs new file mode 100644 index 00000000..ea4f004f --- /dev/null +++ b/server/src/activitypub/object/properties.rs @@ -0,0 +1,111 @@ +/* + * This file is part of ActivityPub. + * + * Copyright © 2018 Riley Trautman + * + * ActivityPub is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ActivityPub is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ActivityPub. If not, see . + */ + +//! Namespace for properties of standard Object types +//! +//! To use these properties in your own types, you can flatten them into your struct with serde: +//! +//! ```rust +//! use activitypub::{Object, object::properties::ApObjectProperties}; +//! use serde_derive::{Deserialize, Serialize}; +//! +//! #[derive(Clone, Debug, Serialize, Deserialize)] +//! #[serde(rename_all = "camelCase")] +//! pub struct MyObject { +//! #[serde(rename = "type")] +//! pub kind: String, +//! +//! /// Define a require property for the MyObject type +//! pub my_property: String, +//! +//! #[serde(flatten)] +//! pub object_props: ApObjectProperties, +//! } +//! +//! impl Object for MyObject {} +//! # +//! # fn main() {} +//! ``` + +use super::Object; + +use activitystreams_derive::Properties; +pub use activitystreams_types::object::properties::{ + ObjectProperties, PlaceProperties, ProfileProperties, RelationshipProperties, TombstoneProperties, +}; +use serde_derive::{Deserialize, Serialize}; + +/// Define activitypub properties for the Object type as described by the Activity Pub vocabulary. +#[derive(Clone, Debug, Default, Deserialize, Properties, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ApObjectProperties { + // TODO: IRI + /// This is a list of all Announce activities with this object as the object property, added as + /// a side effect. + /// + /// The shares collection MUST be either an OrderedCollection or a Collection and MAY be + /// filtered on privileges of an authenticated user or as appropriate when no authentication is + /// given. + /// + /// - Range: `anyUri` + /// - Functional: true + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(concrete(String), functional)] + pub shares: Option, + + /// This is a list of all Like activities with this object as the object property, added as a + /// side effect. + /// + /// The likes collection MUST be either an OrderedCollection or a Collection and MAY be + /// filtered on privileges of an authenticated user or as appropriate when no authentication is + /// given. + /// + /// - Range: `anyUri` + /// - Functional: true + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(concrete(String), functional)] + pub likes: Option, + + /// The source property is intended to convey some sort of source from which the content markup + /// was derived, as a form of provenance, or to support future editing by clients. + /// + /// In general, clients do the conversion from source to content, not the other way around. + /// + /// The value of source is itself an object which uses its own content and mediaType fields to + /// supply source information. + /// + /// - Range: `Object` + /// - Functional: true + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(ab(Object), concrete(String), functional)] + pub source: Option, + + /// Servers MAY support uploading document types to be referenced in activites, such as images, + /// video or other binary data, but the precise mechanism is out of scope for this version of + /// `ActivityPub`. + /// + /// The Social Web Community Group is refining the protocol in the + /// [`ActivityPub` Media Upload report](https://www.w3.org/wiki/SocialCG/ActivityPub/MediaUpload). + /// + /// - Range: `anyUri` + /// - Functional: false + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(concrete(String))] + pub upload_media: Option, +} diff --git a/server/src/apub/community.rs b/server/src/apub/community.rs index 621d4102..bc07b319 100644 --- a/server/src/apub/community.rs +++ b/server/src/apub/community.rs @@ -1,9 +1,9 @@ +use crate::activitypub::{actor::Group, collection::UnorderedCollection, context}; use crate::apub::make_apub_endpoint; use crate::db::community::Community; use crate::db::community_view::CommunityFollowerView; use crate::db::establish_unpooled_connection; use crate::to_datetime_utc; -use activitypub::{actor::Group, collection::UnorderedCollection, context}; use actix_web::body::Body; use actix_web::web::Path; use actix_web::HttpResponse; @@ -36,8 +36,7 @@ impl Community { } if let Some(description) = &self.description { - group - .object_props.summary = Some(json!(description.to_string())); + group.object_props.summary = Some(json!(description.to_string())); } group diff --git a/server/src/apub/post.rs b/server/src/apub/post.rs index ebb17129..50b87c87 100644 --- a/server/src/apub/post.rs +++ b/server/src/apub/post.rs @@ -1,7 +1,7 @@ +use crate::activitypub::{context, object::Page}; use crate::apub::make_apub_endpoint; use crate::db::post::Post; use crate::to_datetime_utc; -use activitypub::{context, object::Page}; impl Post { pub fn as_page(&self) -> Page { diff --git a/server/src/apub/puller.rs b/server/src/apub/puller.rs index b6647060..b3177183 100644 --- a/server/src/apub/puller.rs +++ b/server/src/apub/puller.rs @@ -1,12 +1,12 @@ extern crate reqwest; use self::reqwest::Error; +use crate::activitypub::actor::Group; use crate::api::community::{GetCommunityResponse, ListCommunitiesResponse}; use crate::api::post::GetPosts; use crate::db::community_view::CommunityView; use crate::naive_now; use crate::settings::Settings; -use activitypub::actor::Group; // TODO: right now all of the data is requested on demand, for production we will need to store // things in the local database to not ruin the performance @@ -50,14 +50,34 @@ pub fn get_remote_community(identifier: String) -> Result().unwrap(), - name: name, - title: community.object_props.name.unwrap().as_str().unwrap().to_string(), // TODO: why does it still show !main@lemmy_beta:8541 + id: community + .object_props + .id + .unwrap() + .as_str() + .unwrap() + .parse::() + .unwrap(), + name, + title: community + .object_props + .name + .unwrap() + .as_str() + .unwrap() + .to_string(), // TODO: why does it still show !main@lemmy_beta:8541 description: community.object_props.summary.map(|c| c.to_string()), // TODO: this has an extra quote somehow category_id: -1, - creator_id: community.object_props.attributed_to.unwrap().as_str().unwrap().parse::().unwrap(), + creator_id: community + .object_props + .attributed_to + .unwrap() + .as_str() + .unwrap() + .parse::() + .unwrap(), removed: false, - published: naive_now(), // TODO: need to handle time conversion (or handle it in apub lib) + published: naive_now(), // TODO: need to handle time conversion (or handle it in apub lib) updated: Some(naive_now()), // TODO: community.object_props.updated deleted: false, nsfw: false, diff --git a/server/src/apub/user.rs b/server/src/apub/user.rs index 5f2421f1..fb31e4b6 100644 --- a/server/src/apub/user.rs +++ b/server/src/apub/user.rs @@ -1,8 +1,8 @@ +use crate::activitypub::{actor::Person, context}; use crate::apub::make_apub_endpoint; use crate::db::establish_unpooled_connection; use crate::db::user::User_; use crate::to_datetime_utc; -use activitypub::{actor::Person, context}; use actix_web::body::Body; use actix_web::web::Path; use actix_web::HttpResponse; diff --git a/server/src/lib.rs b/server/src/lib.rs index 3e22585d..5b37a08e 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -22,6 +22,7 @@ pub extern crate serde_json; pub extern crate sha2; pub extern crate strum; +pub mod activitypub; pub mod api; pub mod apub; pub mod db;