Repository: PyGithub/PyGithub

Issue:
Organization.add_to_members() doesn't pass role correctly
https://pygithub.readthedocs.io/en/latest/github_objects/Organization.html#github.Organization.Organization.add_to_members passes the role as part of the query string: https://github.com/PyGithub/PyGithub/blob/master/github/Organization.py#L316

But Github expects it as a JSON payload. As a result, all new members are created as `member` (not as `admin`), and you can't update an organization member to `admin` with PyGithub.


Discussion:

Resolving patch:
diff --git a/github/Organization.py b/github/Organization.py
--- a/github/Organization.py
+++ b/github/Organization.py
@@ -313,12 +313,12 @@ def add_to_members(self, member, role=github.GithubObject.NotSet):
         """
         assert isinstance(role, (str, unicode)), role
         assert isinstance(member, github.NamedUser.NamedUser), member
-        url_parameters = {
-            "role": role,
-        }
+        put_parameters = {}
+        if role is not github.GithubObject.NotSet:
+            put_parameters["role"] = role
         headers, data = self._requester.requestJsonAndCheck(
             "PUT",
-            self.url + "/memberships/" + member._identity, parameters=url_parameters
+            self.url + "/memberships/" + member._identity, input=put_parameters
         )
 
     def add_to_public_members(self, public_member):


Test patch:
diff --git a/github/tests/ReplayData/Organization.testAddMembersAdminRole.txt b/github/tests/ReplayData/Organization.testAddMembersAdminRole.txt
--- a/github/tests/ReplayData/Organization.testAddMembersAdminRole.txt
+++ b/github/tests/ReplayData/Organization.testAddMembersAdminRole.txt
@@ -24,9 +24,9 @@ https
 PUT
 api.github.com
 None
-/orgs/BeaverSoftware/memberships/lyloa?role=admin
-{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
-None
+/orgs/BeaverSoftware/memberships/lyloa
+{'Content-Type': 'application/json', 'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+{"role": "admin"}
 200
 [('content-length', '1718'), ('x-runtime-rack', '0.264296'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('x-xss-protection', '1; mode=block'), ('x-content-type-options', 'nosniff'), ('x-accepted-oauth-scopes', 'admin:org, repo'), ('etag', '"00000000000000000000000000000000"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('status', '200 OK'), ('x-ratelimit-remaining', '4995'), ('x-github-media-type', 'github.v3; format=json'), ('access-control-expose-headers', 'ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval'), ('x-github-request-id', '0000:0000:000000:0000000:00000000'), ('date', 'Fri, 06 Apr 2018 12:54:57 GMT'), ('access-control-allow-origin', '*'), ('content-security-policy', "default-src 'none'"), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('x-frame-options', 'deny'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1523022613')]
 {"url":"https://api.github.com/orgs/BeaverSoftware/memberships/lyloa","state":"pending", "role":"member","organization_url":"https://api.github.com/orgs/BeaverSoftware","user":{"login":"lyloa","id":1,"avatar_url":"https://avatars1.githubusercontent.com/u/28614060?v=4","gravatar_id":"","url":"https://api.github.com/users/lyloa","html_url":"https://github.com/lyloa","followers_url":"https://api.github.com/users/lyloa/followers","following_url":"https://api.github.com/users/lyloa/following{/other_user}","gists_url":"https://api.github.com/users/lyloa/gists{/gist_id}","starred_url":"https://api.github.com/users/lyloa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lyloa/subscriptions","organizations_url":"https://api.github.com/users/lyloa/orgs","repos_url":"https://api.github.com/users/lyloa/repos","events_url":"https://api.github.com/users/lyloa/events{/privacy}","received_events_url":"https://api.github.com/users/lyloa/received_events","type":"User","site_admin":false},"organization":{"login":"BeaverSoftware","id":0000000,"url":"https://api.github.com/orgs/BeaverSoftware","repos_url":"https://api.github.com/orgs/BeaverSoftware/repos","events_url":"https://api.github.com/orgs/BeaverSoftware/events","hooks_url":"https://api.github.com/orgs/BeaverSoftware/hooks","issues_url":"https://api.github.com/orgs/BeaverSoftware/issues","members_url":"https://api.github.com/orgs/BeaverSoftware/members{/member}","public_members_url":"https://api.github.com/orgs/BeaverSoftware/public_members{/member}","avatar_url":"https://avatars1.githubusercontent.com/u/6361338?v=4","description":"Beaver Software is dead.."}}
diff --git a/github/tests/ReplayData/Organization.testAddMembersDefaultRole.txt b/github/tests/ReplayData/Organization.testAddMembersDefaultRole.txt
--- a/github/tests/ReplayData/Organization.testAddMembersDefaultRole.txt
+++ b/github/tests/ReplayData/Organization.testAddMembersDefaultRole.txt
@@ -24,9 +24,9 @@ https
 PUT
 api.github.com
 None
-/orgs/BeaverSoftware/memberships/lyloa?role=member
-{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
-None
+/orgs/BeaverSoftware/memberships/lyloa
+{'Content-Type': 'application/json', 'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+{"role": "member"}
 200
 [('content-length', '1718'), ('x-runtime-rack', '0.352123'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP'), ('x-oauth-scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('x-xss-protection', '1; mode=block'), ('x-content-type-options', 'nosniff'), ('x-accepted-oauth-scopes', 'admin:org, repo'), ('etag', '"92186"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('referrer-policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('status', '200 OK'), ('x-ratelimit-remaining', '4972'), ('x-github-media-type', 'github.v3; format=json'), ('access-control-expose-headers', 'ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval'), ('x-github-request-id', 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'), ('date', 'Thu, 05 Apr 2018 17:09:06 GMT'), ('access-control-allow-origin', '*'), ('content-security-policy', "default-src 'none'"), ('strict-transport-security', 'max-age=31536000; includeSubdomains; preload'), ('server', 'GitHub.com'), ('x-ratelimit-limit', '5000'), ('x-frame-options', 'deny'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1522950939')]
 {"url":"https://api.github.com/orgs/BeaverSoftware/memberships/lyloa","state":"pending", "role":"member","organization_url":"https://api.github.com/orgs/BeaverSoftware","user":{"login":"lyloa","id":1,"avatar_url":"https://avatars1.githubusercontent.com/u/28614060?v=4","gravatar_id":"","url":"https://api.github.com/users/lyloa","html_url":"https://github.com/lyloa","followers_url":"https://api.github.com/users/lyloa/followers","following_url":"https://api.github.com/users/lyloa/following{/other_user}","gists_url":"https://api.github.com/users/lyloa/gists{/gist_id}","starred_url":"https://api.github.com/users/lyloa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lyloa/subscriptions","organizations_url":"https://api.github.com/users/lyloa/orgs","repos_url":"https://api.github.com/users/lyloa/repos","events_url":"https://api.github.com/users/lyloa/events{/privacy}","received_events_url":"https://api.github.com/users/lyloa/received_events","type":"User","site_admin":false},"organization":{"login":"BeaverSoftware","id":0000000,"url":"https://api.github.com/orgs/BeaverSoftware","repos_url":"https://api.github.com/orgs/BeaverSoftware/repos","events_url":"https://api.github.com/orgs/BeaverSoftware/events","hooks_url":"https://api.github.com/orgs/BeaverSoftware/hooks","issues_url":"https://api.github.com/orgs/BeaverSoftware/issues","members_url":"https://api.github.com/orgs/BeaverSoftware/members{/member}","public_members_url":"https://api.github.com/orgs/BeaverSoftware/public_members{/member}","avatar_url":"https://avatars1.githubusercontent.com/u/6361338?v=4","description":"Beaver Software is dead.."}}