1#![cfg_attr(not(feature = "std"), no_std)]
24
25use frame_support::ensure;
26use frame_system::ensure_signed;
27use sp_std::prelude::*;
28
29use encointer_primitives::{
30 bazaar::{BusinessData, BusinessIdentifier, OfferingData, OfferingIdentifier},
31 common::PalletString,
32 communities::CommunityIdentifier,
33};
34
35pub use pallet::*;
36pub use weights::WeightInfo;
37
38#[frame_support::pallet]
39pub mod pallet {
40 use super::*;
41 use frame_support::pallet_prelude::*;
42 use frame_system::pallet_prelude::*;
43
44 #[pallet::config]
45 pub trait Config: frame_system::Config + pallet_encointer_communities::Config {
46 #[allow(deprecated)]
47 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
48 type WeightInfo: WeightInfo;
49 }
50
51 #[pallet::pallet]
52 #[pallet::without_storage_info]
53 pub struct Pallet<T>(PhantomData<T>);
54
55 #[pallet::call]
56 impl<T: Config> Pallet<T> {
57 #[pallet::call_index(0)]
58 #[pallet::weight((<T as Config>::WeightInfo::create_business(), DispatchClass::Normal, Pays::Yes))]
59 pub fn create_business(
60 origin: OriginFor<T>,
61 cid: CommunityIdentifier,
62 url: PalletString,
63 ) -> DispatchResultWithPostInfo {
64 let sender = ensure_signed(origin)?;
66 ensure!(
68 <pallet_encointer_communities::Pallet<T>>::community_identifiers().contains(&cid),
69 Error::<T>::NonexistentCommunity
70 );
71
72 ensure!(
73 !BusinessRegistry::<T>::contains_key(cid, &sender),
74 Error::<T>::ExistingBusiness
75 );
76
77 BusinessRegistry::<T>::insert(cid, &sender, BusinessData::new(url, 1));
78
79 Self::deposit_event(Event::BusinessCreated(cid, sender));
80
81 Ok(().into())
82 }
83
84 #[pallet::call_index(1)]
85 #[pallet::weight((<T as Config>::WeightInfo::update_business(), DispatchClass::Normal, Pays::Yes))]
86 pub fn update_business(
87 origin: OriginFor<T>,
88 cid: CommunityIdentifier,
89 url: PalletString,
90 ) -> DispatchResultWithPostInfo {
91 let sender = ensure_signed(origin)?;
93
94 ensure!(
95 BusinessRegistry::<T>::contains_key(cid, &sender),
96 Error::<T>::NonexistentBusiness
97 );
98
99 BusinessRegistry::<T>::mutate(cid, &sender, |b| b.url = url);
100
101 Self::deposit_event(Event::BusinessUpdated(cid, sender));
102
103 Ok(().into())
104 }
105
106 #[pallet::call_index(2)]
107 #[pallet::weight((<T as Config>::WeightInfo::delete_business(), DispatchClass::Normal, Pays::Yes))]
108 pub fn delete_business(
109 origin: OriginFor<T>,
110 cid: CommunityIdentifier,
111 ) -> DispatchResultWithPostInfo {
112 let sender = ensure_signed(origin)?;
114
115 ensure!(
116 BusinessRegistry::<T>::contains_key(cid, &sender),
117 Error::<T>::NonexistentBusiness
118 );
119
120 BusinessRegistry::<T>::remove(cid, &sender);
121 #[allow(deprecated)]
122 OfferingRegistry::<T>::remove_prefix(
123 BusinessIdentifier::new(cid, sender.clone()),
124 None,
125 );
126
127 Self::deposit_event(Event::BusinessDeleted(cid, sender));
128
129 Ok(().into())
130 }
131
132 #[pallet::call_index(3)]
133 #[pallet::weight((<T as Config>::WeightInfo::create_offering(), DispatchClass::Normal, Pays::Yes))]
134 pub fn create_offering(
135 origin: OriginFor<T>,
136 cid: CommunityIdentifier,
137 url: PalletString,
138 ) -> DispatchResultWithPostInfo {
139 let sender = ensure_signed(origin)?;
141
142 ensure!(
143 BusinessRegistry::<T>::contains_key(cid, &sender),
144 Error::<T>::NonexistentBusiness
145 );
146
147 let oid = BusinessRegistry::<T>::get(cid, &sender).last_oid;
148 BusinessRegistry::<T>::mutate(cid, &sender, |b| b.last_oid += 1);
149 OfferingRegistry::<T>::insert(
150 BusinessIdentifier::new(cid, sender.clone()),
151 oid,
152 OfferingData::new(url),
153 );
154
155 Self::deposit_event(Event::OfferingCreated(cid, sender, oid));
156
157 Ok(().into())
158 }
159
160 #[pallet::call_index(4)]
161 #[pallet::weight((<T as Config>::WeightInfo::update_offering(), DispatchClass::Normal, Pays::Yes))]
162 pub fn update_offering(
163 origin: OriginFor<T>,
164 cid: CommunityIdentifier,
165 oid: OfferingIdentifier,
166 url: PalletString,
167 ) -> DispatchResultWithPostInfo {
168 let sender = ensure_signed(origin)?;
170
171 let business_identifier = BusinessIdentifier::new(cid, sender.clone());
172
173 ensure!(
174 OfferingRegistry::<T>::contains_key(&business_identifier, oid),
175 Error::<T>::NonexistentOffering
176 );
177
178 OfferingRegistry::<T>::mutate(business_identifier, oid, |o| o.url = url);
179
180 Self::deposit_event(Event::OfferingUpdated(cid, sender, oid));
181
182 Ok(().into())
183 }
184
185 #[pallet::call_index(5)]
186 #[pallet::weight((<T as Config>::WeightInfo::delete_offering(), DispatchClass::Normal, Pays::Yes))]
187 pub fn delete_offering(
188 origin: OriginFor<T>,
189 cid: CommunityIdentifier,
190 oid: OfferingIdentifier,
191 ) -> DispatchResultWithPostInfo {
192 let sender = ensure_signed(origin)?;
194
195 let business_identifier = BusinessIdentifier::new(cid, sender.clone());
196
197 ensure!(
198 OfferingRegistry::<T>::contains_key(&business_identifier, oid),
199 Error::<T>::NonexistentOffering
200 );
201
202 OfferingRegistry::<T>::remove(business_identifier, oid);
203
204 Self::deposit_event(Event::OfferingDeleted(cid, sender, oid));
205
206 Ok(().into())
207 }
208 }
209
210 #[pallet::event]
211 #[pallet::generate_deposit(pub(super) fn deposit_event)]
212 pub enum Event<T: Config> {
213 BusinessCreated(CommunityIdentifier, T::AccountId),
215 BusinessUpdated(CommunityIdentifier, T::AccountId),
217 BusinessDeleted(CommunityIdentifier, T::AccountId),
219 OfferingCreated(CommunityIdentifier, T::AccountId, OfferingIdentifier),
221 OfferingUpdated(CommunityIdentifier, T::AccountId, OfferingIdentifier),
223 OfferingDeleted(CommunityIdentifier, T::AccountId, OfferingIdentifier),
225 }
226
227 #[pallet::error]
228 pub enum Error<T> {
229 NonexistentCommunity,
231 ExistingBusiness,
233 NonexistentBusiness,
235 NonexistentOffering,
237 }
238
239 #[pallet::storage]
240 #[pallet::getter(fn business_registry)]
241 pub type BusinessRegistry<T: Config> = StorageDoubleMap<
242 _,
243 Blake2_128Concat,
244 CommunityIdentifier,
245 Blake2_128Concat,
246 T::AccountId,
247 BusinessData,
248 ValueQuery,
249 >;
250
251 #[pallet::storage]
252 #[pallet::getter(fn offering_registry)]
253 pub type OfferingRegistry<T: Config> = StorageDoubleMap<
254 _,
255 Blake2_128Concat,
256 BusinessIdentifier<T::AccountId>,
257 Blake2_128Concat,
258 OfferingIdentifier,
259 OfferingData,
260 ValueQuery,
261 >;
262}
263
264impl<T: Config> Pallet<T> {
265 pub fn get_businesses(cid: &CommunityIdentifier) -> Vec<(T::AccountId, BusinessData)> {
266 BusinessRegistry::<T>::iter_prefix(cid).collect()
267 }
268
269 pub fn get_offerings(bid: &BusinessIdentifier<T::AccountId>) -> Vec<OfferingData> {
270 OfferingRegistry::<T>::iter_prefix_values(bid).collect()
271 }
272}
273
274mod weights;
275
276#[cfg(feature = "runtime-benchmarks")]
277mod benchmarking;
278#[cfg(test)]
279mod mock;
280#[cfg(test)]
281mod tests;