From 2cab805dea312721ead7e24baec4c61696d8c846 Mon Sep 17 00:00:00 2001 From: Bryan Oltman Date: Mon, 7 Oct 2024 15:58:48 -0400 Subject: [PATCH] feat(shorebird_code_push_client): add support for fetching organization memberships (#2507) --- .../lib/src/code_push_client.dart | 16 ++++++ .../test/src/code_push_client_test.dart | 50 +++++++++++++++++++ .../lib/src/models/organization.dart | 13 ++++- .../src/models/organization_membership.dart | 11 +++- .../models/organization_membership_test.dart | 44 ++++++++++++++++ .../test/src/models/organization_test.dart | 48 ++++++++++++++++++ 6 files changed, 179 insertions(+), 3 deletions(-) diff --git a/packages/shorebird_code_push_client/lib/src/code_push_client.dart b/packages/shorebird_code_push_client/lib/src/code_push_client.dart index 28db8624..a9d9d626 100644 --- a/packages/shorebird_code_push_client/lib/src/code_push_client.dart +++ b/packages/shorebird_code_push_client/lib/src/code_push_client.dart @@ -477,6 +477,22 @@ class CodePushClient { } } + /// Gets the list of organizations the user is a member of, along with the + /// user's role in each organization. + Future> getOrganizationMemberships() async { + final response = await _httpClient.get( + Uri.parse('$_v1/organizations'), + ); + + if (!response.isSuccess) { + throw _parseErrorResponse(response.statusCode, response.body); + } + + return GetOrganizationsResponse.fromJson( + json.decode(response.body) as Map, + ).organizations; + } + /// Closes the client. void close() => _httpClient.close(); diff --git a/packages/shorebird_code_push_client/test/src/code_push_client_test.dart b/packages/shorebird_code_push_client/test/src/code_push_client_test.dart index e6f6ecac..f1ceb65c 100644 --- a/packages/shorebird_code_push_client/test/src/code_push_client_test.dart +++ b/packages/shorebird_code_push_client/test/src/code_push_client_test.dart @@ -1913,6 +1913,56 @@ void main() { }); }); + group('getOrganizationMemberships', () { + group('when response is not success', () { + setUp(() { + when(() => httpClient.send(any())).thenAnswer( + (_) async => http.StreamedResponse( + const Stream.empty(), + HttpStatus.failedDependency, + ), + ); + }); + + test('throws exception', () async { + expect( + () async => codePushClient.getOrganizationMemberships(), + throwsA( + isA().having( + (e) => e.message, + 'message', + CodePushClient.unknownErrorMessage, + ), + ), + ); + }); + }); + + group('when response is successful', () { + late GetOrganizationsResponse response; + late OrganizationMembership membership; + + setUp(() { + membership = OrganizationMembership( + role: OrganizationRole.admin, + organization: Organization.forTest(), + ); + response = GetOrganizationsResponse(organizations: [membership]); + when(() => httpClient.send(any())).thenAnswer( + (_) async => http.StreamedResponse( + Stream.value(utf8.encode(json.encode(response))), + HttpStatus.ok, + ), + ); + }); + + test('deserializes GetOrganizationMembershipsResponse', () async { + final memberships = await codePushClient.getOrganizationMemberships(); + expect(memberships, equals([membership])); + }); + }); + }); + group('close', () { test('closes the underlying client', () { codePushClient.close(); diff --git a/packages/shorebird_code_push_protocol/lib/src/models/organization.dart b/packages/shorebird_code_push_protocol/lib/src/models/organization.dart index 08d912fb..15283e92 100644 --- a/packages/shorebird_code_push_protocol/lib/src/models/organization.dart +++ b/packages/shorebird_code_push_protocol/lib/src/models/organization.dart @@ -1,3 +1,4 @@ +import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:meta/meta.dart'; @@ -35,7 +36,7 @@ enum OrganizationType { /// [stripeCustomerId] may have a subscription. /// {@endtemplate} @JsonSerializable() -class Organization { +class Organization extends Equatable { /// {@macro organization} const Organization({ required this.id, @@ -91,4 +92,14 @@ class Organization { /// When this organization was last updated. final DateTime updatedAt; + + @override + List get props => [ + id, + name, + organizationType, + stripeCustomerId, + createdAt, + updatedAt, + ]; } diff --git a/packages/shorebird_code_push_protocol/lib/src/models/organization_membership.dart b/packages/shorebird_code_push_protocol/lib/src/models/organization_membership.dart index 08281658..a08792c5 100644 --- a/packages/shorebird_code_push_protocol/lib/src/models/organization_membership.dart +++ b/packages/shorebird_code_push_protocol/lib/src/models/organization_membership.dart @@ -1,3 +1,4 @@ +import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:shorebird_code_push_protocol/src/models/organization.dart'; @@ -7,9 +8,9 @@ part 'organization_membership.g.dart'; /// An organization and the current user's role in that organization. /// {@endtemplate} @JsonSerializable() -class OrganizationMembership { +class OrganizationMembership extends Equatable { /// {@macro organization_membership} - OrganizationMembership({ + const OrganizationMembership({ required this.organization, required this.role, }); @@ -26,4 +27,10 @@ class OrganizationMembership { /// The user's role in the organization. final OrganizationRole role; + + @override + List get props => [ + organization, + role, + ]; } diff --git a/packages/shorebird_code_push_protocol/test/src/models/organization_membership_test.dart b/packages/shorebird_code_push_protocol/test/src/models/organization_membership_test.dart index 90de1385..3a55e65b 100644 --- a/packages/shorebird_code_push_protocol/test/src/models/organization_membership_test.dart +++ b/packages/shorebird_code_push_protocol/test/src/models/organization_membership_test.dart @@ -13,5 +13,49 @@ void main() { equals(membership.toJson()), ); }); + + group('Equatable', () { + final date = DateTime.now(); + + group('when two instances are equal', () { + test('returns true', () { + final membership = OrganizationMembership( + organization: Organization.forTest( + createdAt: date, + updatedAt: date, + ), + role: OrganizationRole.member, + ); + final otherMembership = OrganizationMembership( + organization: Organization.forTest( + createdAt: date, + updatedAt: date, + ), + role: OrganizationRole.member, + ); + expect(membership, equals(otherMembership)); + }); + }); + + group('when two instances are not equal', () { + test('returns false', () { + final membership = OrganizationMembership( + organization: Organization.forTest( + createdAt: date, + updatedAt: date, + ), + role: OrganizationRole.member, + ); + final otherMembership = OrganizationMembership( + organization: Organization.forTest( + createdAt: date, + updatedAt: date, + ), + role: OrganizationRole.admin, + ); + expect(membership, isNot(equals(otherMembership))); + }); + }); + }); }); } diff --git a/packages/shorebird_code_push_protocol/test/src/models/organization_test.dart b/packages/shorebird_code_push_protocol/test/src/models/organization_test.dart index 7436a1dc..9b461672 100644 --- a/packages/shorebird_code_push_protocol/test/src/models/organization_test.dart +++ b/packages/shorebird_code_push_protocol/test/src/models/organization_test.dart @@ -17,5 +17,53 @@ void main() { equals(organization.toJson()), ); }); + + group('Equatable', () { + final date = DateTime.now(); + + group('when two instances are equal', () { + test('returns true', () { + final organization = Organization( + id: 1, + name: 'name', + createdAt: date, + updatedAt: date, + organizationType: OrganizationType.team, + stripeCustomerId: 'cus_123', + ); + final otherOrganization = Organization( + id: 1, + name: 'name', + createdAt: date, + updatedAt: date, + organizationType: OrganizationType.team, + stripeCustomerId: 'cus_123', + ); + expect(organization, equals(otherOrganization)); + }); + }); + + group('when two instances are not equal', () { + test('returns false', () { + final organization = Organization( + id: 1, + name: 'name', + createdAt: date, + updatedAt: date, + organizationType: OrganizationType.team, + stripeCustomerId: 'cus_123', + ); + final otherOrganization = Organization( + id: 1, + name: 'name', + createdAt: date, + updatedAt: date, + organizationType: OrganizationType.team, + stripeCustomerId: 'cus_456', + ); + expect(organization, isNot(equals(otherOrganization))); + }); + }); + }); }); }