user.rs
1 use super::ActorData; 2 use crate::ACTORS; 3 use candid::{CandidType, Deserialize}; 4 use ic_cdk::api; 5 use shared::{ 6 actor::account::{AccountImage, SetUserProfileError, SetUserProfileRequest}, 7 item::ItemKey, 8 market::MarketPrincipal, 9 store::StorePrincipal, 10 }; 11 use std::{collections::BTreeMap, mem}; 12 13 pub mod basket; 14 15 use basket::Basket; 16 17 nest! { 18 #[derive(CandidType, Deserialize, Debug, Clone)] 19 pub struct UserActor { 20 #>[derive(CandidType, Deserialize, Debug, Clone)] 21 pub version: pub enum UserActorVersion { 22 V1 { 23 profile: UserProfileVersion, 24 following_markets: BTreeMap<MarketPrincipal, DataAboutFollowingMarketV1>, 25 favorite_markets: Vec<MarketPrincipal>, 26 favorite_stores: Vec<StorePrincipal>, 27 favorite_items: Vec<(StorePrincipal, ItemKey)>, 28 basket: Basket, 29 }, 30 }, 31 } 32 } 33 34 nest! { 35 #[derive(CandidType, Deserialize, Debug, Clone, PartialEq)] 36 pub enum UserProfileVersion { 37 V1( 38 #>[derive(CandidType, Deserialize, Debug, Clone, PartialEq)] 39 pub struct UserProfileV1 { 40 pub name: String, 41 pub birth_name: String, 42 pub mail_address: String, 43 pub image: AccountImage, 44 } 45 ), 46 } 47 } 48 49 #[derive(CandidType, Deserialize, Debug, Clone)] 50 pub struct DataAboutFollowingMarketV1 { 51 pub followed_time: u64, 52 pub last_bought_time: Option<u64>, 53 } 54 55 impl DataAboutFollowingMarketV1 { 56 pub fn builder() -> DataAboutFollowingMarketV1Builder { 57 DataAboutFollowingMarketV1Builder { 58 followed_time: None, 59 last_bought_time: None, 60 } 61 } 62 } 63 64 pub struct DataAboutFollowingMarketV1Builder { 65 followed_time: Option<u64>, 66 last_bought_time: Option<u64>, 67 } 68 69 impl DataAboutFollowingMarketV1Builder { 70 pub fn followed_time(mut self, followed_time: u64) -> Self { 71 self.followed_time = Some(followed_time); 72 self 73 } 74 75 pub fn last_bought_time(mut self, last_bought_time: Option<u64>) -> Self { 76 self.last_bought_time = last_bought_time; 77 self 78 } 79 80 pub fn build(self) -> DataAboutFollowingMarketV1 { 81 DataAboutFollowingMarketV1 { 82 followed_time: self.followed_time.expect("followed_time is required"), 83 last_bought_time: self.last_bought_time, 84 } 85 } 86 } 87 88 pub fn set_user_profile(request: SetUserProfileRequest) -> Result<(), SetUserProfileError> { 89 let caller = api::caller(); 90 91 let mut actor_borrowed = ACTORS.with(|actors| actors.borrow().get(&caller.into())); 92 if let Some(actor) = actor_borrowed { 93 if let ActorData::User(mut user) = actor { 94 match &mut user.version { 95 UserActorVersion::V1 { 96 profile, 97 ref mut following_markets, 98 ref mut favorite_markets, 99 ref mut favorite_stores, 100 ref mut favorite_items, 101 ref mut basket, 102 .. 103 } => { 104 let new_profile = UserProfileVersion::V1(UserProfileV1 { 105 name: request.name, 106 birth_name: request.birth_name, 107 mail_address: request.mail_address, 108 image: request.image, 109 }); 110 111 if profile != &new_profile { 112 // Move existing values to a new instance 113 actor_borrowed = Some(ActorData::User(UserActor { 114 version: UserActorVersion::V1 { 115 profile: new_profile, 116 // Reusing existing values with move semantics 117 following_markets: mem::take(following_markets), 118 favorite_markets: mem::take(favorite_markets), 119 favorite_stores: mem::take(favorite_stores), 120 favorite_items: mem::take(favorite_items), 121 basket: mem::take(basket), 122 }, 123 })); 124 125 let _ = ACTORS.with(|actors| { 126 actors 127 .borrow_mut() 128 .insert(caller.into(), actor_borrowed.unwrap()) 129 }); 130 } 131 } 132 } 133 } else { 134 return Err(SetUserProfileError::AccountIsNotUser(caller)); 135 } 136 } else { 137 return Err(SetUserProfileError::AccountNotFound(caller)); 138 } 139 140 Ok(()) 141 }