AuthenticatedUser.py
1 ############################ Copyrights and license ############################ 2 # # 3 # Copyright 2012 Steve English <steve.english@navetas.com> # 4 # Copyright 2012 Vincent Jacques <vincent@vincent-jacques.net> # 5 # Copyright 2012 Zearin <zearin@gonk.net> # 6 # Copyright 2013 AKFish <akfish@gmail.com> # 7 # Copyright 2013 Cameron White <cawhite@pdx.edu> # 8 # Copyright 2013 Vincent Jacques <vincent@vincent-jacques.net> # 9 # Copyright 2013 poulp <mathieu.nerv@gmail.com> # 10 # Copyright 2014 Tomas Radej <tradej@redhat.com> # 11 # Copyright 2014 Vincent Jacques <vincent@vincent-jacques.net> # 12 # Copyright 2016 E. Dunham <github@edunham.net> # 13 # Copyright 2016 Jannis Gebauer <ja.geb@me.com> # 14 # Copyright 2016 Peter Buckley <dx-pbuckley@users.noreply.github.com> # 15 # Copyright 2017 Balázs Rostás <rostas.balazs@gmail.com> # 16 # Copyright 2017 Jannis Gebauer <ja.geb@me.com> # 17 # Copyright 2017 Simon <spam@esemi.ru> # 18 # Copyright 2018 Wan Liuyang <tsfdye@gmail.com> # 19 # Copyright 2018 bryanhuntesl <31992054+bryanhuntesl@users.noreply.github.com> # 20 # Copyright 2018 sfdye <tsfdye@gmail.com> # 21 # Copyright 2018 itsbruce <it.is.bruce@gmail.com> # 22 # Copyright 2019 Rigas Papathanasopoulos <rigaspapas@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 datetime import datetime, timezone 44 from typing import TYPE_CHECKING, Any, NamedTuple 45 46 import github.Authorization 47 import github.Event 48 import github.Gist 49 import github.GithubObject 50 import github.Invitation 51 import github.Issue 52 import github.Membership 53 import github.Migration 54 import github.NamedUser 55 import github.Notification 56 import github.Organization 57 import github.Plan 58 import github.Repository 59 import github.UserKey 60 from github import Consts 61 from github.GithubObject import ( 62 Attribute, 63 CompletableGithubObject, 64 NotSet, 65 Opt, 66 is_defined, 67 is_optional, 68 is_optional_list, 69 is_undefined, 70 ) 71 from github.PaginatedList import PaginatedList 72 73 if TYPE_CHECKING: 74 from github.Authorization import Authorization 75 from github.Event import Event 76 from github.Gist import Gist 77 from github.InputFileContent import InputFileContent 78 from github.Installation import Installation 79 from github.Invitation import Invitation 80 from github.Issue import Issue 81 from github.Label import Label 82 from github.Membership import Membership 83 from github.Migration import Migration 84 from github.NamedUser import NamedUser 85 from github.Notification import Notification 86 from github.Organization import Organization 87 from github.Plan import Plan 88 from github.Project import Project 89 from github.Repository import Repository 90 from github.Team import Team 91 from github.UserKey import UserKey 92 93 94 class EmailData(NamedTuple): 95 email: str 96 primary: bool 97 verified: bool 98 visibility: str 99 100 101 class AuthenticatedUser(CompletableGithubObject): 102 """ 103 This class represents AuthenticatedUsers as returned by https://docs.github.com/en/rest/reference/users#get-the-authenticated-user 104 105 An AuthenticatedUser object can be created by calling ``get_user()`` on a Github object. 106 """ 107 108 def _initAttributes(self) -> None: 109 self._avatar_url: Attribute[str] = NotSet 110 self._bio: Attribute[str] = NotSet 111 self._blog: Attribute[str] = NotSet 112 self._collaborators: Attribute[int] = NotSet 113 self._company: Attribute[str] = NotSet 114 self._created_at: Attribute[datetime] = NotSet 115 self._disk_usage: Attribute[int] = NotSet 116 self._email: Attribute[str] = NotSet 117 self._events_url: Attribute[str] = NotSet 118 self._followers: Attribute[int] = NotSet 119 self._followers_url: Attribute[str] = NotSet 120 self._following: Attribute[int] = NotSet 121 self._following_url: Attribute[str] = NotSet 122 self._gists_url: Attribute[str] = NotSet 123 self._gravatar_id: Attribute[str] = NotSet 124 self._hireable: Attribute[bool] = NotSet 125 self._html_url: Attribute[str] = NotSet 126 self._id: Attribute[int] = NotSet 127 self._location: Attribute[str] = NotSet 128 self._login: Attribute[str] = NotSet 129 self._name: Attribute[str] = NotSet 130 self._node_id: Attribute[str] = NotSet 131 self._organizations_url: Attribute[str] = NotSet 132 self._owned_private_repos: Attribute[int] = NotSet 133 self._plan: Attribute[github.Plan.Plan] = NotSet 134 self._private_gists: Attribute[int] = NotSet 135 self._public_gists: Attribute[int] = NotSet 136 self._public_repos: Attribute[int] = NotSet 137 self._received_events_url: Attribute[str] = NotSet 138 self._repos_url: Attribute[str] = NotSet 139 self._site_admin: Attribute[bool] = NotSet 140 self._starred_url: Attribute[str] = NotSet 141 self._subscriptions_url: Attribute[str] = NotSet 142 self._total_private_repos: Attribute[int] = NotSet 143 self._type: Attribute[str] = NotSet 144 self._updated_at: Attribute[datetime] = NotSet 145 self._url: Attribute[str] = NotSet 146 self._two_factor_authentication: Attribute[bool] = NotSet 147 148 def __repr__(self) -> str: 149 return self.get__repr__({"login": self._login.value}) 150 151 @property 152 def avatar_url(self) -> str: 153 self._completeIfNotSet(self._avatar_url) 154 return self._avatar_url.value 155 156 @property 157 def bio(self) -> str: 158 self._completeIfNotSet(self._bio) 159 return self._bio.value 160 161 @property 162 def blog(self) -> str: 163 self._completeIfNotSet(self._blog) 164 return self._blog.value 165 166 @property 167 def collaborators(self) -> int: 168 self._completeIfNotSet(self._collaborators) 169 return self._collaborators.value 170 171 @property 172 def company(self) -> str: 173 self._completeIfNotSet(self._company) 174 return self._company.value 175 176 @property 177 def created_at(self) -> datetime: 178 self._completeIfNotSet(self._created_at) 179 return self._created_at.value 180 181 @property 182 def disk_usage(self) -> int: 183 self._completeIfNotSet(self._disk_usage) 184 return self._disk_usage.value 185 186 @property 187 def email(self) -> str: 188 self._completeIfNotSet(self._email) 189 return self._email.value 190 191 @property 192 def events_url(self) -> str: 193 self._completeIfNotSet(self._events_url) 194 return self._events_url.value 195 196 @property 197 def followers(self) -> int: 198 self._completeIfNotSet(self._followers) 199 return self._followers.value 200 201 @property 202 def followers_url(self) -> str: 203 self._completeIfNotSet(self._followers_url) 204 return self._followers_url.value 205 206 @property 207 def following(self) -> int: 208 self._completeIfNotSet(self._following) 209 return self._following.value 210 211 @property 212 def following_url(self) -> str: 213 self._completeIfNotSet(self._following_url) 214 return self._following_url.value 215 216 @property 217 def gists_url(self) -> str: 218 self._completeIfNotSet(self._gists_url) 219 return self._gists_url.value 220 221 @property 222 def gravatar_id(self) -> str: 223 self._completeIfNotSet(self._gravatar_id) 224 return self._gravatar_id.value 225 226 @property 227 def hireable(self) -> bool: 228 self._completeIfNotSet(self._hireable) 229 return self._hireable.value 230 231 @property 232 def html_url(self) -> str: 233 self._completeIfNotSet(self._html_url) 234 return self._html_url.value 235 236 @property 237 def id(self) -> int: 238 self._completeIfNotSet(self._id) 239 return self._id.value 240 241 @property 242 def location(self) -> str: 243 self._completeIfNotSet(self._location) 244 return self._location.value 245 246 @property 247 def login(self) -> str: 248 self._completeIfNotSet(self._login) 249 return self._login.value 250 251 @property 252 def name(self) -> str: 253 self._completeIfNotSet(self._name) 254 return self._name.value 255 256 @property 257 def node_id(self) -> str: 258 self._completeIfNotSet(self._node_id) 259 return self._node_id.value 260 261 @property 262 def organizations_url(self) -> str: 263 self._completeIfNotSet(self._organizations_url) 264 return self._organizations_url.value 265 266 @property 267 def owned_private_repos(self) -> int: 268 self._completeIfNotSet(self._owned_private_repos) 269 return self._owned_private_repos.value 270 271 @property 272 def plan(self) -> Plan: 273 self._completeIfNotSet(self._plan) 274 return self._plan.value 275 276 @property 277 def private_gists(self) -> int: 278 self._completeIfNotSet(self._private_gists) 279 return self._private_gists.value 280 281 @property 282 def public_gists(self) -> int: 283 self._completeIfNotSet(self._public_gists) 284 return self._public_gists.value 285 286 @property 287 def public_repos(self) -> int: 288 self._completeIfNotSet(self._public_repos) 289 return self._public_repos.value 290 291 @property 292 def received_events_url(self) -> str: 293 self._completeIfNotSet(self._received_events_url) 294 return self._received_events_url.value 295 296 @property 297 def repos_url(self) -> str: 298 self._completeIfNotSet(self._repos_url) 299 return self._repos_url.value 300 301 @property 302 def site_admin(self) -> bool: 303 self._completeIfNotSet(self._site_admin) 304 return self._site_admin.value 305 306 @property 307 def starred_url(self) -> str: 308 self._completeIfNotSet(self._starred_url) 309 return self._starred_url.value 310 311 @property 312 def subscriptions_url(self) -> str: 313 self._completeIfNotSet(self._subscriptions_url) 314 return self._subscriptions_url.value 315 316 @property 317 def total_private_repos(self) -> int: 318 self._completeIfNotSet(self._total_private_repos) 319 return self._total_private_repos.value 320 321 @property 322 def type(self) -> str: 323 self._completeIfNotSet(self._type) 324 return self._type.value 325 326 @property 327 def updated_at(self) -> datetime: 328 self._completeIfNotSet(self._updated_at) 329 return self._updated_at.value 330 331 @property 332 def url(self) -> str: 333 self._completeIfNotSet(self._url) 334 return self._url.value 335 336 @property 337 def two_factor_authentication(self) -> bool: 338 self._completeIfNotSet(self._two_factor_authentication) 339 return self._two_factor_authentication.value 340 341 def add_to_emails(self, *emails: str) -> None: 342 """ 343 :calls: `POST /user/emails <http://docs.github.com/en/rest/reference/users#emails>`_ 344 """ 345 assert all(isinstance(element, str) for element in emails), emails 346 post_parameters = {"emails": emails} 347 headers, data = self._requester.requestJsonAndCheck("POST", "/user/emails", input=post_parameters) 348 349 def add_to_following(self, following: NamedUser) -> None: 350 """ 351 :calls: `PUT /user/following/{user} <http://docs.github.com/en/rest/reference/users#followers>`_ 352 """ 353 assert isinstance(following, github.NamedUser.NamedUser), following 354 headers, data = self._requester.requestJsonAndCheck("PUT", f"/user/following/{following._identity}") 355 356 def add_to_starred(self, starred: Repository) -> None: 357 """ 358 :calls: `PUT /user/starred/{owner}/{repo} <http://docs.github.com/en/rest/reference/activity#starring>`_ 359 """ 360 assert isinstance(starred, github.Repository.Repository), starred 361 headers, data = self._requester.requestJsonAndCheck("PUT", f"/user/starred/{starred._identity}") 362 363 def add_to_subscriptions(self, subscription: Repository) -> None: 364 """ 365 :calls: `PUT /user/subscriptions/{owner}/{repo} <http://docs.github.com/en/rest/reference/activity#watching>`_ 366 """ 367 assert isinstance(subscription, github.Repository.Repository), subscription 368 headers, data = self._requester.requestJsonAndCheck("PUT", f"/user/subscriptions/{subscription._identity}") 369 370 def add_to_watched(self, watched: Repository) -> None: 371 """ 372 :calls: `PUT /repos/{owner}/{repo}/subscription <http://docs.github.com/en/rest/reference/activity#watching>`_ 373 """ 374 assert isinstance(watched, github.Repository.Repository), watched 375 headers, data = self._requester.requestJsonAndCheck( 376 "PUT", 377 f"/repos/{watched._identity}/subscription", 378 input={"subscribed": True}, 379 ) 380 381 def create_authorization( 382 self, 383 scopes: Opt[list[str]] = NotSet, 384 note: Opt[str] = NotSet, 385 note_url: Opt[str] = NotSet, 386 client_id: Opt[str] = NotSet, 387 client_secret: Opt[str] = NotSet, 388 onetime_password: str | None = None, 389 ) -> Authorization: 390 """ 391 :calls: `POST /authorizations <https://docs.github.com/en/developers/apps/authorizing-oauth-apps>`_ 392 """ 393 assert is_optional_list(scopes, str), scopes 394 assert is_optional(note, str), note 395 assert is_optional(note_url, str), note_url 396 assert is_optional(client_id, str), client_id 397 assert is_optional(client_secret, str), client_secret 398 assert onetime_password is None or isinstance(onetime_password, str), onetime_password 399 post_parameters: dict[str, Any] = NotSet.remove_unset_items( 400 { 401 "scopes": scopes, 402 "note": note, 403 "note_url": note_url, 404 "client_id": client_id, 405 "client_secret": client_secret, 406 } 407 ) 408 409 if onetime_password is not None: 410 request_header = {Consts.headerOTP: onetime_password} # pragma no cover (Should be covered) 411 else: 412 request_header = None 413 headers, data = self._requester.requestJsonAndCheck( 414 "POST", 415 "/authorizations", 416 input=post_parameters, 417 headers=request_header, 418 ) 419 return github.Authorization.Authorization(self._requester, headers, data, completed=True) 420 421 @staticmethod 422 def create_fork( 423 repo: Repository, 424 name: Opt[str] = NotSet, 425 default_branch_only: Opt[bool] = NotSet, 426 ) -> Repository: 427 """ 428 :calls: `POST /repos/{owner}/{repo}/forks <http://docs.github.com/en/rest/reference/repos#forks>`_ 429 """ 430 assert isinstance(repo, github.Repository.Repository), repo 431 return repo.create_fork( 432 organization=github.GithubObject.NotSet, 433 name=name, 434 default_branch_only=default_branch_only, 435 ) 436 437 def create_repo_from_template( 438 self, 439 name: str, 440 repo: Repository, 441 description: Opt[str] = NotSet, 442 private: Opt[bool] = NotSet, 443 ) -> Repository: 444 """ 445 :calls: `POST /repos/{template_owner}/{template_repo}/generate <https://docs.github.com/en/rest/reference/repos#create-a-repository-using-a-template>`_ 446 """ 447 assert isinstance(name, str), name 448 assert isinstance(repo, github.Repository.Repository), repo 449 assert is_optional(description, str), description 450 assert is_optional(private, bool), private 451 post_parameters: dict[str, Any] = NotSet.remove_unset_items( 452 { 453 "name": name, 454 "owner": self.login, 455 "description": description, 456 "private": private, 457 } 458 ) 459 460 headers, data = self._requester.requestJsonAndCheck( 461 "POST", 462 f"/repos/{repo.owner.login}/{repo.name}/generate", 463 input=post_parameters, 464 headers={"Accept": "application/vnd.github.v3+json"}, 465 ) 466 return github.Repository.Repository(self._requester, headers, data, completed=True) 467 468 def create_gist( 469 self, 470 public: bool, 471 files: dict[str, InputFileContent], 472 description: Opt[str] = NotSet, 473 ) -> Gist: 474 """ 475 :calls: `POST /gists <http://docs.github.com/en/rest/reference/gists>`_ 476 """ 477 assert isinstance(public, bool), public 478 assert all(isinstance(element, github.InputFileContent) for element in files.values()), files 479 assert is_undefined(description) or isinstance(description, str), description 480 post_parameters = { 481 "public": public, 482 "files": {key: value._identity for key, value in files.items()}, 483 } 484 if is_defined(description): 485 post_parameters["description"] = description 486 headers, data = self._requester.requestJsonAndCheck("POST", "/gists", input=post_parameters) 487 return github.Gist.Gist(self._requester, headers, data, completed=True) 488 489 def create_key(self, title: str, key: str) -> UserKey: 490 """ 491 :calls: `POST /user/keys <http://docs.github.com/en/rest/reference/users#git-ssh-keys>`_ 492 :param title: string 493 :param key: string 494 :rtype: :class:`github.UserKey.UserKey` 495 """ 496 assert isinstance(title, str), title 497 assert isinstance(key, str), key 498 post_parameters = { 499 "title": title, 500 "key": key, 501 } 502 headers, data = self._requester.requestJsonAndCheck("POST", "/user/keys", input=post_parameters) 503 return github.UserKey.UserKey(self._requester, headers, data, completed=True) 504 505 def create_project(self, name: str, body: Opt[str] = NotSet) -> Project: 506 """ 507 :calls: `POST /user/projects <https://docs.github.com/en/rest/reference/projects#create-a-user-project>`_ 508 :param name: string 509 :param body: string 510 :rtype: :class:`github.Project.Project` 511 """ 512 assert isinstance(name, str), name 513 assert is_undefined(body) or isinstance(body, str), body 514 post_parameters = { 515 "name": name, 516 "body": body, 517 } 518 headers, data = self._requester.requestJsonAndCheck( 519 "POST", 520 "/user/projects", 521 input=post_parameters, 522 headers={"Accept": Consts.mediaTypeProjectsPreview}, 523 ) 524 return github.Project.Project(self._requester, headers, data, completed=True) 525 526 def create_repo( 527 self, 528 name: str, 529 description: Opt[str] = NotSet, 530 homepage: Opt[str] = NotSet, 531 private: Opt[bool] = NotSet, 532 has_issues: Opt[bool] = NotSet, 533 has_wiki: Opt[bool] = NotSet, 534 has_downloads: Opt[bool] = NotSet, 535 has_projects: Opt[bool] = NotSet, 536 auto_init: Opt[bool] = NotSet, 537 license_template: Opt[str] = NotSet, 538 gitignore_template: Opt[str] = NotSet, 539 allow_squash_merge: Opt[bool] = NotSet, 540 allow_merge_commit: Opt[bool] = NotSet, 541 allow_rebase_merge: Opt[bool] = NotSet, 542 delete_branch_on_merge: Opt[bool] = NotSet, 543 ) -> Repository: 544 """ 545 :calls: `POST /user/repos <http://docs.github.com/en/rest/reference/repos>`_ 546 """ 547 assert isinstance(name, str), name 548 assert is_optional(description, str), description 549 assert is_optional(homepage, str), homepage 550 assert is_optional(private, bool), private 551 assert is_optional(has_issues, bool), has_issues 552 assert is_optional(has_wiki, bool), has_wiki 553 assert is_optional(has_downloads, bool), has_downloads 554 assert is_optional(has_projects, bool), has_projects 555 assert is_optional(auto_init, bool), auto_init 556 assert is_optional(license_template, str), license_template 557 assert is_optional(gitignore_template, str), gitignore_template 558 assert is_optional(allow_squash_merge, bool), allow_squash_merge 559 assert is_optional(allow_merge_commit, bool), allow_merge_commit 560 assert is_optional(allow_rebase_merge, bool), allow_rebase_merge 561 assert is_optional(delete_branch_on_merge, bool), delete_branch_on_merge 562 post_parameters: dict[str, Any] = NotSet.remove_unset_items( 563 { 564 "name": name, 565 "description": description, 566 "homepage": homepage, 567 "private": private, 568 "has_issues": has_issues, 569 "has_wiki": has_wiki, 570 "has_downloads": has_downloads, 571 "has_projects": has_projects, 572 "auto_init": auto_init, 573 "license_template": license_template, 574 "gitignore_template": gitignore_template, 575 "allow_squash_merge": allow_squash_merge, 576 "allow_merge_commit": allow_merge_commit, 577 "allow_rebase_merge": allow_rebase_merge, 578 "delete_branch_on_merge": delete_branch_on_merge, 579 } 580 ) 581 582 headers, data = self._requester.requestJsonAndCheck("POST", "/user/repos", input=post_parameters) 583 return github.Repository.Repository(self._requester, headers, data, completed=True) 584 585 def edit( 586 self, 587 name: Opt[str] = NotSet, 588 email: Opt[str] = NotSet, 589 blog: Opt[str] = NotSet, 590 company: Opt[str] = NotSet, 591 location: Opt[str] = NotSet, 592 hireable: Opt[bool] = NotSet, 593 bio: Opt[str] = NotSet, 594 ) -> None: 595 """ 596 :calls: `PATCH /user <http://docs.github.com/en/rest/reference/users>`_ 597 """ 598 assert is_optional(name, str), name 599 assert is_optional(email, str), email 600 assert is_optional(blog, str), blog 601 assert is_optional(company, str), company 602 assert is_optional(location, str), location 603 assert is_optional(hireable, bool), hireable 604 assert is_optional(bio, str), bio 605 post_parameters: dict[str, Any] = NotSet.remove_unset_items( 606 { 607 "name": name, 608 "email": email, 609 "blog": blog, 610 "company": company, 611 "location": location, 612 "hireable": hireable, 613 "bio": bio, 614 } 615 ) 616 617 headers, data = self._requester.requestJsonAndCheck("PATCH", "/user", input=post_parameters) 618 self._useAttributes(data) 619 620 def get_authorization(self, id: int) -> Authorization: 621 """ 622 :calls: `GET /authorizations/{id} <https://docs.github.com/en/developers/apps/authorizing-oauth-apps>`_ 623 """ 624 assert isinstance(id, int), id 625 headers, data = self._requester.requestJsonAndCheck("GET", f"/authorizations/{id}") 626 return github.Authorization.Authorization(self._requester, headers, data, completed=True) 627 628 def get_authorizations(self) -> PaginatedList[Authorization]: 629 """ 630 :calls: `GET /authorizations <https://docs.github.com/en/developers/apps/authorizing-oauth-apps>`_ 631 """ 632 return PaginatedList(github.Authorization.Authorization, self._requester, "/authorizations", None) 633 634 def get_emails(self) -> list[EmailData]: 635 """ 636 :calls: `GET /user/emails <http://docs.github.com/en/rest/reference/users#emails>`_ 637 """ 638 headers, data = self._requester.requestJsonAndCheck("GET", "/user/emails") 639 return [EmailData(**item) for item in data] 640 641 def get_events(self) -> PaginatedList[Event]: 642 """ 643 :calls: `GET /events <http://docs.github.com/en/rest/reference/activity#events>`_ 644 """ 645 return PaginatedList(github.Event.Event, self._requester, "/events", None) 646 647 def get_followers(self) -> PaginatedList[NamedUser]: 648 """ 649 :calls: `GET /user/followers <http://docs.github.com/en/rest/reference/users#followers>`_ 650 """ 651 return PaginatedList(github.NamedUser.NamedUser, self._requester, "/user/followers", None) 652 653 def get_following(self) -> PaginatedList[NamedUser]: 654 """ 655 :calls: `GET /user/following <http://docs.github.com/en/rest/reference/users#followers>`_ 656 """ 657 return PaginatedList(github.NamedUser.NamedUser, self._requester, "/user/following", None) 658 659 def get_gists(self, since: Opt[datetime] = NotSet) -> PaginatedList[Gist]: 660 """ 661 :calls: `GET /gists <http://docs.github.com/en/rest/reference/gists>`_ 662 :param since: datetime format YYYY-MM-DDTHH:MM:SSZ 663 :rtype: :class:`PaginatedList` of :class:`github.Gist.Gist` 664 """ 665 assert is_optional(since, datetime), since 666 url_parameters: dict[str, Any] = {} 667 if is_defined(since): 668 url_parameters["since"] = since.strftime("%Y-%m-%dT%H:%M:%SZ") 669 return PaginatedList(github.Gist.Gist, self._requester, "/gists", url_parameters) 670 671 def get_issues( 672 self, 673 filter: Opt[str] = NotSet, 674 state: Opt[str] = NotSet, 675 labels: Opt[list[Label]] = NotSet, 676 sort: Opt[str] = NotSet, 677 direction: Opt[str] = NotSet, 678 since: Opt[datetime] = NotSet, 679 ) -> PaginatedList[Issue]: 680 """ 681 :calls: `GET /issues <http://docs.github.com/en/rest/reference/issues>`_ 682 """ 683 assert is_optional(filter, str), filter 684 assert is_optional(state, str), state 685 assert is_optional_list(labels, github.Label.Label), labels 686 assert is_optional(sort, str), sort 687 assert is_optional(direction, str), direction 688 assert is_optional(since, datetime), since 689 url_parameters: dict[str, Any] = {} 690 if is_defined(filter): 691 url_parameters["filter"] = filter 692 if is_defined(state): 693 url_parameters["state"] = state 694 if is_defined(labels): 695 url_parameters["labels"] = ",".join(label.name for label in labels) 696 if is_defined(sort): 697 url_parameters["sort"] = sort 698 if is_defined(direction): 699 url_parameters["direction"] = direction 700 if is_defined(since): 701 url_parameters["since"] = since.strftime("%Y-%m-%dT%H:%M:%SZ") 702 return PaginatedList(github.Issue.Issue, self._requester, "/issues", url_parameters) 703 704 def get_user_issues( 705 self, 706 filter: Opt[str] = NotSet, 707 state: Opt[str] = NotSet, 708 labels: Opt[list[Label]] = NotSet, 709 sort: Opt[str] = NotSet, 710 direction: Opt[str] = NotSet, 711 since: Opt[datetime] = NotSet, 712 ) -> PaginatedList[Issue]: 713 """ 714 :calls: `GET /user/issues <http://docs.github.com/en/rest/reference/issues>`_ 715 """ 716 assert is_optional(filter, str), filter 717 assert is_optional(state, str), state 718 assert is_optional_list(labels, github.Label.Label), labels 719 assert is_optional(sort, str), sort 720 assert is_optional(direction, str), direction 721 assert is_optional(since, datetime), since 722 url_parameters: dict[str, Any] = {} 723 if is_defined(filter): 724 url_parameters["filter"] = filter 725 if is_defined(state): 726 url_parameters["state"] = state 727 if is_defined(labels): 728 url_parameters["labels"] = ",".join(label.name for label in labels) 729 if is_defined(sort): 730 url_parameters["sort"] = sort 731 if is_defined(direction): 732 url_parameters["direction"] = direction 733 if is_defined(since): 734 url_parameters["since"] = since.strftime("%Y-%m-%dT%H:%M:%SZ") 735 return PaginatedList(github.Issue.Issue, self._requester, "/user/issues", url_parameters) 736 737 def get_key(self, id: int) -> UserKey: 738 """ 739 :calls: `GET /user/keys/{id} <http://docs.github.com/en/rest/reference/users#git-ssh-keys>`_ 740 """ 741 assert isinstance(id, int), id 742 headers, data = self._requester.requestJsonAndCheck("GET", f"/user/keys/{id}") 743 return github.UserKey.UserKey(self._requester, headers, data, completed=True) 744 745 def get_keys(self) -> PaginatedList[UserKey]: 746 """ 747 :calls: `GET /user/keys <http://docs.github.com/en/rest/reference/users#git-ssh-keys>`_ 748 """ 749 return PaginatedList(github.UserKey.UserKey, self._requester, "/user/keys", None) 750 751 def get_notification(self, id: str) -> Notification: 752 """ 753 :calls: `GET /notifications/threads/{id} <http://docs.github.com/en/rest/reference/activity#notifications>`_ 754 """ 755 756 assert isinstance(id, str), id 757 headers, data = self._requester.requestJsonAndCheck("GET", f"/notifications/threads/{id}") 758 return github.Notification.Notification(self._requester, headers, data, completed=True) 759 760 def get_notifications( 761 self, 762 all: Opt[bool] = NotSet, 763 participating: Opt[bool] = NotSet, 764 since: Opt[datetime] = NotSet, 765 before: Opt[datetime] = NotSet, 766 ) -> PaginatedList[Notification]: 767 """ 768 :calls: `GET /notifications <http://docs.github.com/en/rest/reference/activity#notifications>`_ 769 """ 770 771 assert is_optional(all, bool), all 772 assert is_optional(participating, bool), participating 773 assert is_optional(since, datetime), since 774 assert is_optional(before, datetime), before 775 776 params: dict[str, Any] = {} 777 if is_defined(all): 778 # convert True, False to true, false for api parameters 779 params["all"] = "true" if all else "false" 780 if is_defined(participating): 781 # convert True, False to true, false for api parameters 782 params["participating"] = "true" if participating else "false" 783 if is_defined(since): 784 params["since"] = since.strftime("%Y-%m-%dT%H:%M:%SZ") 785 if is_defined(before): 786 params["before"] = before.strftime("%Y-%m-%dT%H:%M:%SZ") 787 788 return PaginatedList(github.Notification.Notification, self._requester, "/notifications", params) 789 790 def get_organization_events(self, org: Organization) -> PaginatedList[Event]: 791 """ 792 :calls: `GET /users/{user}/events/orgs/{org} <http://docs.github.com/en/rest/reference/activity#events>`_ 793 """ 794 assert isinstance(org, github.Organization.Organization), org 795 return PaginatedList( 796 github.Event.Event, 797 self._requester, 798 f"/users/{self.login}/events/orgs/{org.login}", 799 None, 800 ) 801 802 def get_orgs(self) -> PaginatedList[Organization]: 803 """ 804 :calls: `GET /user/orgs <http://docs.github.com/en/rest/reference/orgs>`_ 805 """ 806 return PaginatedList(github.Organization.Organization, self._requester, "/user/orgs", None) 807 808 def get_repo(self, name: str) -> Repository: 809 """ 810 :calls: `GET /repos/{owner}/{repo} <http://docs.github.com/en/rest/reference/repos>`_ 811 """ 812 assert isinstance(name, str), name 813 headers, data = self._requester.requestJsonAndCheck("GET", f"/repos/{self.login}/{name}") 814 return github.Repository.Repository(self._requester, headers, data, completed=True) 815 816 def get_repos( 817 self, 818 visibility: Opt[str] = NotSet, 819 affiliation: Opt[str] = NotSet, 820 type: Opt[str] = NotSet, 821 sort: Opt[str] = NotSet, 822 direction: Opt[str] = NotSet, 823 ) -> PaginatedList[Repository]: 824 """ 825 :calls: `GET /user/repos <http://docs.github.com/en/rest/reference/repos>`_ 826 """ 827 assert is_optional(visibility, str), visibility 828 assert is_optional(affiliation, str), affiliation 829 assert is_optional(type, str), type 830 assert is_optional(sort, str), sort 831 assert is_optional(direction, str), direction 832 url_parameters = NotSet.remove_unset_items( 833 { 834 "visibility": visibility, 835 "affiliation": affiliation, 836 "type": type, 837 "sort": sort, 838 "direction": direction, 839 } 840 ) 841 return PaginatedList(github.Repository.Repository, self._requester, "/user/repos", url_parameters) 842 843 def get_starred(self) -> PaginatedList[Repository]: 844 """ 845 :calls: `GET /user/starred <http://docs.github.com/en/rest/reference/activity#starring>`_ 846 """ 847 return PaginatedList(github.Repository.Repository, self._requester, "/user/starred", None) 848 849 def get_starred_gists(self) -> PaginatedList[Gist]: 850 """ 851 :calls: `GET /gists/starred <http://docs.github.com/en/rest/reference/gists>`_ 852 """ 853 return PaginatedList(github.Gist.Gist, self._requester, "/gists/starred", None) 854 855 def get_subscriptions(self) -> PaginatedList[Repository]: 856 """ 857 :calls: `GET /user/subscriptions <http://docs.github.com/en/rest/reference/activity#watching>`_ 858 """ 859 return PaginatedList(github.Repository.Repository, self._requester, "/user/subscriptions", None) 860 861 def get_teams(self) -> PaginatedList[Team]: 862 """ 863 :calls: `GET /user/teams <http://docs.github.com/en/rest/reference/teams>`_ 864 """ 865 return PaginatedList(github.Team.Team, self._requester, "/user/teams", None) 866 867 def get_watched(self) -> PaginatedList[Repository]: 868 """ 869 :calls: `GET /user/subscriptions <http://docs.github.com/en/rest/reference/activity#watching>`_ 870 """ 871 return PaginatedList(github.Repository.Repository, self._requester, "/user/subscriptions", None) 872 873 def get_installations(self) -> PaginatedList[Installation]: 874 """ 875 :calls: `GET /user/installations <http://docs.github.com/en/rest/reference/apps>`_ 876 """ 877 return PaginatedList( 878 github.Installation.Installation, 879 self._requester, 880 "/user/installations", 881 None, 882 headers={"Accept": Consts.mediaTypeIntegrationPreview}, 883 list_item="installations", 884 ) 885 886 def has_in_following(self, following: NamedUser) -> bool: 887 """ 888 :calls: `GET /user/following/{user} <http://docs.github.com/en/rest/reference/users#followers>`_ 889 """ 890 assert isinstance(following, github.NamedUser.NamedUser), following 891 status, headers, data = self._requester.requestJson("GET", f"/user/following/{following._identity}") 892 return status == 204 893 894 def has_in_starred(self, starred: Repository) -> bool: 895 """ 896 :calls: `GET /user/starred/{owner}/{repo} <http://docs.github.com/en/rest/reference/activity#starring>`_ 897 """ 898 assert isinstance(starred, github.Repository.Repository), starred 899 status, headers, data = self._requester.requestJson("GET", f"/user/starred/{starred._identity}") 900 return status == 204 901 902 def has_in_subscriptions(self, subscription: Repository) -> bool: 903 """ 904 :calls: `GET /user/subscriptions/{owner}/{repo} <http://docs.github.com/en/rest/reference/activity#watching>`_ 905 """ 906 assert isinstance(subscription, github.Repository.Repository), subscription 907 status, headers, data = self._requester.requestJson("GET", f"/user/subscriptions/{subscription._identity}") 908 return status == 204 909 910 def has_in_watched(self, watched: Repository) -> bool: 911 """ 912 :calls: `GET /repos/{owner}/{repo}/subscription <http://docs.github.com/en/rest/reference/activity#watching>`_ 913 """ 914 assert isinstance(watched, github.Repository.Repository), watched 915 status, headers, data = self._requester.requestJson("GET", f"/repos/{watched._identity}/subscription") 916 return status == 200 917 918 def mark_notifications_as_read(self, last_read_at: datetime | None = None) -> None: 919 """ 920 :calls: `PUT /notifications <https://docs.github.com/en/rest/reference/activity#notifications>`_ 921 """ 922 if last_read_at is None: 923 last_read_at = datetime.now(timezone.utc) 924 assert isinstance(last_read_at, datetime) 925 put_parameters = {"last_read_at": last_read_at.strftime("%Y-%m-%dT%H:%M:%SZ")} 926 927 headers, data = self._requester.requestJsonAndCheck("PUT", "/notifications", input=put_parameters) 928 929 def remove_from_emails(self, *emails: str) -> None: 930 """ 931 :calls: `DELETE /user/emails <http://docs.github.com/en/rest/reference/users#emails>`_ 932 """ 933 assert all(isinstance(element, str) for element in emails), emails 934 post_parameters = {"emails": emails} 935 headers, data = self._requester.requestJsonAndCheck("DELETE", "/user/emails", input=post_parameters) 936 937 def remove_from_following(self, following: NamedUser) -> None: 938 """ 939 :calls: `DELETE /user/following/{user} <http://docs.github.com/en/rest/reference/users#followers>`_ 940 """ 941 assert isinstance(following, github.NamedUser.NamedUser), following 942 headers, data = self._requester.requestJsonAndCheck("DELETE", f"/user/following/{following._identity}") 943 944 def remove_from_starred(self, starred: Repository) -> None: 945 """ 946 :calls: `DELETE /user/starred/{owner}/{repo} <http://docs.github.com/en/rest/reference/activity#starring>`_ 947 """ 948 assert isinstance(starred, github.Repository.Repository), starred 949 headers, data = self._requester.requestJsonAndCheck("DELETE", f"/user/starred/{starred._identity}") 950 951 def remove_from_subscriptions(self, subscription: Repository) -> None: 952 """ 953 :calls: `DELETE /user/subscriptions/{owner}/{repo} <http://docs.github.com/en/rest/reference/activity#watching>`_ 954 """ 955 assert isinstance(subscription, github.Repository.Repository), subscription 956 headers, data = self._requester.requestJsonAndCheck("DELETE", f"/user/subscriptions/{subscription._identity}") 957 958 def remove_from_watched(self, watched: Repository) -> None: 959 """ 960 :calls: `DELETE /repos/{owner}/{repo}/subscription <http://docs.github.com/en/rest/reference/activity#watching>`_ 961 """ 962 assert isinstance(watched, github.Repository.Repository), watched 963 headers, data = self._requester.requestJsonAndCheck("DELETE", f"/repos/{watched._identity}/subscription") 964 965 def accept_invitation(self, invitation: Invitation | int) -> None: 966 """ 967 :calls: `PATCH /user/repository_invitations/{invitation_id} <https://docs.github.com/en/rest/reference/repos/invitations#>`_ 968 """ 969 assert isinstance(invitation, github.Invitation.Invitation) or isinstance(invitation, int) 970 971 if isinstance(invitation, github.Invitation.Invitation): 972 invitation = invitation.id 973 974 headers, data = self._requester.requestJsonAndCheck( 975 "PATCH", f"/user/repository_invitations/{invitation}", input={} 976 ) 977 978 def get_invitations(self) -> PaginatedList[Invitation]: 979 """ 980 :calls: `GET /user/repository_invitations <https://docs.github.com/en/rest/reference/repos#invitations>`_ 981 """ 982 return PaginatedList( 983 github.Invitation.Invitation, 984 self._requester, 985 "/user/repository_invitations", 986 None, 987 ) 988 989 def create_migration( 990 self, 991 repos: list[Repository] | tuple[Repository], 992 lock_repositories: Opt[bool] = NotSet, 993 exclude_attachments: Opt[bool] = NotSet, 994 ) -> Migration: 995 """ 996 :calls: `POST /user/migrations <https://docs.github.com/en/rest/reference/migrations>`_ 997 """ 998 assert isinstance(repos, (list, tuple)), repos 999 assert all(isinstance(repo, str) for repo in repos), repos 1000 assert is_optional(lock_repositories, bool), lock_repositories 1001 assert is_optional(exclude_attachments, bool), exclude_attachments 1002 post_parameters: dict[str, Any] = NotSet.remove_unset_items( 1003 { 1004 "repositories": repos, 1005 "lock_repositories": lock_repositories, 1006 "exclude_attachments": exclude_attachments, 1007 } 1008 ) 1009 1010 headers, data = self._requester.requestJsonAndCheck( 1011 "POST", 1012 "/user/migrations", 1013 input=post_parameters, 1014 headers={"Accept": Consts.mediaTypeMigrationPreview}, 1015 ) 1016 return github.Migration.Migration(self._requester, headers, data, completed=True) 1017 1018 def get_migrations(self) -> PaginatedList[Migration]: 1019 """ 1020 :calls: `GET /user/migrations <https://docs.github.com/en/rest/reference/migrations>`_ 1021 """ 1022 return PaginatedList( 1023 github.Migration.Migration, 1024 self._requester, 1025 "/user/migrations", 1026 None, 1027 headers={"Accept": Consts.mediaTypeMigrationPreview}, 1028 ) 1029 1030 def get_organization_membership(self, org: str) -> Membership: 1031 """ 1032 :calls: `GET /user/memberships/orgs/{org} <https://docs.github.com/en/rest/reference/orgs#get-an-organization-membership-for-the-authenticated-user>`_ 1033 """ 1034 assert isinstance(org, str) 1035 headers, data = self._requester.requestJsonAndCheck("GET", f"/user/memberships/orgs/{org}") 1036 return github.Membership.Membership(self._requester, headers, data, completed=True) 1037 1038 def _useAttributes(self, attributes: dict[str, Any]) -> None: 1039 if "avatar_url" in attributes: # pragma no branch 1040 self._avatar_url = self._makeStringAttribute(attributes["avatar_url"]) 1041 if "bio" in attributes: # pragma no branch 1042 self._bio = self._makeStringAttribute(attributes["bio"]) 1043 if "blog" in attributes: # pragma no branch 1044 self._blog = self._makeStringAttribute(attributes["blog"]) 1045 if "collaborators" in attributes: # pragma no branch 1046 self._collaborators = self._makeIntAttribute(attributes["collaborators"]) 1047 if "company" in attributes: # pragma no branch 1048 self._company = self._makeStringAttribute(attributes["company"]) 1049 if "created_at" in attributes: # pragma no branch 1050 self._created_at = self._makeDatetimeAttribute(attributes["created_at"]) 1051 if "disk_usage" in attributes: # pragma no branch 1052 self._disk_usage = self._makeIntAttribute(attributes["disk_usage"]) 1053 if "email" in attributes: # pragma no branch 1054 self._email = self._makeStringAttribute(attributes["email"]) 1055 if "events_url" in attributes: # pragma no branch 1056 self._events_url = self._makeStringAttribute(attributes["events_url"]) 1057 if "followers" in attributes: # pragma no branch 1058 self._followers = self._makeIntAttribute(attributes["followers"]) 1059 if "followers_url" in attributes: # pragma no branch 1060 self._followers_url = self._makeStringAttribute(attributes["followers_url"]) 1061 if "following" in attributes: # pragma no branch 1062 self._following = self._makeIntAttribute(attributes["following"]) 1063 if "following_url" in attributes: # pragma no branch 1064 self._following_url = self._makeStringAttribute(attributes["following_url"]) 1065 if "gists_url" in attributes: # pragma no branch 1066 self._gists_url = self._makeStringAttribute(attributes["gists_url"]) 1067 if "gravatar_id" in attributes: # pragma no branch 1068 self._gravatar_id = self._makeStringAttribute(attributes["gravatar_id"]) 1069 if "hireable" in attributes: # pragma no branch 1070 self._hireable = self._makeBoolAttribute(attributes["hireable"]) 1071 if "html_url" in attributes: # pragma no branch 1072 self._html_url = self._makeStringAttribute(attributes["html_url"]) 1073 if "id" in attributes: # pragma no branch 1074 self._id = self._makeIntAttribute(attributes["id"]) 1075 if "location" in attributes: # pragma no branch 1076 self._location = self._makeStringAttribute(attributes["location"]) 1077 if "login" in attributes: # pragma no branch 1078 self._login = self._makeStringAttribute(attributes["login"]) 1079 if "name" in attributes: # pragma no branch 1080 self._name = self._makeStringAttribute(attributes["name"]) 1081 if "node_id" in attributes: # pragma no branch 1082 self._node_id = self._makeStringAttribute(attributes["node_id"]) 1083 if "organizations_url" in attributes: # pragma no branch 1084 self._organizations_url = self._makeStringAttribute(attributes["organizations_url"]) 1085 if "owned_private_repos" in attributes: # pragma no branch 1086 self._owned_private_repos = self._makeIntAttribute(attributes["owned_private_repos"]) 1087 if "plan" in attributes: # pragma no branch 1088 self._plan = self._makeClassAttribute(github.Plan.Plan, attributes["plan"]) 1089 if "private_gists" in attributes: # pragma no branch 1090 self._private_gists = self._makeIntAttribute(attributes["private_gists"]) 1091 if "public_gists" in attributes: # pragma no branch 1092 self._public_gists = self._makeIntAttribute(attributes["public_gists"]) 1093 if "public_repos" in attributes: # pragma no branch 1094 self._public_repos = self._makeIntAttribute(attributes["public_repos"]) 1095 if "received_events_url" in attributes: # pragma no branch 1096 self._received_events_url = self._makeStringAttribute(attributes["received_events_url"]) 1097 if "repos_url" in attributes: # pragma no branch 1098 self._repos_url = self._makeStringAttribute(attributes["repos_url"]) 1099 if "site_admin" in attributes: # pragma no branch 1100 self._site_admin = self._makeBoolAttribute(attributes["site_admin"]) 1101 if "starred_url" in attributes: # pragma no branch 1102 self._starred_url = self._makeStringAttribute(attributes["starred_url"]) 1103 if "subscriptions_url" in attributes: # pragma no branch 1104 self._subscriptions_url = self._makeStringAttribute(attributes["subscriptions_url"]) 1105 if "total_private_repos" in attributes: # pragma no branch 1106 self._total_private_repos = self._makeIntAttribute(attributes["total_private_repos"]) 1107 if "type" in attributes: # pragma no branch 1108 self._type = self._makeStringAttribute(attributes["type"]) 1109 if "updated_at" in attributes: # pragma no branch 1110 self._updated_at = self._makeDatetimeAttribute(attributes["updated_at"]) 1111 if "url" in attributes: # pragma no branch 1112 self._url = self._makeStringAttribute(attributes["url"]) 1113 if "two_factor_authentication" in attributes: 1114 self._two_factor_authentication = self._makeBoolAttribute(attributes["two_factor_authentication"])