Skip to content
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

[spaceship] Add visible_apps relationship to invite users with app permissions and fetch user's app permissions #19053

Merged

Conversation

lucgrabowski
Copy link
Contributor

@lucgrabowski lucgrabowski commented Jul 4, 2021

Checklist

  • I've run bundle exec rspec from the root directory to see all new and existing tests pass
  • I've followed the fastlane code style and run bundle exec rubocop -a to ensure the code style is valid
  • I've read the Contribution Guidelines
  • I've updated the documentation if necessary.

Motivation and Context

User and UserInvitation models should have a relationship to visible_apps to manage app permissions.

Description

Changes:
It's possible to assign app permissions when inviting user with post_user_invitation.
It's possible to fetch app permissions (visible_apps) for both User and UserInvitation

Testing Steps

Testing in irb:

require 'spaceship'
Spaceship::ConnectAPI.login

users = Spaceship::ConnectAPI::User.all(includes: Spaceship::ConnectAPI::User::ESSENTIAL_INCLUDES)
# or
users = Spaceship::ConnectAPI::User.all(includes: "visibleApps")
# or
users = Spaceship::ConnectAPI::User.all

user = Spaceship::ConnectAPI::User.find(email:"USER_EMAIL").first
user.get_visible_apps 
user.get_visible_apps(limit: 1)

user = Spaceship::ConnectAPI::User.find(email:"USER_EMAIL", includes: "visibleApps")


invitations = Spaceship::ConnectAPI::UserInvitation.all(includes: Spaceship::ConnectAPI::UserInvitation::ESSENTIAL_INCLUDES)
# or
invitations = Spaceship::ConnectAPI::UserInvitation.all(includes: "visibleApps")
# or 
invitations = Spaceship::ConnectAPI::UserInvitation.all

Spaceship::ConnectAPI::UserInvitation.create(email: "YOUR_EMAIL", first_name: "YOUR_FIRST_NAME", last_name: "YOUR_LAST_NAME", roles: ["DEVELOPER"], provisioning_allowed: true, all_apps_visible: false, visible_app_ids: ["APP_ID"])
user_invitation = Spaceship::ConnectAPI::UserInvitation.find("YOUR_EMAIL")
user_invitation.get_visible_apps
user_invitation.get_visible_apps(limit: 1)
user_invitation.first.delete!

# Testing of invalid combinations of `all_apps_visible` and `visible_app_ids`:

Spaceship::ConnectAPI::UserInvitation.create(email: "YOUR_EMAIL", first_name: "YOUR_FIRST_NAME", last_name: "YOUR_LAST_NAME", roles: ["DEVELOPER"], provisioning_allowed: true, all_apps_visible: true, visible_app_ids: ["APP_ID"])
# It will fail with "The provided entity includes a relationship with an invalid value - If you set allAppsVisible to true, you must not provide values for the visibleApps relationship. - /data/relationships/visibleApps"

Spaceship::ConnectAPI::UserInvitation.create(email: "YOUR_EMAIL", first_name: "YOUR_FIRST_NAME", last_name: "YOUR_LAST_NAME", roles: ["DEVELOPER"], provisioning_allowed: true, all_apps_visible: false)
# It will fail with "The provided visible app information is invalid. - If you set allAppsVisible to false, you must provide at least one value for the visibleApps relationship. - /data/attributes/allAppsVisible

@google-cla google-cla bot added the cla: yes label Jul 4, 2021
Copy link
Contributor

@ainame ainame left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution! I wanted to point how ESSENTIAL_INCLUDES convention is supposed to work🙂 otherwise this looks great change 😍

Comment on lines +37 to +39
ESSENTIAL_INCLUDES = [
"visibleApps"
].join(",")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't automatically used at all. You need to pass this to the parent API calls.

For example, you need to pass it to the corresponding methods as the default value of includes argument. This way App Store Connect API will include "visibleApps" objects within the response and spaceship client will automatically map it to visible_apps property. That's what ESSENTIAL_INCLUDES convention is supposed to work.

def self.all(filter: {}, includes: Spaceship::ConnectAPI::User::ESSENTIAL_INCLUDES, limit: nil, sort: nil)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise visible_apps property ends up returning nil depending on how you get the User object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanatory comment @ainame.
I compared how ESSENTIAL_INCLUDES are used in App, AppStoreVersion models and I thought for a while if user visible_apps should be fetched by default and I wasn't sure if I should use them as default inlcudes argument.
I added the definition though to allow to use it as in example testing steps, e.g.

users = Spaceship::ConnectAPI::User.all(includes: Spaceship::ConnectAPI::User::ESSENTIAL_INCLUDES)

Otherwise those that would like to fetch it would have to investigate what value should be used in includes.

Should visible_apps be fetched by default in self.find and self.all methods?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My point is that if it's not "by default", it shouldn't be named "ESSENTIAL". It sounds more like OPTIONAL_INCLUDES to me.
https://developer.apple.com/documentation/appstoreconnectapi/list_users

Should visible_apps be fetched by default in self.find and self.all methods?

To me, it can be an "essential" info when it comes to handling users for ASC. Any advice to determine if it's essential? @joshdholtz

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the advice will be to go with optional, I'll rename it to OPTIONAL_INCLUDES. Otherwise, I'll add essential as default values for includes parameters in self.all and self.find.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, I missed this conversation completely 😱 Sorry! I had my notifications under control for a while but lost control this past month 😬 But...

I think essential is fine here!

})

ESSENTIAL_INCLUDES = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same applies to this. You need to pass this to self.all and self.find.

@@ -48,6 +56,12 @@ def self.find(client: nil, email: nil, includes: nil)
client ||= Spaceship::ConnectAPI
return all(client: client, filter: { email: email }, includes: includes)
end

def fetch_visible_apps(client: nil, limit: nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joshdholtz Any thought on naming this kind of method with get vs fetch? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ainame This also made me think for a while and compare code in other models and I wasn't sure if the choice is correct. 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me too honestly. Some uses "get" others do "fetch" 😅

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UGGHHHH... I hate naming 😅 I honestly don't know which it should be but I do want it to be consistent at some point 🤷‍♂️

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've renamed it to get and it's used more in code.

Copy link
Member

@joshdholtz joshdholtz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested this out and its working good 😊 Thanks for adding this! Really appreciate the contribution ❤️

@joshdholtz joshdholtz merged commit 5fb3ff7 into fastlane:master Aug 2, 2021
Copy link

@fastlane-bot fastlane-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Congratulations! 🎉 This was released as part of fastlane 2.190.0 🚀

@fastlane fastlane locked and limited conversation to collaborators Oct 9, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants