Skip to content

Commit bad1d52

Browse files
init: add sources
0 parents  commit bad1d52

File tree

8 files changed

+217
-0
lines changed

8 files changed

+217
-0
lines changed

.env.template

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
GITHUB_ACCESS_TOKEN=your_github_access_token

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__pycache**
2+
.env
3+

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# GitHub Multi user invite
2+
3+
A simple script to invite multiple users to a GitHub organization.
4+
5+
## Usage
6+
7+
Clone this repository & install dependencies:
8+
9+
```bash
10+
git clone https://github.com/GDSCParulUniversity/Github-multi-user-invite.git
11+
cd github-multi-user-invite
12+
pip install -r requirements.txt
13+
```
14+
15+
Create a personal access token with the `admin:org` scope from [GitHub](https://github.com/settings/tokens) and create a `.env` file with the following content:
16+
17+
```bash
18+
GITHUB_ACCESS_TOKEN=your_token_here
19+
```
20+
21+
> **Note**
22+
> You should be have owner/admin access to the organization.
23+
24+
Create a file ( e.g. `users.txt` ) with the list of users to invite, one per line.
25+
26+
example:
27+
28+
```txt
29+
saicharankandukuri
30+
vinci-d
31+
torvalds
32+
```
33+
34+
> **Warning**
35+
> Cross check the usernames before adding them to the list for safety.
36+
37+
Run the script:
38+
39+
```bash
40+
python3 main.py --org your_org_name --users_file users.txt
41+
```
42+
43+
## Contributing
44+
45+
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
46+
47+
## License
48+
49+
This project is licensed under the MIT License.

github.py

Whitespace-only changes.

main.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# pylint: disable=missing-module-docstring
2+
import os
3+
import sys
4+
import argparse
5+
from dotenv import load_dotenv
6+
from rich.progress import track
7+
from rich import print as cprint
8+
from utils import github
9+
10+
gh: github
11+
12+
13+
def multi_invite(org: str, a_users: list):
14+
"""
15+
Invite multiple users to a GitHub organization.
16+
17+
Args:
18+
org (str): The name of the GitHub organization.
19+
users (list): A list of usernames to invite.
20+
21+
Returns:
22+
None
23+
"""
24+
# check if user exists
25+
cprint(f"[magenta] Inviting {len(a_users)} user/s ..")
26+
for user in track(a_users, description="Inviting users"):
27+
uid = gh.get_user_id(user)
28+
29+
if uid is None:
30+
cprint(f"[red]: user {user} does not exists")
31+
continue
32+
33+
cprint(f"[green]: sending invite to {user}.")
34+
inv = gh.invite_user_org(org, uid)
35+
36+
if inv.status_code == 201:
37+
cprint(f"[green]: invite sent to {user}.")
38+
else:
39+
print(f"[red]: coudn't invite {user}")
40+
print(f"[gray]: LOG: {inv.json()}")
41+
42+
43+
if __name__ == "__main__":
44+
# Load environment variables
45+
if os.path.exists(".env"):
46+
load_dotenv(".env")
47+
48+
# Parse arguments
49+
parser = argparse.ArgumentParser(
50+
prog="GitHub Organization Inviter",
51+
epilog="v0.0.1"
52+
)
53+
parser.add_argument("--users_file", dest="users_file",
54+
help="invite multiple users", required=True)
55+
parser.add_argument(
56+
"--org", dest="org", help="The organization to invite the user to.", required=True)
57+
args = parser.parse_args()
58+
59+
auth = os.environ["GITHUB_ACCESS_TOKEN"]
60+
gh = github(auth)
61+
62+
if not args.org:
63+
cprint("[red]: requires org name")
64+
sys.exit(1)
65+
66+
users = []
67+
if args.users_file:
68+
usr_file = args.users_file
69+
if os.path.exists(usr_file):
70+
with open(usr_file, 'r', encoding="utf-8") as f:
71+
users = f.readlines()
72+
users = [u.strip() for u in users]
73+
74+
multi_invite(args.org, a_users=users)

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
argparse
2+
requests

users.txt

Whitespace-only changes.

utils.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import json, requests
2+
class github:
3+
def __init__(self, auth, org=None):
4+
self.auth = auth
5+
self.org = org
6+
7+
def gh_request(self, path: str, method="GET", data: dict = {}) -> requests.Response:
8+
"""Make a request to the GitHub API.
9+
"""
10+
data = json.dumps(data) if data != {} else None
11+
12+
res = requests.request(
13+
method=method, url=f"https://api.github.com{path}",
14+
headers={
15+
"Accept": "application/vnd.github+json",
16+
"Authorization": f"Bearer {self.auth}",
17+
"X-GitHub-Api-Version": "2022-11-28"
18+
},
19+
data=data
20+
)
21+
22+
return res
23+
24+
def invite_user_org(
25+
self,
26+
org: str, user: int,
27+
teams: list = [], role: str = "direct_member"
28+
) -> requests.Response:
29+
"""
30+
Invite a user to an organization with the specified role and teams.
31+
32+
Args:
33+
org (str): The name of the organization to invite the user to.
34+
user (int): The ID of the user to invite.
35+
teams (list, optional): A list of team IDs to add the user to. Defaults to [].
36+
role (str, optional): The role to assign to the user. Defaults to "direct_member".
37+
38+
Returns:
39+
requests.Response: The response object from the GitHub API.
40+
"""
41+
res = self.gh_request(
42+
f"/orgs/{org}/invitations",
43+
method="POST",
44+
data={
45+
"invitee_id": user,
46+
"role": role,
47+
"team_ids": teams
48+
}
49+
)
50+
51+
return res
52+
53+
def get_user_id(self, user: str) -> int | None:
54+
"""
55+
Get the user ID of a given GitHub username.
56+
57+
Args:
58+
user (str): The GitHub username.
59+
60+
Returns:
61+
int | None: The user ID if the user exists, otherwise None.
62+
"""
63+
64+
res = self.gh_request(f"/users/{user}")
65+
if res.status_code == 200:
66+
return res.json()['id']
67+
else:
68+
return None
69+
70+
def list_teams(self, org: str):
71+
"""
72+
Lists all the teams in the specified organization.
73+
74+
Args:
75+
- org (str): The name of the organization.
76+
77+
Returns:
78+
- None
79+
"""
80+
res = self.gh_request(f"/orgs/{org}/teams")
81+
82+
if res.status_code == 200:
83+
for team in len(res):
84+
print(f"{team.name} | id: {team.id}")
85+
else:
86+
print("Something unexpected happened")
87+
88+

0 commit comments

Comments
 (0)