upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/groups/init.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2023-05-21 11:19:28 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2023-05-21 11:19:28 +0000
commite98276e79cea0c3e474ca0251c276c474c35ed70 (patch)
treeef5149bba1c4933b86f92c7ef79368faa873de3f /src/groups/init.rs
parentfda0fdd81caab1ca92eb7ed601058e6c2fdc59f5 (diff)
groups
Diffstat (limited to 'src/groups/init.rs')
-rw-r--r--src/groups/init.rs244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/groups/init.rs b/src/groups/init.rs
new file mode 100644
index 0000000..797d190
--- /dev/null
+++ b/src/groups/init.rs
@@ -0,0 +1,244 @@
1
2use std::{str::FromStr, fmt::Debug};
3use nostr_sdk::{EventBuilder, Tag, secp256k1::XOnlyPublicKey, Keys, Event};
4use serde::{Deserialize, Serialize};
5
6use crate::{kind::Kind, ngit_tag::{tag_extract_relays, tag_admin_group_with_relays, tag_extract_value, tag_hashtag, tag_into_event}};
7
8/// [`InitializeGroup`] error
9#[derive(Debug, thiserror::Error)]
10pub enum Error {
11 /// Error serializing or deserializing JSON data
12 #[error("json error: {0}")]
13 Json(#[from] serde_json::Error),
14 // /// Error adding wrong tag kind to member_groups
15 // #[error("expecting event tag for member_groups but got: {0}")]
16 // WongMemberGroupsTagKind(String),
17 // /// Error InvalidGroupIdInTag
18 // #[error("invalid group id in member_groups tag: {0}")]
19 // InvalidGroupIdInTag(String),
20}
21
22impl InitializeGroup {
23
24 pub fn initialize(&self,keys:&Keys) -> Event {
25 // let keys = Keys::generate();
26 EventBuilder::new(
27 Kind::InitializeGroup.into_sdk_custom_kind(),
28 self.as_json(),
29 &self.generate_tags(),
30 )
31 .to_unsigned_event(keys.public_key())
32 .sign(&keys)
33 .unwrap()
34 }
35
36 fn generate_tags(&self) -> Vec<Tag> {
37 let mut tags:Vec<Tag> = vec![
38 tag_hashtag("ngit-event"),
39 tag_hashtag("ngit-format-0.0.1"),
40 ];
41 for m in &self.direct_members {
42 let key = XOnlyPublicKey::from_str(m);
43 match key {
44 Ok(k) => tags.push(Tag::PubKey(k, None)),
45 Err(error) => print!("could not add this pubkey to tag: {m} error: {error}"),
46 }
47 }
48 for m in &self.member_groups {
49 tags.push(m.clone());
50 tags.push(tag_into_event(m.clone()));
51
52 }
53 match &self.admin {
54 None => (),
55 Some(admin) => {
56 tags.push(tag_admin_group_with_relays(
57 &tag_extract_value(admin),
58 &tag_extract_relays(admin),
59 ));
60 tags.push(tag_into_event(admin.clone()));
61 },
62 };
63 tags
64 }
65}
66
67/// InitializeGroup
68#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
69pub struct InitializeGroup {
70 /// Name
71 #[serde(skip_serializing_if = "Option::is_none")]
72 pub name: Option<String>,
73 /// Description
74 #[serde(skip_serializing_if = "Option::is_none")]
75 pub about: Option<String>,
76 /// Picture
77 #[serde(skip_serializing_if = "Option::is_none")]
78 pub picture: Option<String>,
79 /// relays
80 pub relays: Vec<String>,
81 /// Direct Members
82 pub direct_members: Vec<String>,
83 /// Member Groups as group tag vector
84 pub member_groups: Vec<Tag>,
85 /// Admin
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub admin: Option<Tag>,
88
89}
90
91impl Default for InitializeGroup {
92 fn default() -> Self {
93 Self::new()
94 }
95}
96
97impl InitializeGroup {
98 /// New empty [`InitializeGroup`]
99 pub fn new() -> Self {
100 Self {
101 name: None,
102 about: None,
103 picture: None,
104 relays: vec![],
105 direct_members: vec![],
106 member_groups: vec![],
107 admin: None,
108 }
109 }
110
111 /// Deserialize [`InitializeGroup`] from `JSON` string
112 pub fn from_json<S>(json: S) -> Result<Self, Error>
113 where
114 S: Into<String>,
115 {
116 Ok(serde_json::from_str(&json.into())?)
117 }
118
119 /// Serialize [`InitializeGroup`] to `JSON` string
120 pub fn as_json(&self) -> String {
121 serde_json::json!(self).to_string()
122 }
123
124 /// Set name
125 pub fn name<S>(self, name: S) -> Self
126 where
127 S: Into<String>,
128 {
129 Self {
130 name: Some(name.into()),
131 ..self
132 }
133 }
134
135 /// Set about
136 pub fn about<S>(self, about: S) -> Self
137 where
138 S: Into<String>,
139 {
140 Self {
141 about: Some(about.into()),
142 ..self
143 }
144 }
145
146 /// Set picture
147 pub fn picture<S>(self, picture: S) -> Self
148 where
149 S: Into<String>,
150 {
151 Self {
152 picture: Some(picture.into()),
153 ..self
154 }
155 }
156
157 /// Set relays
158 pub fn relays(mut self, relays: &Vec<String>) -> Self {
159 for m in relays {
160 self.relays.push(m.clone());
161 }
162 self
163 }
164
165 /// Set members
166 pub fn members(mut self, pubkeys: Vec<String>, group_refs:Vec<Tag>) -> Self /* Result<Self,Error>*/ {
167 for m in pubkeys {
168 let key = XOnlyPublicKey::from_str(m.as_str());
169 match key {
170 Ok(_k) => self.direct_members.push(m),
171 Err(error) => print!("could not add this pubkey to members: {m} error: {error}"),
172 }
173 }
174 for group_ref in group_refs {
175 self.member_groups.push(group_ref);
176 }
177 self
178 }
179
180 /// Set admin
181 pub fn admin(self, group_ref: Tag) -> Self {
182 Self {
183 admin: Some(group_ref),
184 ..self
185 }
186 }
187}
188
189#[cfg(test)]
190mod tests {
191
192 use nostr::prelude::UncheckedUrl;
193
194 use crate::ngit_tag::{tag_group_with_relays, tag_group};
195
196 use super::*;
197
198 #[test]
199 fn test_deserialize_content() {
200 let content = r#"{
201 "name":"myname",
202 "picture":"https://www.example.com/profile.jpg",
203 "direct_members":[
204 "88a14a0df1aa0223e9f3a44cd4964fb82a19590440bb8cf1610d8c7367798314",
205 "14c27d59268ae2554d03b89c5c01dac17a604b17ac258ad345bd0648d3f5c011"
206 ],
207 "member_groups":[
208 ["group","109ca9850488d301147ac92c6ea3e1d3dd3ebe3a59dcd1151e99c7e16ef48897","ws://localhost"],
209 ["group","06bd7667a7c115fd8faf7f300302f39c019e16e6461845930686b84fbeae8c87"]
210 ],
211 "relays":["wss://relay.damus.io","ws://localhost"],
212 "admin":["admin-group","109ca9850488d301147ac92c6ea3e1d3dd3ebe3a59dcd1151e99c7e16ef48897","ws://localhost"]
213 }"#;
214 assert_eq!(
215 InitializeGroup::from_json(content).unwrap(),
216 InitializeGroup::new()
217 .name("myname")
218 // 'about' intentionally ommitted
219 .picture("https://www.example.com/profile.jpg")
220 .members(
221 vec![
222 "88a14a0df1aa0223e9f3a44cd4964fb82a19590440bb8cf1610d8c7367798314".to_string(),
223 "14c27d59268ae2554d03b89c5c01dac17a604b17ac258ad345bd0648d3f5c011".to_string(),
224 ],
225 vec![
226 tag_group_with_relays(
227 &"109ca9850488d301147ac92c6ea3e1d3dd3ebe3a59dcd1151e99c7e16ef48897".to_string(),
228 &vec!["ws://localhost".to_string()],
229 ),
230 tag_group(
231 &"06bd7667a7c115fd8faf7f300302f39c019e16e6461845930686b84fbeae8c87".to_string(),
232 ),
233 ],
234 )
235 .relays(&vec!["wss://relay.damus.io".to_string(),"ws://localhost".to_string()])
236 .admin(
237 tag_admin_group_with_relays(
238 &"109ca9850488d301147ac92c6ea3e1d3dd3ebe3a59dcd1151e99c7e16ef48897".to_string(),
239 &vec![UncheckedUrl::from_str("ws://localhost").unwrap()],
240 ),
241 )
242 );
243 }
244}