// This file is part of Bizinikiwi. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #[cfg(feature = "runtime-benchmarks")] use alloc::vec; use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen}; #[cfg(feature = "runtime-benchmarks")] use enumflags2::BitFlag; use enumflags2::{bitflags, BitFlags}; use pezframe_support::{traits::Get, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound}; use scale_info::{build::Variants, Path, Type, TypeInfo}; use pezsp_runtime::{BoundedVec, RuntimeDebug}; use crate::types::{Data, IdentityInformationProvider}; /// The fields that we use to identify the owner of an account with. Each corresponds to a field /// in the `IdentityInfo` struct. #[bitflags] #[repr(u64)] #[derive(Clone, Copy, PartialEq, Eq, RuntimeDebug)] pub enum IdentityField { Display, Legal, Web, Riot, Email, PgpFingerprint, Image, Twitter, } impl TypeInfo for IdentityField { type Identity = Self; fn type_info() -> scale_info::Type { Type::builder().path(Path::new("IdentityField", module_path!())).variant( Variants::new() .variant("Display", |v| v.index(0)) .variant("Legal", |v| v.index(1)) .variant("Web", |v| v.index(2)) .variant("Riot", |v| v.index(3)) .variant("Email", |v| v.index(4)) .variant("PgpFingerprint", |v| v.index(5)) .variant("Image", |v| v.index(6)) .variant("Twitter", |v| v.index(7)), ) } } /// Information concerning the identity of the controller of an account. /// /// NOTE: This should be stored at the end of the storage item to facilitate the addition of extra /// fields in a backwards compatible way through a specialized `Decode` impl. #[derive( CloneNoBound, Encode, Decode, DecodeWithMemTracking, EqNoBound, MaxEncodedLen, PartialEqNoBound, RuntimeDebugNoBound, TypeInfo, )] #[codec(mel_bound())] #[scale_info(skip_type_params(FieldLimit))] pub struct IdentityInfo> { /// Additional fields of the identity that are not catered for with the struct's explicit /// fields. pub additional: BoundedVec<(Data, Data), FieldLimit>, /// A reasonable display name for the controller of the account. This should be whatever it is /// that it is typically known as and should not be confusable with other entities, given /// reasonable context. /// /// Stored as UTF-8. pub display: Data, /// The full legal name in the local jurisdiction of the entity. This might be a bit /// long-winded. /// /// Stored as UTF-8. pub legal: Data, /// A representative website held by the controller of the account. /// /// NOTE: `https://` is automatically prepended. /// /// Stored as UTF-8. pub web: Data, /// The Riot/Matrix handle held by the controller of the account. /// /// Stored as UTF-8. pub riot: Data, /// The email address of the controller of the account. /// /// Stored as UTF-8. pub email: Data, /// The PGP/GPG public key of the controller of the account. pub pgp_fingerprint: Option<[u8; 20]>, /// A graphic image representing the controller of the account. Should be a company, /// organization or project logo or a headshot in the case of a human. pub image: Data, /// The Twitter identity. The leading `@` character may be elided. pub twitter: Data, } impl + 'static> IdentityInformationProvider for IdentityInfo { type FieldsIdentifier = u64; fn has_identity(&self, fields: Self::FieldsIdentifier) -> bool { self.fields().bits() & fields == fields } #[cfg(feature = "runtime-benchmarks")] fn create_identity_info() -> Self { let data = Data::Raw(vec![0; 32].try_into().unwrap()); IdentityInfo { additional: vec![(data.clone(), data.clone()); FieldLimit::get().try_into().unwrap()] .try_into() .unwrap(), display: data.clone(), legal: data.clone(), web: data.clone(), riot: data.clone(), email: data.clone(), pgp_fingerprint: Some([0; 20]), image: data.clone(), twitter: data, } } #[cfg(feature = "runtime-benchmarks")] fn all_fields() -> Self::FieldsIdentifier { IdentityField::all().bits() } } impl> Default for IdentityInfo { fn default() -> Self { IdentityInfo { additional: BoundedVec::default(), display: Data::None, legal: Data::None, web: Data::None, riot: Data::None, email: Data::None, pgp_fingerprint: None, image: Data::None, twitter: Data::None, } } } impl> IdentityInfo { pub(crate) fn fields(&self) -> BitFlags { let mut res = BitFlags::::empty(); if !self.display.is_none() { res.insert(IdentityField::Display); } if !self.legal.is_none() { res.insert(IdentityField::Legal); } if !self.web.is_none() { res.insert(IdentityField::Web); } if !self.riot.is_none() { res.insert(IdentityField::Riot); } if !self.email.is_none() { res.insert(IdentityField::Email); } if self.pgp_fingerprint.is_some() { res.insert(IdentityField::PgpFingerprint); } if !self.image.is_none() { res.insert(IdentityField::Image); } if !self.twitter.is_none() { res.insert(IdentityField::Twitter); } res } }