Skip to content

Commit af1090e

Browse files
Feat: Update google oauth for google calendar integration.
1 parent 8c27331 commit af1090e

File tree

4 files changed

+69
-34
lines changed

4 files changed

+69
-34
lines changed

pyproject.toml

+3
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ module = [
6363
"feedparser.*",
6464
"gitlint.*",
6565
"googleapiclient.*",
66+
"google_api_python_client.*",
67+
"google_auth_httplib2.*",
68+
"google_auth_oauthlib.*",
6669
"irc.*",
6770
"mercurial.*",
6871
"nio.*",

zulip/integrations/google/get-google-credentials

+52-16
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,43 @@
22
import argparse
33
import os
44

5-
from oauth2client import client, tools
6-
from oauth2client.file import Storage
5+
from google.auth.transport.requests import Request # type: ignore[import-not-found]
6+
from google.oauth2.credentials import Credentials # type: ignore[import-not-found]
7+
from google_auth_oauthlib.flow import InstalledAppFlow
8+
9+
parser = argparse.ArgumentParser(add_help=False)
10+
parser.add_argument(
11+
"--auth_host_name", default="localhost", help="Hostname when running a local web server."
12+
)
13+
parser.add_argument(
14+
"--noauth_local_webserver",
15+
action="store_true",
16+
default=False,
17+
help="Do not run a local web server.",
18+
)
19+
parser.add_argument(
20+
"--auth_host_port",
21+
default=[8080, 8090],
22+
type=int,
23+
nargs="*",
24+
help="Port web server should listen on.",
25+
)
26+
flags = parser.parse_args()
727

8-
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
928

1029
# If modifying these scopes, delete your previously saved credentials
1130
# at zulip/bots/gcal/
1231
# NOTE: When adding more scopes, add them after the previous one in the same field, with a space
1332
# seperating them.
14-
SCOPES = "https://www.googleapis.com/auth/calendar.readonly"
33+
SCOPES = ["https://www.googleapis.com/auth/calendar.readonly"]
1534
# This file contains the information that google uses to figure out which application is requesting
1635
# this client's data.
1736
CLIENT_SECRET_FILE = "client_secret.json" # noqa: S105
1837
APPLICATION_NAME = "Zulip Calendar Bot"
1938
HOME_DIR = os.path.expanduser("~")
2039

2140

22-
def get_credentials() -> client.Credentials:
41+
def get_credentials() -> Credentials:
2342
"""Gets valid user credentials from storage.
2443
2544
If nothing has been stored, or if the stored credentials are invalid,
@@ -28,19 +47,36 @@ def get_credentials() -> client.Credentials:
2847
Returns:
2948
Credentials, the obtained credential.
3049
"""
31-
50+
credentials = None
3251
credential_path = os.path.join(HOME_DIR, "google-credentials.json")
33-
34-
store = Storage(credential_path)
35-
credentials = store.get()
36-
if not credentials or credentials.invalid:
37-
flow = client.flow_from_clientsecrets(os.path.join(HOME_DIR, CLIENT_SECRET_FILE), SCOPES)
38-
flow.user_agent = APPLICATION_NAME
39-
# This attempts to open an authorization page in the default web browser, and asks the user
40-
# to grant the bot access to their data. If the user grants permission, the run_flow()
41-
# function returns new credentials.
42-
credentials = tools.run_flow(flow, store, flags)
52+
if os.path.exists(credential_path):
53+
credentials = Credentials.from_authorized_user_file(credential_path, SCOPES)
54+
if not credentials or not credentials.valid:
55+
if credentials and credentials.expired and credentials.refresh_token:
56+
credentials.refresh(Request())
57+
else:
58+
flow = InstalledAppFlow.from_client_secrets_file(
59+
os.path.join(HOME_DIR, CLIENT_SECRET_FILE), SCOPES
60+
)
61+
if not flags.noauth_local_webserver:
62+
credentials = flow.run_local_server(
63+
host=flags.auth_host_name, port=flags.auth_host_port[0]
64+
)
65+
# This attempts to open an authorization page in the default web browser, and asks the user
66+
# to grant the bot access to their data. If the user grants permission, the run_flow()
67+
# function returns new credentials.
68+
else:
69+
auth_url, _ = flow.authorization_url(prompt="consent")
70+
print(
71+
"Proceed to the following link in your browser:",
72+
auth_url,
73+
)
74+
auth_code = input("Enter the authorization code: ")
75+
credentials = flow.fetch_token(code=auth_code)
76+
with open(credential_path, "w") as token:
77+
token.write(credentials.to_json())
4378
print("Storing credentials to " + credential_path)
79+
return credentials
4480

4581

4682
get_credentials()

zulip/integrations/google/google-calendar

+11-16
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,18 @@ import time
1212
from typing import List, Optional, Set, Tuple
1313

1414
import dateutil.parser
15-
import httplib2
1615
import pytz
17-
from oauth2client import client
18-
from oauth2client.file import Storage
1916

2017
try:
21-
from googleapiclient import discovery
18+
from google.oauth2.credentials import Credentials # type: ignore[import-not-found]
19+
from googleapiclient.discovery import build
2220
except ImportError:
23-
logging.exception("Install google-api-python-client")
21+
logging.exception("Install google-api-python-client and google-auth-oauthlib")
2422
sys.exit(1)
25-
2623
sys.path.append(os.path.join(os.path.dirname(__file__), "../../"))
2724
import zulip
2825

29-
SCOPES = "https://www.googleapis.com/auth/calendar.readonly"
26+
SCOPES = ["https://www.googleapis.com/auth/calendar.readonly"]
3027
CLIENT_SECRET_FILE = "client_secret.json" # noqa: S105
3128
APPLICATION_NAME = "Zulip"
3229
HOME_DIR = os.path.expanduser("~")
@@ -88,7 +85,7 @@ if not options.zulip_email:
8885
zulip_client = zulip.init_from_options(options)
8986

9087

91-
def get_credentials() -> client.Credentials:
88+
def get_credentials() -> Credentials:
9289
"""Gets valid user credentials from storage.
9390
9491
If nothing has been stored, or if the stored credentials are invalid,
@@ -100,22 +97,20 @@ def get_credentials() -> client.Credentials:
10097
"""
10198
try:
10299
credential_path = os.path.join(HOME_DIR, "google-credentials.json")
103-
104-
store = Storage(credential_path)
105-
return store.get()
106-
except client.Error:
100+
credentials = Credentials.from_authorized_user_file(credential_path, SCOPES)
101+
except ValueError:
107102
logging.exception("Error while trying to open the `google-credentials.json` file.")
108103
sys.exit(1)
109104
except OSError:
110105
logging.error("Run the get-google-credentials script from this directory first.")
111106
sys.exit(1)
107+
else:
108+
return credentials
112109

113110

114111
def populate_events() -> Optional[None]:
115-
credentials = get_credentials()
116-
creds = credentials.authorize(httplib2.Http())
117-
service = discovery.build("calendar", "v3", http=creds)
118-
112+
creds = get_credentials()
113+
service = build("calendar", "v3", credentials=creds)
119114
now = datetime.datetime.now(pytz.utc).isoformat()
120115
feed = (
121116
service.events()
+3-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
httplib2>=0.22.0
2-
oauth2client>=4.1.3
1+
google-api-python-client>=2.157.0
2+
google-auth-httplib2>=0.2.0
3+
google-auth-oauthlib>=1.2.1

0 commit comments

Comments
 (0)