generated from scio-labs/inkathon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlib.rs
executable file
·349 lines (287 loc) · 11.9 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
#![cfg_attr(not(feature = "std"), no_std, no_main)]
#[ink::contract]
mod chatroom {
// Import necessary modules
use ink::prelude::string::String;
use ink::prelude::vec::Vec;
use ink::storage::Mapping;
#[derive(Debug, Clone, PartialEq, scale::Encode, scale::Decode)]
#[cfg_attr(
feature = "std",
derive(scale_info::TypeInfo, ink::storage::traits::StorageLayout)
)]
pub struct Message {
sender: AccountId,
content: String,
sent_timestamp: Timestamp,
}
#[derive(Debug, Clone, PartialEq, scale::Encode, scale::Decode)]
#[cfg_attr(
feature = "std",
derive(scale_info::TypeInfo, ink::storage::traits::StorageLayout)
)]
pub struct Room {
owner: AccountId,
timeout: Timestamp,
}
#[ink(storage)]
pub struct Chatroom {
chatrooms: Mapping<AccountId, Room>,
participants: Mapping<AccountId, Vec<AccountId>>,
messages: Mapping<AccountId, Vec<Message>>,
}
impl Chatroom {
// Constructor to initialize the contract
#[ink(constructor)]
pub fn new() -> Self {
Self {
chatrooms: Mapping::new(),
participants: Mapping::new(),
messages: Mapping::new(),
}
}
#[ink(message)]
pub fn create_chatroom(&mut self) -> AccountId {
// TODO: let there be optional list of participants & first message
// Create a new chatroom
let caller = self.env().caller(); // TODO
let timeout = self.env().block_timestamp() + &3600000; // 60 minutes destroy chatroom in 60 minutes
let new_chatroom = Room {
owner: Self::env().caller(),
timeout: timeout,
};
// Store the chatroom owner
self.chatrooms.insert(caller, &new_chatroom);
// Store the participants (which is just the chatroom owner at this point)
let mut new_participants = Vec::new();
new_participants.push(caller);
self.participants.insert(caller, &new_participants);
// Store the messages
let mut new_messages = Vec::new();
new_messages.push(Message {
sender: caller,
content: String::from("Welcome to whisper!"),
sent_timestamp: self.env().block_timestamp(),
});
self.messages.insert(caller, &new_messages);
caller // caller account_id is the id for the chatroom
}
#[ink(message)]
pub fn get_chatroom(&self, chatroom_id: AccountId) -> Option<Room> {
match self.chatrooms.get(chatroom_id) {
Some(chat) => Some(chat),
None => None,
}
}
#[ink(message)]
pub fn is_a_participant(&self, chatroom_id: AccountId, participant_id: AccountId) -> bool {
match self.participants.get(chatroom_id) {
Some(parts) => parts.contains(&participant_id),
None => false, // participant_id is not a member
}
}
#[ink(message)]
pub fn invite(&mut self, chatroom_id: AccountId, participant: AccountId) {
let chatroom = self.get_chatroom(chatroom_id.clone()).unwrap();
// Ensure only the owner can invite participants
assert_eq!(
chatroom.owner,
self.env().caller(),
"Only owner can invite participants"
);
// update participants vector in chatroom
let mut participants_list = self.participants.get(chatroom.owner).unwrap();
participants_list.push(participant);
self.participants
.insert(self.env().caller(), &participants_list);
}
#[ink(message)]
pub fn send_message(&mut self, chatroom_id: AccountId, message: String) {
let caller = self.env().caller();
// Ensure the sender is a participant of the chatroom
match self.participants.get(&chatroom_id) {
Some(participants_list) => {
assert!(
participants_list.contains(&caller),
"Sender is not a participant of the chatroom"
);
}
None => panic!("Chatroom doesn't exist"),
};
let mut messages = self.messages.get(chatroom_id).unwrap();
messages.push(Message {
sender: caller,
content: message,
sent_timestamp: self.env().block_timestamp(),
});
self.messages.insert(chatroom_id, &messages);
}
#[ink(message)]
pub fn get_messages(&self, chatroom_id: AccountId) -> Vec<Message> {
let caller = self.env().caller();
// Ensure the sender is a participant of the chatroom
match self.participants.get(&chatroom_id) {
Some(participants_list) => {
assert!(
participants_list.contains(&caller),
"Sender is not a participant of the chatroom"
);
}
None => panic!("Chatroom doesn't exist"),
};
self.messages.get(chatroom_id).unwrap()
}
#[ink(message)]
pub fn delete_chatroom(&mut self, chatroom_id: AccountId) {
let chatroom = self.get_chatroom(chatroom_id).unwrap();
// Ensure only the owner can delete the chatroom
assert_eq!(
chatroom.owner.clone(),
self.env().caller(),
"Only owner can delete the chatroom"
);
// delete the contract from storage
self.chatrooms.remove(chatroom.owner);
}
#[ink(message)]
pub fn set_timeout(&mut self, chatroom_id: AccountId, timeout: Timestamp) {
let mut chatroom = self.get_chatroom(chatroom_id).unwrap();
// Ensure only the owner can set the timeout
assert_eq!(
chatroom.owner.clone(),
self.env().caller(),
"Only owner can set timeout"
);
// Set the timeout
chatroom.timeout = timeout;
}
#[ink(message)]
pub fn check_timeout(&mut self, chatroom_id: AccountId) {
let chatroom = self.get_chatroom(chatroom_id).unwrap();
// Ensure only the owner can check timeout
assert_eq!(
chatroom.owner.clone(),
self.env().caller(),
"Only owner can check timeout"
);
// Get the current timestamp
let current_time = self.env().block_timestamp();
// Check if the timeout has expired
if current_time >= chatroom.timeout {
// delete the contract from storage
self.chatrooms.remove(chatroom.owner);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[ink::test]
fn new_works() {
let account = AccountId::from([0x1; 32]);
ink::env::test::set_caller::<ink::env::DefaultEnvironment>(account);
let mut chatroom = Chatroom::new();
let chatroom_id = chatroom.create_chatroom();
assert_eq!(chatroom_id, account);
}
#[ink::test]
fn create_chatroom_works() {}
#[ink::test]
fn get_chatroom_works() {
let account = AccountId::from([0x1; 32]);
ink::env::test::set_caller::<ink::env::DefaultEnvironment>(account);
let mut chatroom = Chatroom::new();
chatroom.create_chatroom();
let chatroom_id = chatroom.get_chatroom(account).unwrap();
assert_eq!(chatroom_id.owner, account);
}
#[ink::test]
fn invite_works() {
let account1 = AccountId::from([0x1; 32]);
let account2 = AccountId::from([0x2; 32]);
ink::env::test::set_caller::<ink::env::DefaultEnvironment>(account1);
let mut chatroom = Chatroom::new();
chatroom.create_chatroom();
// invite account2
chatroom.invite(account1.clone(), account2.clone());
// check participants list for account2
assert!(
chatroom
.participants
.get(account1)
.unwrap()
.contains(&account2),
"Account is not a participant"
);
}
#[ink::test]
fn send_message_works() {
let accounts = ink::env::test::default_accounts::<ink::env::DefaultEnvironment>();
let chatroom_id = accounts.bob.clone();
ink::env::test::set_caller::<ink::env::DefaultEnvironment>(chatroom_id);
let mut chatroom = Chatroom::new();
chatroom.create_chatroom();
// invite alice & charlie
chatroom.invite(chatroom_id, accounts.alice);
chatroom.invite(chatroom_id, accounts.charlie);
// test to see if member is a participant
// account 2 send message
ink::env::test::set_caller::<ink::env::DefaultEnvironment>(accounts.alice); // set account2 as the current caller
let message1 = String::from("This is the first message");
chatroom.send_message(chatroom_id, message1.clone());
// check message1
assert!(
chatroom
.messages
.get(chatroom_id)
.unwrap()
.iter()
.any(|e| e.content == message1),
"Message does not exist"
);
// account 3 send message
ink::env::test::set_caller::<ink::env::DefaultEnvironment>(accounts.charlie); // set account3 as the current caller
let message2 = String::from("Do or do not, there's no try");
chatroom.send_message(chatroom_id, message2.clone());
// check message2
assert!(
chatroom
.messages
.get(chatroom_id)
.unwrap()
.iter()
.any(|e| e.content == message2),
"Message does not exist"
);
}
#[ink::test]
#[should_panic]
fn should_not_delete_chatroom_works() {
let accounts = ink::env::test::default_accounts::<ink::env::DefaultEnvironment>();
let chatroom_id = accounts.bob.clone();
ink::env::test::set_caller::<ink::env::DefaultEnvironment>(chatroom_id);
let mut chatroom = Chatroom::new();
chatroom.create_chatroom();
// invite alice & charlie
chatroom.invite(chatroom_id, accounts.alice);
// attempt to delete chatroom by alice, should panic
ink::env::test::set_caller::<ink::env::DefaultEnvironment>(accounts.alice);
chatroom.delete_chatroom(chatroom_id);
}
#[ink::test]
fn is_a_participant_works() {
let accounts = ink::env::test::default_accounts::<ink::env::DefaultEnvironment>();
let chatroom_id = accounts.bob.clone();
ink::env::test::set_caller::<ink::env::DefaultEnvironment>(chatroom_id);
let mut chatroom = Chatroom::new();
chatroom.create_chatroom();
// invite alice & charlie
chatroom.invite(chatroom_id, accounts.alice);
chatroom.invite(chatroom_id, accounts.charlie);
assert!(chatroom.is_a_participant(chatroom_id, accounts.alice));
assert!(!chatroom.is_a_participant(chatroom_id, accounts.eve)); // eve has not been invited, so it should fail
// test to see if member is a participant
}
// TODO write a test for auto delete after 60 minutes
}
}