diff --git a/lib/src/common/orgs_service.dart b/lib/src/common/orgs_service.dart index c0774bda..d793a8b9 100644 --- a/lib/src/common/orgs_service.dart +++ b/lib/src/common/orgs_service.dart @@ -21,8 +21,11 @@ class OrganizationsService extends Service { if (userName == null) { requestPath = '/user/orgs'; } - return PaginationHelper(github) - .objects('GET', requestPath, Organization.fromJson); + return PaginationHelper(github).objects( + 'GET', + requestPath, + Organization.fromJson, + ); } /// Fetches the organization specified by [name]. @@ -31,7 +34,7 @@ class OrganizationsService extends Service { Future get(String? name) => github.getJSON('/orgs/$name', convert: Organization.fromJson, statusCode: StatusCodes.OK, fail: (http.Response response) { - if (response.statusCode == 404) { + if (response.statusCode == StatusCodes.NOT_FOUND) { throw OrganizationNotFound(github, name); } }); @@ -47,13 +50,15 @@ class OrganizationsService extends Service { /// Edits an Organization /// /// API docs: https://developer.github.com/v3/orgs/#edit-an-organization - Future edit(String org, - {String? billingEmail, - String? company, - String? email, - String? location, - String? name, - String? description}) { + Future edit( + String org, { + String? billingEmail, + String? company, + String? email, + String? location, + String? name, + String? description, + }) { final map = createNonNullMap({ 'billing_email': billingEmail, 'company': company, @@ -64,7 +69,7 @@ class OrganizationsService extends Service { }); return github.postJSON('/orgs/$org', - statusCode: 200, + statusCode: StatusCodes.OK, convert: Organization.fromJson, body: GitHubJson.encode(map)); } @@ -73,8 +78,11 @@ class OrganizationsService extends Service { /// /// API docs: https://developer.github.com/v3/orgs/teams/#list-teams Stream listTeams(String orgName) { - return PaginationHelper(github) - .objects('GET', '/orgs/$orgName/teams', Team.fromJson); + return PaginationHelper(github).objects( + 'GET', + '/orgs/$orgName/teams', + Team.fromJson, + ); } /// Gets the team specified by the [teamId]. @@ -82,14 +90,34 @@ class OrganizationsService extends Service { /// API docs: https://developer.github.com/v3/orgs/teams/#get-team Future getTeam(int teamId) { return github.getJSON('/teams/$teamId', - convert: Organization.fromJson, statusCode: 200) as Future; + convert: Organization.fromJson, + statusCode: StatusCodes.OK) as Future; + } + + /// Gets the team specified by its [teamName]. + /// + /// https://docs.github.com/en/rest/teams/teams?apiVersion=2022-11-28#get-a-team-by-name + Future getTeamByName( + String orgName, + String teamName, + ) { + return github.getJSON( + 'orgs/$orgName/teams/$teamName', + convert: Team.fromJson, + statusCode: StatusCodes.OK, + ); } /// Creates a Team. /// /// API docs: https://developer.github.com/v3/orgs/teams/#create-team - Future createTeam(String org, String name, - {String? description, List? repos, String? permission}) { + Future createTeam( + String org, + String name, { + String? description, + List? repos, + String? permission, + }) { final map = createNonNullMap({ 'name': name, 'description': description, @@ -98,14 +126,20 @@ class OrganizationsService extends Service { }); return github.postJSON('/orgs/$org/teams', - statusCode: 201, convert: Team.fromJson, body: GitHubJson.encode(map)); + statusCode: StatusCodes.CREATED, + convert: Team.fromJson, + body: GitHubJson.encode(map)); } /// Edits a Team. /// /// API docs: https://developer.github.com/v3/orgs/teams/#edit-team - Future editTeam(int teamId, String name, - {String? description, String? permission}) { + Future editTeam( + int teamId, + String name, { + String? description, + String? permission, + }) { final map = createNonNullMap({ 'name': name, 'description': description, @@ -114,7 +148,7 @@ class OrganizationsService extends Service { return github.postJSON( '/teams/$teamId', - statusCode: 200, + statusCode: StatusCodes.OK, convert: Team.fromJson, body: GitHubJson.encode(map), ); @@ -125,7 +159,7 @@ class OrganizationsService extends Service { /// API docs: https://developer.github.com/v3/orgs/teams/#delete-team Future deleteTeam(int teamId) { return github.request('DELETE', '/teams/$teamId').then((response) { - return response.statusCode == 204; + return response.statusCode == StatusCodes.NO_CONTENT; }); } @@ -133,8 +167,11 @@ class OrganizationsService extends Service { /// /// API docs: https://developer.github.com/v3/orgs/teams/#list-team-members Stream listTeamMembers(int teamId) { - return PaginationHelper(github) - .objects('GET', '/teams/$teamId/members', TeamMember.fromJson); + return PaginationHelper(github).objects( + 'GET', + '/teams/$teamId/members', + TeamMember.fromJson, + ); } Future getTeamMemberStatus(int teamId, String user) { @@ -143,85 +180,129 @@ class OrganizationsService extends Service { }); } - /// Returns the membership status for a user in a team. + /// Returns the membership status for a [user] in a team with [teamId]. /// /// API docs: https://developer.github.com/v3/orgs/teams/#get-team-membership - Future getTeamMembership(int teamId, String user) { - final completer = Completer(); - - github - .getJSON( - '/teams/$teamId/memberships/$user', - statusCode: 200, - fail: (http.Response response) { - if (response.statusCode == 404) { - completer.complete(TeamMembershipState(null)); - } else { - github.handleStatusCode(response); - } - }, - convert: (dynamic json) => TeamMembershipState(json['state']), - ) - .then(completer.complete); + Future getTeamMembership( + int teamId, + String user, + ) { + return github.getJSON( + '/teams/$teamId/memberships/$user', + statusCode: StatusCodes.OK, + convert: (dynamic json) => TeamMembershipState( + json['state'], + ), + ); + } - return completer.future; + /// Returns the membership status for [user] in [teamName] given the [orgName]. + /// + /// Note that this will throw on NotFound if the user is not a member of the + /// team. Adding a fail function to set the value does not help unless you + /// throw out of the fail function. + Future getTeamMembershipByName( + String orgName, + String teamName, + String user, + ) { + return github.getJSON( + '/orgs/$orgName/teams/$teamName/memberships/$user', + statusCode: StatusCodes.OK, + convert: (dynamic json) => TeamMembershipState( + json['state'], + ), + ); } /// Invites a user to the specified team. /// /// API docs: https://developer.github.com/v3/teams/members/#add-or-update-team-membership - Future addTeamMembership(int teamId, String user) async { - final response = await github - .request('PUT', '/teams/$teamId/memberships/$user', statusCode: 200); + Future addTeamMembership( + int teamId, + String user, + ) async { + final response = await github.request( + 'PUT', + '/teams/$teamId/memberships/$user', + statusCode: StatusCodes.OK, + ); return TeamMembershipState(jsonDecode(response.body)['state']); } /// Removes a user from the specified team. /// /// API docs: https://developer.github.com/v3/orgs/teams/#get-team-membership - Future removeTeamMembership(int teamId, String user) { - return github.request('DELETE', '/teams/$teamId/memberships/$user', - statusCode: 204); + Future removeTeamMembership( + int teamId, + String user, + ) { + return github.request( + 'DELETE', + '/teams/$teamId/memberships/$user', + statusCode: StatusCodes.NO_CONTENT, + ); } /// Lists the repositories that the specified team has access to. /// /// API docs: https://developer.github.com/v3/orgs/teams/#list-team-repos Stream listTeamRepositories(int teamId) { - return PaginationHelper(github) - .objects('GET', '/teams/$teamId/repos', Repository.fromJson); + return PaginationHelper(github).objects( + 'GET', + '/teams/$teamId/repos', + Repository.fromJson, + ); } /// Checks if a team manages the specified repository. /// /// API docs: https://developer.github.com/v3/orgs/teams/#get-team-repo - Future isTeamRepository(int teamId, RepositorySlug slug) { + Future isTeamRepository( + int teamId, + RepositorySlug slug, + ) { return github - .request('GET', '/teams/$teamId/repos/${slug.fullName}') + .request( + 'GET', + '/teams/$teamId/repos/${slug.fullName}', + ) .then((response) { - return response.statusCode == 204; + return response.statusCode == StatusCodes.NO_CONTENT; }); } /// Adds a repository to be managed by the specified team. /// /// API docs: https://developer.github.com/v3/orgs/teams/#add-team-repo - Future addTeamRepository(int teamId, RepositorySlug slug) { + Future addTeamRepository( + int teamId, + RepositorySlug slug, + ) { return github - .request('PUT', '/teams/$teamId/repos/${slug.fullName}') + .request( + 'PUT', + '/teams/$teamId/repos/${slug.fullName}', + ) .then((response) { - return response.statusCode == 204; + return response.statusCode == StatusCodes.NO_CONTENT; }); } /// Removes a repository from being managed by the specified team. /// /// API docs: https://developer.github.com/v3/orgs/teams/#remove-team-repo - Future removeTeamRepository(int teamId, RepositorySlug slug) { + Future removeTeamRepository( + int teamId, + RepositorySlug slug, + ) { return github - .request('DELETE', '/teams/$teamId/repos/${slug.fullName}') + .request( + 'DELETE', + '/teams/$teamId/repos/${slug.fullName}', + ) .then((response) { - return response.statusCode == 204; + return response.statusCode == StatusCodes.NO_CONTENT; }); } @@ -229,16 +310,22 @@ class OrganizationsService extends Service { /// /// API docs: https://developer.github.com/v3/orgs/teams/#list-user-teams Stream listUserTeams() { - return PaginationHelper(github) - .objects('GET', '/user/teams', Team.fromJson); + return PaginationHelper(github).objects( + 'GET', + '/user/teams', + Team.fromJson, + ); } /// Lists all of the users in an organization /// /// API docs: https://developer.github.com/v3/orgs/teams/#list-user-teams Stream listUsers(String org) { - return PaginationHelper(github) - .objects('GET', '/orgs/$org/members', User.fromJson); + return PaginationHelper(github).objects( + 'GET', + '/orgs/$org/members', + User.fromJson, + ); } /// Lists the hooks for the specified organization. @@ -252,14 +339,20 @@ class OrganizationsService extends Service { /// Fetches a single hook by [id]. /// /// API docs: https://developer.github.com/v3/orgs/hooks/#get-single-hook - Future getHook(String org, int id) => + Future getHook( + String org, + int id, + ) => github.getJSON('/orgs/$org/hooks/$id', convert: (dynamic i) => Hook.fromJson(i)..repoName = org); /// Creates an organization hook based on the specified [hook]. /// /// API docs: https://developer.github.com/v3/orgs/hooks/#create-a-hook - Future createHook(String org, CreateHook hook) { + Future createHook( + String org, + CreateHook hook, + ) { return github.postJSON('/orgs/$org/hooks', convert: (Map i) => Hook.fromJson(i)..repoName = org, body: GitHubJson.encode(hook)); @@ -270,16 +363,27 @@ class OrganizationsService extends Service { /// Pings the organization hook. /// /// API docs: https://developer.github.com/v3/orgs/hooks/#ping-a-hook - Future pingHook(String org, int id) { + Future pingHook( + String org, + int id, + ) { return github - .request('POST', '/orgs/$org/hooks/$id/pings') - .then((response) => response.statusCode == 204); + .request( + 'POST', + '/orgs/$org/hooks/$id/pings', + ) + .then((response) => response.statusCode == StatusCodes.NO_CONTENT); } /// Deletes the specified hook. Future deleteHook(String org, int id) { - return github.request('DELETE', '/orgs/$org/hooks/$id').then((response) { - return response.statusCode == 204; + return github + .request( + 'DELETE', + '/orgs/$org/hooks/$id', + ) + .then((response) { + return response.statusCode == StatusCodes.NO_CONTENT; }); } } diff --git a/test/unit/orgs_service_test.dart b/test/unit/orgs_service_test.dart new file mode 100644 index 00000000..04fff9e1 --- /dev/null +++ b/test/unit/orgs_service_test.dart @@ -0,0 +1,175 @@ +import 'dart:io'; + +import 'package:github/github.dart'; +import 'package:http/http.dart'; +import 'package:http/testing.dart'; +import 'package:test/test.dart'; + +void main() { + const teamResponse = ''' + { + "name": "flutter-hackers", + "id": 1753404, + "slug": "flutter-hackers", + "permission": "pull", + "members_count": 255, + "repos_count": 34, + "organization": { + "login": "flutter", + "id": 14101776, + "url": "https://api.github.com/orgs/flutter", + "avatar_url": "https://avatars.githubusercontent.com/u/14101776?v=4", + "name": "Flutter", + "company": null, + "blog": "https://flutter.dev", + "location": null, + "email": null, + "public_repos": 30, + "public_gists": 0, + "followers": 6642, + "following": 0, + "html_url": "https://github.com/flutter", + "created_at": "2015-09-03T00:37:37Z", + "updated_at": "2022-03-17T17:35:40Z" + } + } +'''; + + const teamNotFoundResponse = ''' + { + "message": "Not Found", + "documentation_url": "https://docs.github.com/rest/reference/teams#list-teams" + } + '''; + + const activeMemberResponse = ''' + { + "state": "active", + "role": "member", + "url": "https://api.github.com/organizations/14101776/team/1753404/memberships/ricardoamador" + } + '''; + + const pendingMemberResponse = ''' + { + "state": "pending", + "role": "member", + "url": "https://api.github.com/organizations/14101776/team/1753404/memberships/ricardoamador" + } + '''; + + group(GitHub, () { + test('getTeamByName is successful', () async { + Request? request; + + final client = MockClient((r) async { + request = r; + return Response(teamResponse, HttpStatus.ok); + }); + + final github = GitHub(client: client); + final organizationsService = OrganizationsService(github); + + final team = await organizationsService.getTeamByName( + 'flutter', 'flutter-hackers'); + expect(team.name, 'flutter-hackers'); + expect(team.id, 1753404); + expect(team.organization!.login, 'flutter'); + expect(request, isNotNull); + }); + + test('getTeamByName not found', () async { + Request? request; + + final headers = {}; + headers['content-type'] = 'application/json'; + + final client = MockClient((r) async { + request = r; + return Response(teamNotFoundResponse, HttpStatus.notFound, + headers: headers); + }); + + final github = GitHub(client: client); + final organizationsService = OrganizationsService(github); + + // ignore: omit_local_variable_types + expect( + () async => organizationsService.getTeamByName( + 'flutter', 'flutter-programmers'), + throwsException); + expect(request, isNull); + }); + + test('getTeamMembership using string name, active', () async { + Request? request; + + final client = MockClient((r) async { + request = r; + return Response(activeMemberResponse, HttpStatus.ok); + }); + + final github = GitHub(client: client); + final organizationsService = OrganizationsService(github); + + final teamMembershipState = + await organizationsService.getTeamMembershipByName( + 'flutter', + 'flutter-hackers', + 'ricardoamador', + ); + expect(teamMembershipState.isActive, isTrue); + expect(request, isNotNull); + }); + + test('getTeamMembership using string name, pending', () async { + Request? request; + + final client = MockClient((r) async { + request = r; + return Response(pendingMemberResponse, HttpStatus.ok); + }); + + final github = GitHub(client: client); + final organizationsService = OrganizationsService(github); + + final teamMembershipState = + await organizationsService.getTeamMembershipByName( + 'flutter', + 'flutter-hackers', + 'ricardoamador', + ); + expect(teamMembershipState.isActive, isFalse); + expect(teamMembershipState.isPending, isTrue); + expect(request, isNotNull); + }); + + test('getTeamMembership using string name, null', () async { + Request? request; + + final headers = {}; + headers['content-type'] = 'application/json'; + + final client = MockClient((r) async { + request = r; + return Response( + teamNotFoundResponse, + HttpStatus.notFound, + headers: headers, + ); + }); + + final github = GitHub(client: client); + final organizationsService = OrganizationsService(github); + + expect( + () async => organizationsService.getTeamMembershipByName( + 'flutter', + 'flutter-hackers', + 'garfield', + ), + throwsException); + expect(request, isNull); + }); + }); +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy