Merge pull request #31772 from gavindsouza/refactor_google-calendar

refactor: Google Calendar
This commit is contained in:
gavin 2025-03-19 16:23:23 +01:00 committed by GitHub
commit 9a654347df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 235 additions and 199 deletions

View file

@ -20,6 +20,7 @@ from frappe.utils import (
date_diff,
format_datetime,
get_datetime_str,
get_fullname,
getdate,
month_diff,
now_datetime,
@ -38,6 +39,11 @@ communication_mapping = {
"Other": "Other",
}
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.core.doctype.communication.communication import Communication
class Event(Document):
# begin: auto-generated types
@ -107,42 +113,49 @@ class Event(Document):
def on_trash(self):
communications = frappe.get_all(
"Communication", dict(reference_doctype=self.doctype, reference_name=self.name)
"Communication",
filters={"reference_doctype": self.doctype, "reference_name": self.name},
pluck="name",
)
if communications:
for communication in communications:
frappe.delete_doc_if_exists("Communication", communication.name, force=True)
for communication in communications:
frappe.delete_doc("Communication", communication, force=True)
def sync_communication(self):
if self.event_participants:
for participant in self.event_participants:
filters = [
if not self.event_participants:
return
for participant in self.event_participants:
if communications := frappe.get_all(
"Communication",
filters=[
["Communication", "reference_doctype", "=", self.doctype],
["Communication", "reference_name", "=", self.name],
["Communication Link", "link_doctype", "=", participant.reference_doctype],
["Communication Link", "link_name", "=", participant.reference_docname],
]
if comms := frappe.get_all("Communication", filters=filters, fields=["name"], distinct=True):
for comm in comms:
communication = frappe.get_doc("Communication", comm.name)
self.update_communication(participant, communication)
else:
meta = frappe.get_meta(participant.reference_doctype)
if hasattr(meta, "allow_events_in_timeline") and meta.allow_events_in_timeline == 1:
self.create_communication(participant)
],
pluck="name",
distinct=True,
):
for comm in communications:
communication = frappe.get_doc("Communication", comm)
self.update_communication(participant, communication)
else:
meta = frappe.get_meta(participant.reference_doctype)
if hasattr(meta, "allow_events_in_timeline") and meta.allow_events_in_timeline == 1:
self.create_communication(participant)
def create_communication(self, participant):
def create_communication(self, participant: "EventParticipants"):
communication = frappe.new_doc("Communication")
self.update_communication(participant, communication)
self.communication = communication.name
def update_communication(self, participant, communication):
def update_communication(self, participant: "EventParticipants", communication: "Communication"):
communication.communication_medium = "Event"
communication.subject = self.subject
communication.content = self.description if self.description else self.subject
communication.communication_date = self.starts_on
communication.sender = self.owner
communication.sender_full_name = frappe.utils.get_fullname(self.owner)
communication.sender_full_name = get_fullname(self.owner)
communication.reference_doctype = self.doctype
communication.reference_name = self.name
communication.communication_medium = (
@ -195,28 +208,24 @@ class Event(Document):
@frappe.whitelist()
def delete_communication(event, reference_doctype, reference_docname):
deleted_participant = frappe.get_doc(reference_doctype, reference_docname)
if isinstance(event, str):
event = json.loads(event)
filters = [
["Communication", "reference_doctype", "=", event.get("doctype")],
["Communication", "reference_name", "=", event.get("name")],
["Communication Link", "link_doctype", "=", deleted_participant.reference_doctype],
["Communication Link", "link_name", "=", deleted_participant.reference_docname],
]
deleted_participant = frappe.get_doc(reference_doctype, reference_docname)
comms = frappe.get_list("Communication", filters=filters, fields=["name"])
comms = frappe.get_list(
"Communication",
filters=[
["Communication", "reference_doctype", "=", event.get("doctype")],
["Communication", "reference_name", "=", event.get("name")],
["Communication Link", "link_doctype", "=", deleted_participant.reference_doctype],
["Communication Link", "link_name", "=", deleted_participant.reference_docname],
],
pluck="name",
)
if comms:
deletion = []
for comm in comms:
delete = frappe.get_doc("Communication", comm.name).delete()
deletion.append(delete)
return deletion
return {}
for comm in comms:
frappe.delete_doc("Communication", comm)
def get_permission_query_conditions(user):

View file

@ -231,13 +231,13 @@ scheduler_events = {
"all": [
"frappe.email.queue.flush",
"frappe.monitor.flush",
"frappe.integrations.doctype.google_calendar.google_calendar.sync",
],
"hourly": [
"frappe.model.utils.link_count.update_link_count",
"frappe.model.utils.user_settings.sync_user_settings",
"frappe.desk.page.backups.backups.delete_downloadable_backups",
"frappe.desk.form.document_follow.send_hourly_updates",
"frappe.integrations.doctype.google_calendar.google_calendar.sync",
"frappe.email.doctype.newsletter.newsletter.send_scheduled_email",
"frappe.website.doctype.personal_data_deletion_request.personal_data_deletion_request.process_data_deletion_request",
],

View file

@ -2,8 +2,10 @@
# License: MIT. See LICENSE
from datetime import datetime, timedelta
from urllib.parse import quote
from contextlib import suppress
from datetime import date, datetime, timedelta
from math import ceil
from typing import TYPE_CHECKING, TypedDict
from zoneinfo import ZoneInfo
import google.oauth2.credentials
@ -13,7 +15,7 @@ from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
import frappe
from frappe import _
from frappe import _, _lt
from frappe.integrations.google_oauth import GoogleOAuth
from frappe.model.document import Document
from frappe.utils import (
@ -27,6 +29,16 @@ from frappe.utils import (
)
from frappe.utils.password import set_encrypted_password
if TYPE_CHECKING:
from frappe.desk.doctype.event.event import Event
class RecurrenceParameters(TypedDict):
frequency: str | None
until: datetime | None
byday: list[str]
SCOPES = "https://www.googleapis.com/auth/calendar"
google_calendar_frequencies = {
@ -64,6 +76,9 @@ framework_days = {
}
allow_google_calendar_label = _lt("Allow Google Calendar Access")
class GoogleCalendar(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
@ -86,7 +101,7 @@ class GoogleCalendar(Document):
# end: auto-generated types
def validate(self):
google_settings = frappe.get_single("Google Settings")
google_settings = frappe.get_cached_doc("Google Settings")
if not google_settings.enable:
frappe.throw(_("Enable Google API in Google Settings."))
@ -99,8 +114,9 @@ class GoogleCalendar(Document):
google_settings = self.validate()
if not self.refresh_token:
button_label = frappe.bold(_("Allow Google Calendar Access"))
raise frappe.ValidationError(_("Click on {0} to generate Refresh Token.").format(button_label))
raise frappe.ValidationError(
_("Click on {0} to generate Refresh Token.").format(frappe.bold(allow_google_calendar_label))
)
data = {
"client_id": google_settings.client_id,
@ -113,67 +129,64 @@ class GoogleCalendar(Document):
try:
r = requests.post(GoogleOAuth.OAUTH_URL, data=data).json()
except requests.exceptions.HTTPError:
button_label = frappe.bold(_("Allow Google Calendar Access"))
frappe.throw(
_(
"Something went wrong during the token generation. Click on {0} to generate a new one."
).format(button_label)
).format(frappe.bold(allow_google_calendar_label))
)
return r.get("access_token")
@frappe.whitelist()
def authorize_access(g_calendar, reauthorize=None):
def authorize_access(g_calendar: str, reauthorize: bool = False):
"""
If no Authorization code get it from Google and then request for Refresh Token.
Google Calendar Name is set to flags to set_value after Authorization Code is obtained.
"""
google_settings = frappe.get_doc("Google Settings")
google_calendar = frappe.get_doc("Google Calendar", g_calendar)
google_calendar.check_permission("write")
google_settings = frappe.get_cached_doc("Google Settings")
redirect_uri = (
get_request_site_address(True)
+ "?cmd=frappe.integrations.doctype.google_calendar.google_calendar.google_callback"
f"{get_request_site_address(full_address=True)}"
f"?cmd={google_callback.__module__}.{google_callback.__qualname__}"
)
if not google_calendar.authorization_code or reauthorize:
frappe.cache.hset("google_calendar", "google_calendar", google_calendar.name)
return get_authentication_url(client_id=google_settings.client_id, redirect_uri=redirect_uri)
else:
try:
data = {
"code": google_calendar.get_password(fieldname="authorization_code", raise_exception=False),
"client_id": google_settings.client_id,
"client_secret": google_settings.get_password(
fieldname="client_secret", raise_exception=False
),
"redirect_uri": redirect_uri,
"grant_type": "authorization_code",
}
r = requests.post(GoogleOAuth.OAUTH_URL, data=data).json()
if "refresh_token" in r:
frappe.db.set_value(
"Google Calendar", google_calendar.name, "refresh_token", r.get("refresh_token")
)
frappe.db.commit()
data = {
"code": google_calendar.get_password(fieldname="authorization_code", raise_exception=False),
"client_id": google_settings.client_id,
"client_secret": google_settings.get_password(fieldname="client_secret", raise_exception=False),
"redirect_uri": redirect_uri,
"grant_type": "authorization_code",
}
frappe.local.response["type"] = "redirect"
frappe.local.response["location"] = "/app/Form/{}/{}".format(
quote("Google Calendar"), quote(google_calendar.name)
)
try:
r = requests.post(GoogleOAuth.OAUTH_URL, data=data).json()
except Exception as e:
frappe.throw(e)
frappe.msgprint(_("Google Calendar has been configured."))
except Exception as e:
frappe.throw(e)
if "refresh_token" in r:
frappe.db.set_value("Google Calendar", google_calendar.name, "refresh_token", r["refresh_token"])
frappe.db.commit()
frappe.local.response["type"] = "redirect"
frappe.local.response["location"] = google_calendar.get_url()
frappe.msgprint(_("Google Calendar has been configured."), indicator="green")
def get_authentication_url(client_id=None, redirect_uri=None):
return {
"url": "https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&response_type=code&prompt=consent&client_id={}&include_granted_scopes=true&scope={}&redirect_uri={}".format(
client_id, SCOPES, redirect_uri
"url": (
"https://accounts.google.com/o/oauth2/v2/auth?"
f"access_type=offline&response_type=code&prompt=consent&client_id={client_id}"
f"&include_granted_scopes=true&scope={SCOPES}&redirect_uri={redirect_uri}"
)
}
@ -191,69 +204,71 @@ def google_callback(code=None):
@frappe.whitelist()
def sync(g_calendar=None):
filters = {"enable": 1}
def sync(g_calendar: str | None = None):
filters = {"enable": 1, "pull_from_google_calendar": 1}
user_messages = []
if g_calendar:
filters.update({"name": g_calendar})
google_calendars = frappe.get_list("Google Calendar", filters=filters)
for g in frappe.get_list("Google Calendar", filters=filters, pluck="name"):
user_messages.append(sync_events_from_google_calendar(g))
for g in google_calendars:
return sync_events_from_google_calendar(g.name)
return user_messages
def get_google_calendar_object(g_calendar):
"""Return an object of Google Calendar along with Google Calendar doc."""
google_settings = frappe.get_doc("Google Settings")
account = frappe.get_doc("Google Calendar", g_calendar)
google_settings = frappe.get_cached_doc("Google Settings")
account: GoogleCalendar = frappe.get_doc("Google Calendar", g_calendar)
credentials_dict = {
"token": account.get_access_token(),
"refresh_token": account.get_password(fieldname="refresh_token", raise_exception=False),
"token_uri": GoogleOAuth.OAUTH_URL,
"client_id": google_settings.client_id,
"client_secret": google_settings.get_password(fieldname="client_secret", raise_exception=False),
"scopes": [SCOPES],
}
credentials = google.oauth2.credentials.Credentials(**credentials_dict)
credentials = google.oauth2.credentials.Credentials(
token=account.get_access_token(),
refresh_token=account.get_password(fieldname="refresh_token", raise_exception=False),
token_uri=GoogleOAuth.OAUTH_URL,
client_id=google_settings.client_id,
client_secret=google_settings.get_password(fieldname="client_secret", raise_exception=False),
scopes=[SCOPES],
)
google_calendar = build(
serviceName="calendar", version="v3", credentials=credentials, static_discovery=False
)
check_google_calendar(account, google_calendar)
check_google_calendar(account.reload(), google_calendar)
account.load_from_db()
return google_calendar, account
return google_calendar, account.reload()
def check_google_calendar(account, google_calendar):
def check_google_calendar(account: GoogleCalendar, google_calendar):
"""
Checks if Google Calendar is present with the specified name.
If not, creates one.
"""
account.load_from_db()
try:
if account.google_calendar_id:
google_calendar.calendars().get(calendarId=account.google_calendar_id).execute()
else:
# If no Calendar ID create a new Calendar
calendar = {
"summary": account.calendar_name,
"timeZone": frappe.get_system_settings("time_zone"),
}
created_calendar = google_calendar.calendars().insert(body=calendar).execute()
frappe.db.set_value(
"Google Calendar", account.name, "google_calendar_id", created_calendar.get("id")
if account.google_calendar_id:
try:
return google_calendar.calendars().get(calendarId=account.google_calendar_id).execute()
except HttpError as err:
frappe.throw(
_("Google Calendar - Could not find Calendar for {0}, error code {1}.").format(
account.name, err.resp.status
)
)
frappe.db.commit()
# If no Calendar ID create a new Calendar
calendar = {
"summary": account.calendar_name,
"timeZone": frappe.get_system_settings("time_zone"),
}
try:
created_calendar = google_calendar.calendars().insert(body=calendar).execute()
except HttpError as err:
frappe.throw(
_("Google Calendar - Could not create Calendar for {0}, error code {1}.").format(
account.name, err.resp.status
)
)
account.db_set("google_calendar_id", created_calendar.get("id"))
frappe.db.commit()
def sync_events_from_google_calendar(g_calendar, method=None):
@ -308,30 +323,33 @@ def sync_events_from_google_calendar(g_calendar, method=None):
for idx, event in enumerate(results):
frappe.publish_realtime(
"import_google_calendar", dict(progress=idx + 1, total=len(results)), user=frappe.session.user
"import_google_calendar", {"progress": idx + 1, "total": len(results)}, user=frappe.session.user
)
# If Google Calendar Event if confirmed, then create an Event
if event.get("status") == "confirmed":
recurrence = None
if event.get("recurrence"):
try:
with suppress(IndexError):
recurrence = event.get("recurrence")[0]
except IndexError:
pass
if not frappe.db.exists("Event", {"google_calendar_event_id": event.get("id")}):
insert_event_to_calendar(account, event, recurrence)
else:
update_event_in_calendar(account, event, recurrence)
# If any synced Google Calendar Event is cancelled, then close the Event
elif event.get("status") == "cancelled":
# If any synced Google Calendar Event is cancelled, then close the Event
frappe.db.set_value(
event_name = frappe.db.get_value(
"Event",
{
"google_calendar_id": account.google_calendar_id,
"google_calendar_event_id": event.get("id"),
},
)
frappe.db.set_value(
"Event",
event_name,
"status",
"Closed",
)
@ -340,19 +358,10 @@ def sync_events_from_google_calendar(g_calendar, method=None):
"doctype": "Comment",
"comment_type": "Info",
"reference_doctype": "Event",
"reference_name": frappe.db.get_value(
"Event",
{
"google_calendar_id": account.google_calendar_id,
"google_calendar_event_id": event.get("id"),
},
"name",
),
"reference_name": event_name,
"content": " - Event deleted from Google Calendar.",
}
).insert(ignore_permissions=True)
else:
pass
if not results:
return _("No Google Calendar Event to sync.")
@ -368,7 +377,7 @@ def insert_event_to_calendar(account, event, recurrence=None):
"""
calendar_event = {
"doctype": "Event",
"subject": event.get("summary"),
"subject": event.get("summary") or "No Title",
"description": event.get("description"),
"google_calendar_event": 1,
"google_calendar": account.name,
@ -376,13 +385,36 @@ def insert_event_to_calendar(account, event, recurrence=None):
"google_calendar_event_id": event.get("id"),
"google_meet_link": event.get("hangoutLink"),
"pulled_from_google_calendar": 1,
"owner": account.owner,
"event_type": "Public" if account.sync_as_public else "Private",
}
calendar_event.update(
google_calendar_to_repeat_on(recurrence=recurrence, start=event.get("start"), end=event.get("end"))
} | google_calendar_to_repeat_on(recurrence=recurrence, start=event.get("start"), end=event.get("end"))
e: Event = frappe.get_doc(calendar_event)
update_participants_in_event(calendar_event=e, google_event=event)
e.insert(ignore_permissions=True)
e.db_set("owner", account.user, update_modified=False)
def update_participants_in_event(calendar_event: "Event", google_event: dict):
google_event_participants = [
attendee["email"] for attendee in google_event.get("attendees", []) if not attendee.get("self")
]
in_system_participants = frappe.get_all(
"User", filters={"email": ("in", google_event_participants)}, pluck="email"
)
frappe.get_doc(calendar_event).insert(ignore_permissions=True)
existing_calendar_participants = [
participant.reference_docname
for participant in calendar_event.event_participants
if participant.reference_doctype == "User"
]
for participant in in_system_participants:
if participant not in existing_calendar_participants:
calendar_event.add_participant("User", participant)
# Add a Guest user to indicate participants not in the system
if len(in_system_participants) < len(google_event_participants):
calendar_event.add_participant("User", "Guest")
def update_event_in_calendar(account, event, recurrence=None):
@ -396,6 +428,7 @@ def update_event_in_calendar(account, event, recurrence=None):
calendar_event.update(
google_calendar_to_repeat_on(recurrence=recurrence, start=event.get("start"), end=event.get("end"))
)
update_participants_in_event(calendar_event, event)
calendar_event.save(ignore_permissions=True)
@ -550,13 +583,10 @@ def delete_event_from_google_calendar(doc, method=None):
Delete Events from Google Calendar if Frappe Event is deleted.
"""
if not frappe.db.exists("Google Calendar", {"name": doc.google_calendar}):
if not frappe.db.exists("Google Calendar", {"name": doc.google_calendar, "push_to_google_calendar": 1}):
return
google_calendar, account = get_google_calendar_object(doc.google_calendar)
if not account.push_to_google_calendar:
return
google_calendar, _ = get_google_calendar_object(doc.google_calendar)
try:
event = (
@ -578,28 +608,23 @@ def delete_event_from_google_calendar(doc, method=None):
)
def google_calendar_to_repeat_on(start, end, recurrence=None):
def parse_google_calendar_date(dt):
if dt.get("date"):
return get_datetime(dt.get("date"))
return parser.parse(dt.get("dateTime")).astimezone(ZoneInfo(get_system_timezone())).replace(tzinfo=None)
def google_calendar_to_repeat_on(*, start, end, recurrence=None):
"""
recurrence is in the form ['RRULE:FREQ=WEEKLY;BYDAY=MO,TU,TH']
has the frequency and then the days on which the event recurs
Both have been mapped in a dict for easier mapping.
"""
repeat_on = {
"starts_on": (
get_datetime(start.get("date"))
if start.get("date")
else parser.parse(start.get("dateTime"))
.astimezone(ZoneInfo(get_system_timezone()))
.replace(tzinfo=None)
),
"ends_on": (
get_datetime(end.get("date"))
if end.get("date")
else parser.parse(end.get("dateTime"))
.astimezone(ZoneInfo(get_system_timezone()))
.replace(tzinfo=None)
),
"starts_on": parse_google_calendar_date(start),
"ends_on": parse_google_calendar_date(end),
"all_day": 1 if start.get("date") else 0,
"repeat_this_event": 1 if recurrence else 0,
"repeat_on": None,
@ -614,44 +639,45 @@ def google_calendar_to_repeat_on(start, end, recurrence=None):
}
# recurrence rule "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,TH"
if recurrence:
# google_calendar_frequency = RRULE:FREQ=WEEKLY, byday = BYDAY=MO,TU,TH, until = 20191028
google_calendar_frequency, until, byday = get_recurrence_parameters(recurrence)
repeat_on["repeat_on"] = google_calendar_frequencies.get(google_calendar_frequency)
if not recurrence:
return repeat_on
if repeat_on["repeat_on"] == "Daily":
repeat_on["ends_on"] = None
repeat_on["repeat_till"] = datetime.strptime(until, "%Y%m%d") if until else None
# google_calendar_frequency = RRULE:FREQ=WEEKLY, byday = BYDAY=MO,TU,TH, until = 20191028
google_calendar_frequency, until, byday = get_recurrence_parameters(recurrence)
repeat_on["repeat_on"] = google_calendar_frequencies.get(google_calendar_frequency)
if byday and repeat_on["repeat_on"] == "Weekly":
repeat_on["repeat_till"] = datetime.strptime(until, "%Y%m%d") if until else None
byday = byday.split("=")[1].split(",")
for repeat_day in byday:
repeat_on[google_calendar_days[repeat_day]] = 1
if repeat_on["repeat_on"] == "Daily":
repeat_on["ends_on"] = None
repeat_on["repeat_till"] = until
if byday and repeat_on["repeat_on"] == "Monthly":
byday = byday.split("=")[1]
repeat_day_week_number, repeat_day_name = None, None
if byday and repeat_on["repeat_on"] == "Weekly":
repeat_on["repeat_till"] = until
for repeat_day in byday:
repeat_on[google_calendar_days[repeat_day]] = 1
for num in ["-2", "-1", "1", "2", "3", "4", "5"]:
if num in byday:
repeat_day_week_number = num
break
if byday and repeat_on["repeat_on"] == "Monthly":
byday = byday.split("=")[1]
repeat_day_week_number, repeat_day_name = None, None
for day in ["MO", "TU", "WE", "TH", "FR", "SA", "SU"]:
if day in byday:
repeat_day_name = google_calendar_days.get(day)
break
for num in ["-2", "-1", "1", "2", "3", "4", "5"]:
if num in byday:
repeat_day_week_number = num
break
# Only Set starts_on for the event to repeat monthly
start_date = parse_google_calendar_recurrence_rule(int(repeat_day_week_number), repeat_day_name)
repeat_on["starts_on"] = start_date
repeat_on["ends_on"] = add_to_date(start_date, minutes=5)
repeat_on["repeat_till"] = datetime.strptime(until, "%Y%m%d") if until else None
for day in ["MO", "TU", "WE", "TH", "FR", "SA", "SU"]:
if day in byday:
repeat_day_name = google_calendar_days.get(day)
break
if repeat_on["repeat_till"] == "Yearly":
repeat_on["ends_on"] = None
repeat_on["repeat_till"] = datetime.strptime(until, "%Y%m%d") if until else None
# Only Set starts_on for the event to repeat monthly
start_date = parse_google_calendar_recurrence_rule(int(repeat_day_week_number), repeat_day_name)
repeat_on["starts_on"] = start_date
repeat_on["ends_on"] = add_to_date(start_date, minutes=5)
repeat_on["repeat_till"] = until
if repeat_on["repeat_till"] == "Yearly":
repeat_on["ends_on"] = None
repeat_on["repeat_till"] = until
return repeat_on
@ -725,13 +751,11 @@ def repeat_on_to_google_calendar_recurrence_rule(doc):
return [recurrence]
def get_week_number(dt):
def get_week_number(dt: date):
"""Return the week number of the month for the specified date.
https://stackoverflow.com/questions/3806473/python-week-number-of-the-month/16804556
"""
from math import ceil
first_day = dt.replace(day=1)
dom = dt.day
@ -740,19 +764,21 @@ def get_week_number(dt):
return int(ceil(adjusted_dom / 7.0))
def get_recurrence_parameters(recurrence):
def get_recurrence_parameters(recurrence: str) -> RecurrenceParameters:
recurrence = recurrence.split(";")
frequency, until, byday = None, None, None
frequency, until, byday = None, None, []
for r in recurrence:
if "RRULE:FREQ" in r:
frequency = r
elif "UNTIL" in r:
until = r
elif "BYDAY" in r:
byday = r
else:
pass
for token in recurrence:
if "RRULE:FREQ" in token:
frequency = token
elif "UNTIL" in token:
_until = token.replace("UNTIL=", "").rstrip("Z")
fmt = "%Y%m%dT%H%M%S" if "T" in _until else "%Y%m%d"
until = datetime.strptime(_until, fmt)
elif "BYDAY" in token:
byday = token.split("=", 1)[1].split(",")
return frequency, until, byday

View file

@ -28,7 +28,8 @@ class GoogleSettings(Document):
@frappe.whitelist()
def get_file_picker_settings():
"""Return all the data FileUploader needs to start the Google Drive Picker."""
google_settings = frappe.get_single("Google Settings")
google_settings = frappe.get_cached_doc("Google Settings")
if not (google_settings.enable and google_settings.google_drive_picker_enabled):
return {}

View file

@ -125,7 +125,7 @@ class WebsiteSettings(Document):
)
def validate_google_settings(self):
if self.enable_google_indexing and not frappe.db.get_single_value("Google Settings", "enable"):
if self.enable_google_indexing and not frappe.get_cached_value("Google Settings", None, "enable"):
frappe.throw(_("Enable Google API in Google Settings."))
def validate_redirects(self):