-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add shield for display API #374
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #374 +/- ##
==========================================
+ Coverage 92.66% 92.68% +0.02%
==========================================
Files 1187 1190 +3
Lines 26781 26861 +80
Branches 85 85
==========================================
+ Hits 24816 24896 +80
Misses 1954 1954
Partials 11 11
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
&self, | ||
shield_id: SecurityStructureID, | ||
) -> Result<EntitiesLinkedToSecurityStructure> { | ||
let accounts = self |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: does this work:
fn filter<E>(entity: &E) -> bool where E: HasSecurityState { entity.is_linked_to_security_structure(shield_id) }
and then .filter(filter)
in the four places below.
or does compiler complain about shield_id
being captured?
can you do `let filter = |entity: &(impl HasSecurityState)| { .. }; ? or does that not work?
mostly curiuos...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this might help as guide
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw it and indeed it works, but I didn't see any value, that's why I passed.
If you want I can add it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DRY
But only truly helps IMO if one can pass .filter(filter)
which is possible in Swift, but trickier in Rust since the fn or closure captures the shield_id
variable
{ | ||
return provisional_security_structure | ||
.security_structure_id | ||
== shield_id; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
undefined behaviour here... if the provisional is different, then we return false
here, even though the actual ("committed") is linked. So you need to doc this method what is it suppose to do? what does linked
mean? I think linked means "provisionally_referenced_or_de_facto_in_use" ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would actually split this into three methods:
trait HasSecurityState {
fn is_currently_or_provisionally_securified_with(&self, shield_id: SecurityStructureID) {
self.is_currently_securified_with(shield_id) || self.is_provisionally_securified_with(shield_id)
}
fn is_currently_securified_with(&self, shield_id: SecurityStructureID) {
self.security_state().as_securified().map(|s| s.shield_id == shield_id).unwrap_or(false)
}
fn is_provisionally_securified_with(&self, shield_id: SecurityStructureID) {
self.provisional_security_config.map(|s| s.shield_id() == shield_id).unwrap_or(false)
}
}
impl ProvisionalSecurityConfig {
fn shield_id(&self) -> bool {
match self { ... }
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@giannis-rdx furthermore, this should be in profile-logic
crate. All Profile logic goes into profile-logic
crate :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the provisional is different, then we return false here, even though the actual ("committed") is linked
That is the behaviour we want, or at least agreed to - if an account has a provisional shield set, then that is shown throughout the app. What you are proposing implies showing users that an account is linked to two shields at the same time, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@GhenadieVP my point is that is_linked
is too broad a term. so the method should be renamed and it should it should be documented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated
{ | ||
return provisional_security_structure | ||
.security_structure_id | ||
== shield_id; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
undefined behaviour here... if the provisional is different, then we return false
here, even though the actual ("committed") is linked. So you need to doc this method what is it suppose to do? what does linked
mean? I think linked means "provisionally_referenced_or_de_facto_in_use" ? if so, you should provisional_security_structure .security_structure_id == shield_id || value.security_structure.security_structure_id == shield_id
crates/uniffi/uniffi_SPLIT_ME/src/profile/supporting_types/shield_for_display.rs
Outdated
Show resolved
Hide resolved
...iffi/uniffi_SPLIT_ME/src/system/sargon_os/sargon_os_entities_linked_to_security_structure.rs
Outdated
Show resolved
Hide resolved
crates/profile/models/app-preferences/src/shield_for_display.rs
Outdated
Show resolved
Hide resolved
..._SPLIT_ME/src/logic/profile_network/profile_network_entities_linked_to_security_structure.rs
Show resolved
Hide resolved
#[display("{}", self.metadata.display_name)] | ||
pub struct ShieldForDisplay { | ||
pub metadata: SecurityStructureMetadata, | ||
pub number_of_linked_accounts: usize, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this can probably be put in profile-logic
crate. it is not a model used by the Profile.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you on that
However, the reasons I placed it there are as follows:
- there is already an existing
account_for_display
which also is not used by theProfile
. For consistency, I addedshield_for_display
here. - I am not sure where exactly I should place it in the
profile-logic
crate. We do not have amodel
directory there... Oops! model ≠ logic :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
account_for_display
should be moved to profile-logic
too. :) The "logic" in profile-logic
does not mean "cannot contain structs or enums". It means "here is code that DOES stuff using models from Profile models crate OR using models declared in this crate". Where as profile model crates should as much as possible just be the Serde impl of Profile model. Without logic. Why? Well since we might need to migrate v100 Profile to v101 Profile someday and then we need to copy paste all profile models and do some trait IntoLatest
and impl that for v100 models. But we should not duplicate logic, neither should the logic operate on v100
models then, only v101
models.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok where do you think we should place it in profile-logic
?
under app_preferences
?
or create a new directory security_structures
and place it there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
either is fine :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
/// This is the result of checking what entities are linked to a given `SecurityStructure`. | ||
#[derive(Clone, Debug, PartialEq)] | ||
pub struct EntitiesLinkedToSecurityStructure { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not Profile model so move to profile-logic
crate I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Furthermore, this model does not contain which Shield ID, which looks like an oversight! If you include it the code later can be more functional.
If you include the SecurityStructureMetadata
then you can do more functional stuff below:
https://github.com/radixdlt/sargon/pull/374/files#r1945169455
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not Profile model so move to profile-logic crate I think.
now that i see this then better to have a security_structures
in profile-logic crate and place the EntitiesLinkedToSecurityStructure
and ShieldForDisplay
there.
right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not Profile model so move to profile-logic crate I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Furthermore, this model does not contain which Shield ID, which looks like an oversight! If you include it the code later can be more functional.
If you include the SecurityStructureMetadata ...
if I include the SecurityStructureMetadata
in the EntitiesLinkedToSecurityStructure
, I need:
- either update the API
pub async fn entities_linked_to_security_structure(
&self,
metadata: SecurityStructureMetadata, // from shield_id: SecurityStructureID
profile_to_check: ProfileToCheck,
)
// so I can pass the metadata all the way down to build the `EntitiesLinkedToSecurityStructure` struct.
- or leave the API as it is with
shield_id: SecurityStructureID
and internally fetch theSecurityStructureMetadata
.
I think the latter is more appropriate.
what do you think @CyonAlexRDX ?
edit: done
) | ||
.await?; | ||
|
||
shields_for_display.insert(ShieldForDisplay { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should use constructor ShieldForDisplay::new
also prefer functional:
let security_structures = self.security_structures_of_factor_source_ids()?;
let shields_for_display = security_structures
.iter()
.map(|shield| shield.metadata)
.map(|metadata| self.entities_linked_to_security_structure(metadata, ProfileToCheck::Current))
.map(ShieldForDisplay::new)
.collect::<ShieldsForDisplay>();
Ok(shields_for_display)
which I think is much more clean
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
although I updated the EntitiesLinkedToSecurityStructure
struct by adding the metadata: SecurityStructureMetadata
, this functional code doesn't work because map
doesn't support async
Unless there is another way that I am not aware of.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@giannis-rdx you should be able to use futures::future::join_all
, so:
let security_structures = self.security_structures_of_factor_source_ids()?;
let shields_for_display = security_structures
.iter()
.map(|shield| shield.metadata)
.map(|metadata| self.entities_linked_to_security_structure(metadata, ProfileToCheck::Current))
.map(ShieldForDisplay::new)
let shields_for_display = futures::future::join_all(shields_for_display)
.await
.collect::<ShieldsForDisplay>();
Ok(shields_for_display)
I think that should work.
See join_all, which does preserve order:
The returned future will drive execution for all of its underlying futures, collecting the results into a destination Vec in the same order as they were provided.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no it doesn't work. I get a couple of errors:
function is expected to take 1 argument, but it takes 5 arguments
.map(ShieldForDisplay::new);
Vec<_> is not an iterator
--> crates/system/os/factors/src/sargon_os_security_structures.rs:262:14
|
260 | let shields_for_display = futures::future::join_all(shields_for_display)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the only way to make it work is this:
let security_structures = self.security_structures_of_factor_source_ids()?;
let shields_for_display_futures = security_structures.iter().map(|security_structure| {
let metadata = security_structure.metadata.clone();
async {
let linked_entities = self
.entities_linked_to_security_structure(
metadata.id,
ProfileToCheck::Current,
)
.await?;
Ok(ShieldForDisplay::new(
metadata,
linked_entities.accounts.len(),
linked_entities.hidden_accounts.len(),
linked_entities.personas.len(),
linked_entities.hidden_personas.len(),
))
}
});
let shields_for_display =
futures::future::join_all(shields_for_display_futures)
.await
.into_iter()
.collect::<Result<ShieldsForDisplay>>()?;
Ok(shields_for_display)
}
which is quite ugly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I will stick to my original solution. Way simpler and clean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I mean by ShieldForDisplay::new
if ofc a constructor which takes a EntitiesLinkedToSecurityStructure
... maybe fn with_linked
and use .map(ShieldForDisplay::with_linked)
:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great first start! Some crate admin needed. Logic into logic :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Hope join_all
works as I thought, else lets skip it.
crates/system/os/factors/Cargo.toml
Outdated
@@ -32,3 +32,4 @@ preinterpret = { workspace = true } | |||
pretty_assertions = { workspace = true } | |||
serde = { workspace = true } | |||
serde_json = { workspace = true } | |||
futures = "0.3.31" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use workspace, always
get_shields_for_display for SargonOS
LinkedToSecurityStructure trait/functions
updated ProfileNetworkQueryEntitiesLinkedToSecurityStructure
1c50e93
to
829526a
Compare
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] Generated by cargo-workspaces
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job
This PR is the last part of the ABW-4146.
It adds an API to