Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit cbdfa80

Browse files
committedJan 16, 2025
api: Exclude None values from request payload in Endpoint class.
Refactored the Endpoint class to exclude parameters with None values from the request payload. This ensures cleaner API interactions and avoids unintended behavior, improving code reliability and aligning with best practices. Fixes zulip#847
1 parent 8c27331 commit cbdfa80

File tree

5 files changed

+73
-44
lines changed

5 files changed

+73
-44
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.*",

‎requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ types-pytz
1717
types-requests
1818
gitlint>=0.13.0
1919
-r ./zulip/integrations/bridge_with_matrix/requirements.txt
20+
-r ./zulip/integrations/google/requirements.txt

‎zulip/integrations/google/get-google-credentials

+39-17
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,32 @@
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
6+
from google.oauth2.credentials import Credentials
7+
from google_auth_oauthlib.flow import InstalledAppFlow
78

8-
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
9+
flags = argparse.ArgumentParser(description="Google Calendar Bot")
10+
flags.add_argument(
11+
"--noauth_local_webserver",
12+
action="store_true",
13+
help="Run OAuth flow in console instead of opening a web browser.",
14+
)
15+
args = flags.parse_args()
916

1017
# If modifying these scopes, delete your previously saved credentials
1118
# at zulip/bots/gcal/
1219
# NOTE: When adding more scopes, add them after the previous one in the same field, with a space
1320
# seperating them.
14-
SCOPES = "https://www.googleapis.com/auth/calendar.readonly"
21+
SCOPES = ["https://www.googleapis.com/auth/calendar.readonly"]
1522
# This file contains the information that google uses to figure out which application is requesting
1623
# this client's data.
1724
CLIENT_SECRET_FILE = "client_secret.json" # noqa: S105
1825
APPLICATION_NAME = "Zulip Calendar Bot"
1926
HOME_DIR = os.path.expanduser("~")
27+
CREDENTIALS_PATH = os.path.join(HOME_DIR, "google-credentials.json")
2028

2129

22-
def get_credentials() -> client.Credentials:
30+
def get_credentials() -> Credentials:
2331
"""Gets valid user credentials from storage.
2432
2533
If nothing has been stored, or if the stored credentials are invalid,
@@ -29,18 +37,32 @@ def get_credentials() -> client.Credentials:
2937
Credentials, the obtained credential.
3038
"""
3139

32-
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)
43-
print("Storing credentials to " + credential_path)
40+
creds = None
41+
42+
# Check if the credentials file exists
43+
if os.path.exists(CREDENTIALS_PATH):
44+
creds = Credentials.from_authorized_user_file(CREDENTIALS_PATH, SCOPES)
45+
46+
# If there are no valid credentials, initiate the OAuth flow
47+
if not creds or not creds.valid:
48+
if creds and creds.expired and creds.refresh_token:
49+
creds.refresh(Request())
50+
else:
51+
flow = InstalledAppFlow.from_client_secrets_file(
52+
os.path.join(HOME_DIR, CLIENT_SECRET_FILE), SCOPES
53+
)
54+
if args.noauth_local_webserver:
55+
creds = flow.run_console()
56+
else:
57+
creds = flow.run_local_server(port=0)
58+
59+
# Save the credentials for future use
60+
with open(CREDENTIALS_PATH, "w") as token_file:
61+
token_file.write(creds.to_json())
62+
63+
print("Storing credentials to " + CREDENTIALS_PATH)
64+
65+
return creds
4466

4567

4668
get_credentials()

‎zulip/integrations/google/google-calendar

+27-25
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,16 @@ 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
19-
20-
try:
21-
from googleapiclient import discovery
22-
except ImportError:
23-
logging.exception("Install google-api-python-client")
24-
sys.exit(1)
16+
from google.auth.transport.requests import Request
17+
from google.oauth2.credentials import Credentials
18+
from google_auth_oauthlib.flow import InstalledAppFlow
19+
from googleapiclient.discovery import build
2520

2621
sys.path.append(os.path.join(os.path.dirname(__file__), "../../"))
2722
import zulip
2823

29-
SCOPES = "https://www.googleapis.com/auth/calendar.readonly"
24+
SCOPES = ["https://www.googleapis.com/auth/calendar.readonly"]
3025
CLIENT_SECRET_FILE = "client_secret.json" # noqa: S105
3126
APPLICATION_NAME = "Zulip"
3227
HOME_DIR = os.path.expanduser("~")
@@ -88,33 +83,40 @@ if not options.zulip_email:
8883
zulip_client = zulip.init_from_options(options)
8984

9085

91-
def get_credentials() -> client.Credentials:
86+
def get_credentials() -> Credentials:
9287
"""Gets valid user credentials from storage.
9388
9489
If nothing has been stored, or if the stored credentials are invalid,
95-
an exception is thrown and the user is informed to run the script in this directory to get
96-
credentials.
90+
the user will be prompted to authenticate.
9791
9892
Returns:
9993
Credentials, the obtained credential.
10094
"""
101-
try:
102-
credential_path = os.path.join(HOME_DIR, "google-credentials.json")
95+
credential_path = os.path.join(HOME_DIR, "google-credentials.json")
96+
creds = None
97+
98+
# Load credentials from file if they exist
99+
if os.path.exists(credential_path):
100+
creds = Credentials.from_authorized_user_file(credential_path, SCOPES)
101+
102+
# If there are no (valid) credentials available, prompt the user to log in.
103+
if not creds or not creds.valid:
104+
if creds and creds.expired and creds.refresh_token:
105+
creds.refresh(Request())
106+
else:
107+
flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRET_FILE, SCOPES)
108+
creds = flow.run_local_server(port=0)
109+
110+
# Save the credentials for the next run
111+
with open(credential_path, "w") as token:
112+
token.write(creds.to_json())
103113

104-
store = Storage(credential_path)
105-
return store.get()
106-
except client.Error:
107-
logging.exception("Error while trying to open the `google-credentials.json` file.")
108-
sys.exit(1)
109-
except OSError:
110-
logging.error("Run the get-google-credentials script from this directory first.")
111-
sys.exit(1)
114+
return creds
112115

113116

114117
def populate_events() -> Optional[None]:
115118
credentials = get_credentials()
116-
creds = credentials.authorize(httplib2.Http())
117-
service = discovery.build("calendar", "v3", http=creds)
119+
service = build("calendar", "v3", credentials=credentials)
118120

119121
now = datetime.datetime.now(pytz.utc).isoformat()
120122
feed = (
+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)
Please sign in to comment.