Skip to content

Commit 8523ee5

Browse files
authored
feat: Add Forms Publishing related samples (#2176)
1 parent e4745e4 commit 8523ee5

8 files changed

+822
-0
lines changed

forms/snippets/add_responder.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START forms_add_responder]
16+
17+
import os.path
18+
19+
from google.auth.transport.requests import Request
20+
from google.oauth2.credentials import Credentials
21+
from google_auth_oauthlib.flow import InstalledAppFlow
22+
from googleapiclient.discovery import build
23+
24+
25+
# If modifying these SCOPES, delete the file token.json.
26+
SCOPES = ["https://www.googleapis.com/auth/drive.file"]
27+
CLIENT_SECRET_FILE = "client_secrets.json"
28+
TOKEN_FILE = "token.json"
29+
30+
# TODO: Replace with your Form ID and responder's email
31+
YOUR_FORM_ID = "YOUR_FORM_ID"
32+
YOUR_RESPONDER_EMAIL = "[email protected]"
33+
34+
35+
def get_credentials():
36+
"""Gets the credentials for the user."""
37+
creds = None
38+
if os.path.exists(TOKEN_FILE):
39+
creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
40+
if not creds or not creds.valid:
41+
if creds and creds.expired and creds.refresh_token:
42+
creds.refresh(Request())
43+
else:
44+
flow = InstalledAppFlow.from_client_secrets_file(
45+
CLIENT_SECRET_FILE, SCOPES
46+
)
47+
creds = flow.run_local_server(port=8080)
48+
with open(TOKEN_FILE, "w") as token:
49+
token.write(creds.to_json())
50+
return creds
51+
52+
53+
def add_responder():
54+
"""Adds the responder to the form."""
55+
creds = get_credentials()
56+
drive_service = build("drive", "v3", credentials=creds)
57+
58+
permission_body = {
59+
"view": "published",
60+
"role": "reader",
61+
"type": "user",
62+
"emailAddress": YOUR_RESPONDER_EMAIL,
63+
}
64+
65+
try:
66+
response = (
67+
drive_service.permissions()
68+
.create(
69+
fileId=YOUR_FORM_ID,
70+
body=permission_body,
71+
sendNotificationEmail=False, # Optional: to avoid sending an email
72+
)
73+
.execute()
74+
)
75+
print(
76+
f"Added responder {YOUR_RESPONDER_EMAIL}. Permission ID:"
77+
f" {response.get('id')}"
78+
)
79+
print(response)
80+
except Exception as e:
81+
print(f"An error occurred: {e}")
82+
83+
84+
if __name__ == "__main__":
85+
add_responder()
86+
# [end forms_add_responder]
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
import os.path
17+
18+
from google.auth.transport.requests import Request
19+
from google.oauth2.credentials import Credentials
20+
from google_auth_oauthlib.flow import InstalledAppFlow
21+
from googleapiclient.discovery import build
22+
23+
24+
# If modifying these SCOPES, delete the file token.json.
25+
SCOPES = ["https://www.googleapis.com/auth/drive.file"]
26+
CLIENT_SECRET_FILE = "client_secrets.json"
27+
TOKEN_FILE = "token.json"
28+
29+
# TODO: Replace with your Form ID and responder's email
30+
YOUR_FORM_ID = "YOUR_FORM_ID"
31+
32+
33+
def get_credentials():
34+
"""Gets the credentials for the user."""
35+
creds = None
36+
if os.path.exists(TOKEN_FILE):
37+
creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
38+
if not creds or not creds.valid:
39+
if creds and creds.expired and creds.refresh_token:
40+
creds.refresh(Request())
41+
else:
42+
flow = InstalledAppFlow.from_client_secrets_file(
43+
CLIENT_SECRET_FILE, SCOPES
44+
)
45+
creds = flow.run_local_server(port=8080)
46+
with open(TOKEN_FILE, "w") as token:
47+
token.write(creds.to_json())
48+
return creds
49+
50+
51+
# [START forms_is_anyone_with_link_responder]
52+
def is_anyone_with_link_responder():
53+
"""Checks if anyone with the link is a responder for the form."""
54+
creds = get_credentials()
55+
drive_service = build("drive", "v3", credentials=creds)
56+
anyone_with_link_responder = False
57+
58+
try:
59+
permissions_result = (
60+
drive_service.permissions()
61+
.list(
62+
fileId=YOUR_FORM_ID,
63+
fields="permissions(id,type,role,view)",
64+
includePermissionsForView="published",
65+
)
66+
.execute()
67+
)
68+
69+
permissions = permissions_result.get("permissions", [])
70+
if not permissions:
71+
print(f"No permissions found for form ID: {YOUR_FORM_ID}")
72+
else:
73+
for permission in permissions:
74+
if (
75+
permission.get("type") == "anyone"
76+
and permission.get("view") == "published"
77+
and permission.get("role") == "reader"
78+
):
79+
anyone_with_link_responder = True
80+
break
81+
82+
if anyone_with_link_responder:
83+
print(
84+
f"Form '{YOUR_FORM_ID}' IS configured for 'Anyone with the link' to"
85+
" respond."
86+
)
87+
else:
88+
print(
89+
f"Form '{YOUR_FORM_ID}' is NOT configured for 'Anyone with the link'"
90+
" to respond."
91+
)
92+
93+
except Exception as e:
94+
print(f"An error occurred: {e}")
95+
return anyone_with_link_responder
96+
97+
98+
# [end forms_is_anyone_with_link_responder]
99+
100+
101+
# [START forms_set_anyone_with_link_responder]
102+
def set_anyone_with_link_responder():
103+
"""Sets anyone with the link to be a responder for the form."""
104+
creds = get_credentials()
105+
drive_service = build("drive", "v3", credentials=creds)
106+
107+
permission_body = {
108+
"type": "anyone",
109+
"view": "published", # Key for making it a responder setting
110+
"role": "reader",
111+
}
112+
113+
try:
114+
response = (
115+
drive_service.permissions()
116+
.create(
117+
fileId=YOUR_FORM_ID,
118+
body=permission_body,
119+
)
120+
.execute()
121+
)
122+
print(
123+
"'Anyone with the link can respond' permission set for form"
124+
f" {YOUR_FORM_ID}: {response}"
125+
)
126+
return True
127+
except Exception as e:
128+
print(f"An error occurred: {e}")
129+
return False
130+
131+
132+
# [end forms_set_anyone_with_link_responder]
133+
134+
135+
# [START forms_remove_anyone_with_link_responder]
136+
def remove_anyone_with_link_responder():
137+
"""Removes anyone with the link as a responder for the form."""
138+
creds = get_credentials()
139+
drive_service = build("drive", "v3", credentials=creds)
140+
141+
permission_id_to_delete = None
142+
143+
try:
144+
permissions_result = (
145+
drive_service.permissions()
146+
.list(
147+
fileId=YOUR_FORM_ID,
148+
fields="permissions(id,type,role,view)",
149+
includePermissionsForView="published",
150+
)
151+
.execute()
152+
)
153+
154+
permissions = permissions_result.get("permissions", [])
155+
for permission in permissions:
156+
if (
157+
permission.get("type") == "anyone"
158+
and permission.get("role") == "reader"
159+
and permission.get("view") == "published"
160+
):
161+
permission_id_to_delete = permission.get("id")
162+
break
163+
164+
if permission_id_to_delete:
165+
drive_service.permissions().delete(
166+
fileId=YOUR_FORM_ID, permissionId=permission_id_to_delete
167+
).execute()
168+
print(
169+
"Successfully removed 'Anyone with the link' permission (ID:"
170+
f" {permission_id_to_delete}) from form {YOUR_FORM_ID}."
171+
)
172+
return True
173+
else:
174+
print(
175+
"'Anyone with the link can respond' permission not found for form"
176+
f" {YOUR_FORM_ID}."
177+
)
178+
179+
except Exception as e:
180+
print(f"An error occurred: {e}")
181+
return False
182+
183+
184+
# [end forms_remove_anyone_with_link_responder]
185+
186+
if __name__ == "__main__":
187+
is_anyone_with_link_responder()

forms/snippets/get_responders.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START forms_get_responders]
16+
17+
import os.path
18+
19+
from google.auth.transport.requests import Request
20+
from google.oauth2.credentials import Credentials
21+
from google_auth_oauthlib.flow import InstalledAppFlow
22+
from googleapiclient.discovery import build
23+
24+
25+
# If modifying these SCOPES, delete the file token.json.
26+
SCOPES = ["https://www.googleapis.com/auth/drive.metadata.readonly"]
27+
CLIENT_SECRET_FILE = "client_secrets.json"
28+
TOKEN_FILE = "token.json"
29+
30+
# TODO: Replace with your Form ID
31+
YOUR_FORM_ID = "YOUR_FORM_ID"
32+
33+
34+
def get_credentials():
35+
"""Gets the credentials for the user."""
36+
creds = None
37+
if os.path.exists(TOKEN_FILE):
38+
creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
39+
if not creds or not creds.valid:
40+
if creds and creds.expired and creds.refresh_token:
41+
creds.refresh(Request())
42+
else:
43+
flow = InstalledAppFlow.from_client_secrets_file(
44+
CLIENT_SECRET_FILE, SCOPES
45+
)
46+
creds = flow.run_local_server(port=8080)
47+
with open(TOKEN_FILE, "w") as token:
48+
token.write(creds.to_json())
49+
return creds
50+
51+
52+
def get_responders():
53+
"""Gets the responders for the form."""
54+
creds = get_credentials()
55+
drive_service = build("drive", "v3", credentials=creds)
56+
57+
try:
58+
response = (
59+
drive_service.permissions()
60+
.list(
61+
fileId=YOUR_FORM_ID,
62+
fields="permissions(id,emailAddress,type,role,view)",
63+
includePermissionsForView="published",
64+
)
65+
.execute()
66+
)
67+
68+
published_readers = []
69+
for permission in response.get("permissions", []):
70+
# 'view': 'published' indicates it's related to the published link.
71+
# 'role': 'reader' is standard for responders.
72+
# 'type': 'user' for specific users, 'anyone' for public.
73+
if (
74+
permission.get("view") == "published"
75+
and permission.get("role") == "reader"
76+
):
77+
published_readers.append(permission)
78+
79+
if published_readers:
80+
print("Responders for this form:")
81+
print(published_readers)
82+
else:
83+
print("No specific published readers found for this form.")
84+
85+
except Exception as e:
86+
print(f"An error occurred: {e}")
87+
88+
89+
if __name__ == "__main__":
90+
get_responders()
91+
# [end forms_get_responders]

0 commit comments

Comments
 (0)