coop_content_types/
group_entry.rs1use crate::hdi;
2
3use std::collections::BTreeMap;
4use hdi::prelude::*;
5
6
7
8pub trait CommonFields<'a> {
11 fn published_at(&'a self) -> &'a u64;
13 fn last_updated(&'a self) -> &'a u64;
15 fn metadata(&'a self) -> &'a BTreeMap<String, rmpv::Value>;
17}
18
19#[macro_export]
36macro_rules! common_fields {
37 ( $name:ident ) => {
38 impl<'a> CommonFields<'a> for $name {
39 fn published_at(&'a self) -> &'a u64 {
40 &self.published_at
41 }
42 fn last_updated(&'a self) -> &'a u64 {
43 &self.last_updated
44 }
45 fn metadata(&'a self) -> &'a BTreeMap<String, rmpv::Value> {
46 &self.metadata
47 }
48 }
49 };
50}
51
52
53
54#[hdk_entry_helper]
59#[derive(Clone)]
60pub struct GroupEntry {
61 pub admins: Vec<AgentPubKey>,
63 pub members: Vec<AgentPubKey>,
65 pub deleted: Option<bool>,
67
68 pub published_at: u64,
70 pub last_updated: u64,
71 pub metadata: BTreeMap<String, rmpv::Value>,
72}
73common_fields!( GroupEntry );
74
75impl GroupEntry {
76 pub fn contributors(&self) -> Vec<AgentPubKey> {
78 vec![ self.admins.clone(), self.members.clone() ]
79 .into_iter()
80 .flatten()
81 .collect()
82 }
83
84 pub fn is_contributor(&self, agent: &AgentPubKey) -> bool {
86 self.contributors().contains( agent )
87 }
88
89 pub fn is_admin(&self, agent: &AgentPubKey) -> bool {
91 self.admins.contains( agent )
92 }
93
94 pub fn is_member(&self, agent: &AgentPubKey) -> bool {
96 self.members.contains( agent )
97 }
98
99 pub fn contributors_diff(&self, other: &GroupEntry) -> ContributorsDiff {
101 let added: Vec<AgentPubKey> = other.contributors()
102 .into_iter()
103 .filter(|pubkey| !self.is_contributor(pubkey) )
104 .collect();
105
106 let removed: Vec<AgentPubKey> = self.contributors()
107 .into_iter()
108 .filter(|pubkey| !other.is_contributor(pubkey) )
109 .collect();
110
111 let intersection: Vec<AgentPubKey> = self.contributors()
112 .into_iter()
113 .filter(|pubkey| other.is_contributor(pubkey) )
114 .collect();
115
116 ContributorsDiff {
117 added,
118 removed,
119 intersection,
120 }
121 }
122}
123
124#[derive(Clone, Debug, Serialize, Deserialize)]
126pub struct ContributorsDiff {
127 pub added: Vec<AgentPubKey>,
128 pub removed: Vec<AgentPubKey>,
129 pub intersection: Vec<AgentPubKey>,
130}
131
132
133
134#[hdk_entry_helper]
139#[derive(Clone)]
140pub struct ContributionsAnchorEntry( pub ActionHash, pub AgentPubKey );
141
142impl ContributionsAnchorEntry {
143 pub fn author(&self) -> &AgentPubKey {
145 &self.1
146 }
147
148 pub fn group(&self) -> &ActionHash {
150 &self.0
151 }
152}
153
154
155
156#[hdk_entry_helper]
161#[derive(Clone)]
162pub struct ArchivedContributionsAnchorEntry( String, pub ActionHash, pub AgentPubKey );
163
164impl ArchivedContributionsAnchorEntry {
165 pub fn new(group_id: ActionHash, agent: AgentPubKey) -> Self {
166 ArchivedContributionsAnchorEntry("archive".to_string(), group_id, agent)
167 }
168}
169
170impl ArchivedContributionsAnchorEntry {
171 pub fn author(&self) -> &AgentPubKey {
173 &self.2
174 }
175
176 pub fn group(&self) -> &ActionHash {
178 &self.1
179 }
180}
181
182
183#[hdk_entry_helper]
185#[serde(untagged)]
186#[derive(Clone)]
187pub enum ContributionAnchors {
188 Active(ContributionsAnchorEntry),
189 Archive(ArchivedContributionsAnchorEntry),
190}
191
192impl ContributionAnchors {
193 pub fn author(&self) -> &AgentPubKey {
195 match &self {
196 ContributionAnchors::Active(anchor) => &anchor.1,
197 ContributionAnchors::Archive(anchor) => &anchor.2,
198 }
199 }
200
201 pub fn group(&self) -> &ActionHash {
203 match &self {
204 ContributionAnchors::Active(anchor) => &anchor.0,
205 ContributionAnchors::Archive(anchor) => &anchor.1,
206 }
207 }
208
209 pub fn is_archive(&self) -> bool {
211 match &self {
212 ContributionAnchors::Active(_) => false,
213 ContributionAnchors::Archive(_) => true,
214 }
215 }
216}
217
218
219#[derive(Clone, Debug, Serialize)]
224#[serde(untagged)]
225pub enum ContributionAnchorTypes {
226 Active,
227 Archive,
228}
229
230impl<'de> serde::Deserialize<'de> for ContributionAnchorTypes {
231 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
232 where
233 D: serde::Deserializer<'de>,
234 {
235 let input : Option<String> = Deserialize::deserialize(deserializer)?;
236
237 Ok(
238 match input {
239 Some(name) => match name.to_lowercase().as_str() {
240 "active" => ContributionAnchorTypes::Active,
241 "archive" | "inactive" => ContributionAnchorTypes::Archive,
242 lw_name => Err(serde::de::Error::custom(
243 format!("No match for '{}' in ContributionAnchorTypes enum", lw_name )
244 ))?,
245 },
246 None => ContributionAnchorTypes::Active,
247 }
248 )
249 }
250}