/ github / Team.py
Team.py
  1  ############################ Copyrights and license ############################
  2  #                                                                              #
  3  # Copyright 2012 Vincent Jacques <vincent@vincent-jacques.net>                 #
  4  # Copyright 2012 Zearin <zearin@gonk.net>                                      #
  5  # Copyright 2013 AKFish <akfish@gmail.com>                                     #
  6  # Copyright 2013 Vincent Jacques <vincent@vincent-jacques.net>                 #
  7  # Copyright 2013 martinqt <m.ki2@laposte.net>                                  #
  8  # Copyright 2014 Jan Orel <jan.orel@gooddata.com>                              #
  9  # Copyright 2014 Vincent Jacques <vincent@vincent-jacques.net>                 #
 10  # Copyright 2015 Aron Culotta <aronwc@gmail.com>                               #
 11  # Copyright 2016 Jannis Gebauer <ja.geb@me.com>                                #
 12  # Copyright 2016 Peter Buckley <dx-pbuckley@users.noreply.github.com>          #
 13  # Copyright 2016 mattjmorrison <mattjmorrison@mattjmorrison.com>               #
 14  # Copyright 2018 Isuru Fernando <isuruf@gmail.com>                             #
 15  # Copyright 2018 Jacopo Notarstefano <jacopo.notarstefano@gmail.com>           #
 16  # Copyright 2018 James D'Amato <james.j.damato@gmail.com>                      #
 17  # Copyright 2018 Maarten Fonville <mfonville@users.noreply.github.com>         #
 18  # Copyright 2018 Manu Hortet <manuhortet@gmail.com>                            #
 19  # Copyright 2018 Michał Górny <mgorny@gentoo.org>                            #
 20  # Copyright 2018 Steve Kowalik <steven@wedontsleep.org>                        #
 21  # Copyright 2018 Tim Boring <tboring@hearst.com>                               #
 22  # Copyright 2018 sfdye <tsfdye@gmail.com>                                      #
 23  #                                                                              #
 24  # This file is part of PyGithub.                                               #
 25  # http://pygithub.readthedocs.io/                                              #
 26  #                                                                              #
 27  # PyGithub is free software: you can redistribute it and/or modify it under    #
 28  # the terms of the GNU Lesser General Public License as published by the Free  #
 29  # Software Foundation, either version 3 of the License, or (at your option)    #
 30  # any later version.                                                           #
 31  #                                                                              #
 32  # PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY  #
 33  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    #
 34  # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more #
 35  # details.                                                                     #
 36  #                                                                              #
 37  # You should have received a copy of the GNU Lesser General Public License     #
 38  # along with PyGithub. If not, see <http://www.gnu.org/licenses/>.             #
 39  #                                                                              #
 40  ################################################################################
 41  from __future__ import annotations
 42  
 43  from typing import TYPE_CHECKING, Any
 44  
 45  from deprecated import deprecated
 46  
 47  import github.NamedUser
 48  import github.Organization
 49  import github.PaginatedList
 50  import github.Repository
 51  import github.TeamDiscussion
 52  from github import Consts
 53  from github.GithubException import UnknownObjectException
 54  from github.GithubObject import Attribute, CompletableGithubObject, NotSet, Opt
 55  
 56  if TYPE_CHECKING:
 57      from github.Membership import Membership
 58      from github.NamedUser import NamedUser
 59      from github.Organization import Organization
 60      from github.PaginatedList import PaginatedList
 61      from github.Permissions import Permissions
 62      from github.Repository import Repository
 63      from github.TeamDiscussion import TeamDiscussion
 64  
 65  
 66  class Team(CompletableGithubObject):
 67      """
 68      This class represents Teams. The reference can be found here https://docs.github.com/en/rest/reference/teams
 69      """
 70  
 71      def _initAttributes(self) -> None:
 72          self._id: Attribute[int] = NotSet
 73          self._members_count: Attribute[int] = NotSet
 74          self._members_url: Attribute[str] = NotSet
 75          self._name: Attribute[str] = NotSet
 76          self._description: Attribute[str] = NotSet
 77          self._permission: Attribute[str] = NotSet
 78          self._repos_count: Attribute[int] = NotSet
 79          self._repositories_url: Attribute[str] = NotSet
 80          self._slug: Attribute[str] = NotSet
 81          self._url: Attribute[str] = NotSet
 82          self._organization: Attribute[github.Organization.Organization] = NotSet
 83          self._privacy: Attribute[str] = NotSet
 84          self._parent: Attribute[github.Team.Team] = NotSet
 85          self._html_url: Attribute[str] = NotSet
 86  
 87      def __repr__(self) -> str:
 88          return self.get__repr__({"id": self._id.value, "name": self._name.value})
 89  
 90      @property
 91      def id(self) -> int:
 92          self._completeIfNotSet(self._id)
 93          return self._id.value
 94  
 95      @property
 96      def members_count(self) -> int:
 97          self._completeIfNotSet(self._members_count)
 98          return self._members_count.value
 99  
100      @property
101      def members_url(self) -> str:
102          self._completeIfNotSet(self._members_url)
103          return self._members_url.value
104  
105      @property
106      def name(self) -> str:
107          self._completeIfNotSet(self._name)
108          return self._name.value
109  
110      @property
111      def description(self) -> str:
112          self._completeIfNotSet(self._description)
113          return self._description.value
114  
115      @property
116      def permission(self) -> str:
117          self._completeIfNotSet(self._permission)
118          return self._permission.value
119  
120      @property
121      def repos_count(self) -> int:
122          self._completeIfNotSet(self._repos_count)
123          return self._repos_count.value
124  
125      @property
126      def repositories_url(self) -> str:
127          self._completeIfNotSet(self._repositories_url)
128          return self._repositories_url.value
129  
130      @property
131      def slug(self) -> str:
132          self._completeIfNotSet(self._slug)
133          return self._slug.value
134  
135      @property
136      def url(self) -> str:
137          self._completeIfNotSet(self._url)
138          return self._url.value
139  
140      @property
141      def organization(self) -> Organization:
142          self._completeIfNotSet(self._organization)
143          return self._organization.value
144  
145      @property
146      def privacy(self) -> str:
147          self._completeIfNotSet(self._privacy)
148          return self._privacy.value
149  
150      @property
151      def parent(self) -> Team:
152          self._completeIfNotSet(self._parent)
153          return self._parent.value
154  
155      @property
156      def html_url(self) -> str:
157          self._completeIfNotSet(self._html_url)
158          return self._html_url.value
159  
160      def add_to_members(self, member: NamedUser) -> None:
161          """
162          This API call is deprecated. Use `add_membership` instead.
163          https://docs.github.com/en/rest/reference/teams#add-or-update-team-membership-for-a-user-legacy
164  
165          :calls: `PUT /teams/{id}/members/{user} <https://docs.github.com/en/rest/reference/teams>`_
166          """
167          assert isinstance(member, github.NamedUser.NamedUser), member
168          headers, data = self._requester.requestJsonAndCheck("PUT", f"{self.url}/members/{member._identity}")
169  
170      def add_membership(self, member: NamedUser, role: Opt[str] = NotSet) -> None:
171          """
172          :calls: `PUT /teams/{id}/memberships/{user} <https://docs.github.com/en/rest/reference/teams>`_
173          """
174          assert isinstance(member, github.NamedUser.NamedUser), member
175          assert role is NotSet or isinstance(role, str), role
176          if role is not NotSet:
177              assert role in ["member", "maintainer"]
178              put_parameters = {
179                  "role": role,
180              }
181          else:
182              put_parameters = {
183                  "role": "member",
184              }
185          headers, data = self._requester.requestJsonAndCheck(
186              "PUT", f"{self.url}/memberships/{member._identity}", input=put_parameters
187          )
188  
189      def get_team_membership(self, member: str | NamedUser) -> Membership:
190          """
191          :calls: `GET /orgs/{org}/memberships/team/{team_id}/{username} <https://docs.github.com/en/rest/reference/teams#get-team-membership-for-a-user>`_
192          """
193          assert isinstance(member, str) or isinstance(member, github.NamedUser.NamedUser), member
194          if isinstance(member, github.NamedUser.NamedUser):
195              member = member._identity
196          headers, data = self._requester.requestJsonAndCheck("GET", f"{self.url}/memberships/{member}")
197          return github.Membership.Membership(self._requester, headers, data, completed=True)
198  
199      def add_to_repos(self, repo: Repository) -> None:
200          """
201          :calls: `PUT /teams/{id}/repos/{org}/{repo} <https://docs.github.com/en/rest/reference/teams>`_
202          """
203          assert isinstance(repo, github.Repository.Repository), repo
204          headers, data = self._requester.requestJsonAndCheck("PUT", f"{self.url}/repos/{repo._identity}")
205  
206      def get_repo_permission(self, repo: Repository) -> Permissions | None:
207          """
208          :calls: `GET /teams/{id}/repos/{org}/{repo} <https://docs.github.com/en/rest/reference/teams>`_
209          """
210          assert isinstance(repo, github.Repository.Repository) or isinstance(repo, str), repo
211          if isinstance(repo, github.Repository.Repository):
212              repo = repo._identity  # type: ignore
213          try:
214              headers, data = self._requester.requestJsonAndCheck(
215                  "GET",
216                  f"{self.url}/repos/{repo}",
217                  headers={"Accept": Consts.teamRepositoryPermissions},
218              )
219              return github.Permissions.Permissions(self._requester, headers, data["permissions"], completed=True)
220          except UnknownObjectException:
221              return None
222  
223      @deprecated(
224          reason="""
225          Team.set_repo_permission() is deprecated, use Team.update_team_repository() instead.
226          """
227      )
228      def set_repo_permission(self, repo: Repository, permission: str) -> None:
229          """
230          :calls: `PUT /teams/{id}/repos/{org}/{repo} <https://docs.github.com/en/rest/reference/teams>`_
231          :param repo: :class:`github.Repository.Repository`
232          :param permission: string
233          :rtype: None
234          """
235  
236          assert isinstance(repo, github.Repository.Repository), repo
237          put_parameters = {
238              "permission": permission,
239          }
240          headers, data = self._requester.requestJsonAndCheck(
241              "PUT", f"{self.url}/repos/{repo._identity}", input=put_parameters
242          )
243  
244      def update_team_repository(self, repo: Repository, permission: str) -> bool:
245          """
246          :calls: `PUT /orgs/{org}/teams/{team_slug}/repos/{owner}/{repo} <https://docs.github.com/en/rest/reference/teams#check-team-permissions-for-a-repository>`_
247          """
248          assert isinstance(repo, github.Repository.Repository) or isinstance(repo, str), repo
249          assert isinstance(permission, str), permission
250          if isinstance(repo, github.Repository.Repository):
251              repo_url_param = repo._identity
252          else:
253              repo_url_param = repo
254          put_parameters = {
255              "permission": permission,
256          }
257          status, _, _ = self._requester.requestJson(
258              "PUT",
259              f"{self.organization.url}/teams/{self.slug}/repos/{repo_url_param}",
260              input=put_parameters,
261          )
262          return status == 204
263  
264      def delete(self) -> None:
265          """
266          :calls: `DELETE /teams/{id} <https://docs.github.com/en/rest/reference/teams#delete-a-team>`_
267          """
268          headers, data = self._requester.requestJsonAndCheck("DELETE", self.url)
269  
270      def edit(
271          self,
272          name: str,
273          description: Opt[str] = NotSet,
274          permission: Opt[str] = NotSet,
275          privacy: Opt[str] = NotSet,
276      ) -> None:
277          """
278          :calls: `PATCH /teams/{id} <https://docs.github.com/en/rest/reference/teams#update-a-team>`_
279          """
280          assert isinstance(name, str), name
281          assert description is NotSet or isinstance(description, str), description
282          assert permission is NotSet or isinstance(permission, str), permission
283          assert privacy is NotSet or isinstance(privacy, str), privacy
284          post_parameters = NotSet.remove_unset_items(
285              {"name": name, "description": description, "permission": permission, "privacy": privacy}
286          )
287  
288          headers, data = self._requester.requestJsonAndCheck("PATCH", self.url, input=post_parameters)
289          self._useAttributes(data)
290  
291      def get_teams(self) -> PaginatedList[Team]:
292          """
293          :calls: `GET /teams/{id}/teams <https://docs.github.com/en/rest/reference/teams#list-teams>`_
294          """
295          return github.PaginatedList.PaginatedList(
296              github.Team.Team,
297              self._requester,
298              f"{self.url}/teams",
299              None,
300          )
301  
302      def get_discussions(self) -> PaginatedList[TeamDiscussion]:
303          """
304          :calls: `GET /teams/{id}/discussions <https://docs.github.com/en/rest/reference/teams#list-discussions>`_
305          """
306          return github.PaginatedList.PaginatedList(
307              github.TeamDiscussion.TeamDiscussion,
308              self._requester,
309              f"{self.url}/discussions",
310              None,
311              headers={"Accept": Consts.mediaTypeTeamDiscussionsPreview},
312          )
313  
314      def get_members(self, role: Opt[str] = NotSet) -> PaginatedList[NamedUser]:
315          """
316          :calls: `GET /teams/{id}/members <https://docs.github.com/en/rest/reference/teams#list-team-members>`_
317          """
318          assert role is NotSet or isinstance(role, str), role
319          url_parameters: dict[str, Any] = {}
320          if role is not NotSet:
321              assert role in ["member", "maintainer", "all"]
322              url_parameters["role"] = role
323          return github.PaginatedList.PaginatedList(
324              github.NamedUser.NamedUser,
325              self._requester,
326              f"{self.url}/members",
327              url_parameters,
328          )
329  
330      def get_repos(self) -> PaginatedList[Repository]:
331          """
332          :calls: `GET /teams/{id}/repos <https://docs.github.com/en/rest/reference/teams>`_
333          """
334          return github.PaginatedList.PaginatedList(
335              github.Repository.Repository, self._requester, f"{self.url}/repos", None
336          )
337  
338      def invitations(self) -> PaginatedList[NamedUser]:
339          """
340          :calls: `GET /teams/{id}/invitations <https://docs.github.com/en/rest/reference/teams#members>`_
341          """
342          return github.PaginatedList.PaginatedList(
343              github.NamedUser.NamedUser,
344              self._requester,
345              f"{self.url}/invitations",
346              None,
347              headers={"Accept": Consts.mediaTypeOrganizationInvitationPreview},
348          )
349  
350      def has_in_members(self, member: NamedUser) -> bool:
351          """
352          :calls: `GET /teams/{id}/members/{user} <https://docs.github.com/en/rest/reference/teams>`_
353          """
354          assert isinstance(member, github.NamedUser.NamedUser), member
355          status, headers, data = self._requester.requestJson("GET", f"{self.url}/members/{member._identity}")
356          return status == 204
357  
358      def has_in_repos(self, repo: Repository) -> bool:
359          """
360          :calls: `GET /teams/{id}/repos/{owner}/{repo} <https://docs.github.com/en/rest/reference/teams>`_
361          """
362          assert isinstance(repo, github.Repository.Repository), repo
363          status, headers, data = self._requester.requestJson("GET", f"{self.url}/repos/{repo._identity}")
364          return status == 204
365  
366      def remove_membership(self, member: NamedUser) -> None:
367          """
368          :calls: `DELETE /teams/{team_id}/memberships/{username} <https://docs.github.com/en/rest/reference/teams#remove-team-membership-for-a-user>`_
369          """
370          assert isinstance(member, github.NamedUser.NamedUser), member
371          headers, data = self._requester.requestJsonAndCheck("DELETE", f"{self.url}/memberships/{member._identity}")
372  
373      def remove_from_members(self, member: NamedUser) -> None:
374          """
375          This API call is deprecated. Use `remove_membership` instead:
376          https://docs.github.com/en/rest/reference/teams#add-or-update-team-membership-for-a-user-legacy
377  
378          :calls: `DELETE /teams/{id}/members/{user} <https://docs.github.com/en/rest/reference/teams>`_
379          """
380          assert isinstance(member, github.NamedUser.NamedUser), member
381          headers, data = self._requester.requestJsonAndCheck("DELETE", f"{self.url}/members/{member._identity}")
382  
383      def remove_from_repos(self, repo: Repository) -> None:
384          """
385          :calls: `DELETE /teams/{id}/repos/{owner}/{repo} <https://docs.github.com/en/rest/reference/teams>`_
386          """
387          assert isinstance(repo, github.Repository.Repository), repo
388          headers, data = self._requester.requestJsonAndCheck("DELETE", f"{self.url}/repos/{repo._identity}")
389  
390      @property
391      def _identity(self) -> int:
392          return self.id
393  
394      def _useAttributes(self, attributes: dict[str, Any]) -> None:
395          if "id" in attributes:  # pragma no branch
396              self._id = self._makeIntAttribute(attributes["id"])
397          if "members_count" in attributes:  # pragma no branch
398              self._members_count = self._makeIntAttribute(attributes["members_count"])
399          if "members_url" in attributes:  # pragma no branch
400              self._members_url = self._makeStringAttribute(attributes["members_url"])
401          if "name" in attributes:  # pragma no branch
402              self._name = self._makeStringAttribute(attributes["name"])
403          if "description" in attributes:  # pragma no branch
404              self._description = self._makeStringAttribute(attributes["description"])
405          if "permission" in attributes:  # pragma no branch
406              self._permission = self._makeStringAttribute(attributes["permission"])
407          if "repos_count" in attributes:  # pragma no branch
408              self._repos_count = self._makeIntAttribute(attributes["repos_count"])
409          if "repositories_url" in attributes:  # pragma no branch
410              self._repositories_url = self._makeStringAttribute(attributes["repositories_url"])
411          if "slug" in attributes:  # pragma no branch
412              self._slug = self._makeStringAttribute(attributes["slug"])
413          if "url" in attributes:  # pragma no branch
414              self._url = self._makeStringAttribute(attributes["url"])
415          if "organization" in attributes:  # pragma no branch
416              self._organization = self._makeClassAttribute(github.Organization.Organization, attributes["organization"])
417          if "privacy" in attributes:  # pragma no branch
418              self._privacy = self._makeStringAttribute(attributes["privacy"])
419          if "parent" in attributes:  # pragma no branch
420              self._parent = self._makeClassAttribute(github.Team.Team, attributes["parent"])
421          if "html_url" in attributes:
422              self._html_url = self._makeStringAttribute(attributes["html_url"])