feat: push contacts to google contacts
This commit is contained in:
parent
0c86588bf4
commit
6de3e9a1bf
4 changed files with 145 additions and 25 deletions
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"_comments": "[]",
|
||||
"allow_events_in_timeline": 1,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
|
|
@ -21,7 +22,14 @@
|
|||
"gender",
|
||||
"phone",
|
||||
"image",
|
||||
"sync_with_google_contacts",
|
||||
"sb_00",
|
||||
"google_contacts",
|
||||
"google_contacts_id",
|
||||
"cb_00",
|
||||
"pulled_from_google_contacts",
|
||||
"google_contacts_description",
|
||||
"sb_01",
|
||||
"email_ids",
|
||||
"phone_nos",
|
||||
"contact_details",
|
||||
|
|
@ -29,10 +37,7 @@
|
|||
"links",
|
||||
"more_info",
|
||||
"department",
|
||||
"unsubscribed",
|
||||
"column_break_17",
|
||||
"pulled_from_google_contacts",
|
||||
"google_contacts_description"
|
||||
"unsubscribed"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
|
|
@ -155,10 +160,6 @@
|
|||
"fieldtype": "Data",
|
||||
"label": "Designation"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_17",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "unsubscribed",
|
||||
|
|
@ -171,15 +172,17 @@
|
|||
"label": "Middle Name"
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.source==\"Google Contacts\"",
|
||||
"depends_on": "pulled_from_google_contacts",
|
||||
"fieldname": "google_contacts_description",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Google Contacts Description"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"depends_on": "eval:doc.sync_with_google_contacts || doc.pulled_from_google_contacts",
|
||||
"fieldname": "sb_00",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Contact Details"
|
||||
"label": "Google Contacts"
|
||||
},
|
||||
{
|
||||
"fieldname": "email_ids",
|
||||
|
|
@ -205,12 +208,39 @@
|
|||
"fieldtype": "Check",
|
||||
"label": "Pulled from Google Contacts",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "sync_with_google_contacts",
|
||||
"fieldtype": "Check",
|
||||
"label": "Sync with Google Contacts"
|
||||
},
|
||||
{
|
||||
"fieldname": "google_contacts",
|
||||
"fieldtype": "Link",
|
||||
"label": "Google Contacts",
|
||||
"options": "Google Contacts"
|
||||
},
|
||||
{
|
||||
"fieldname": "cb_00",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "sb_01",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Contact Details"
|
||||
},
|
||||
{
|
||||
"fieldname": "google_contacts_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Google Contacts Id",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-user",
|
||||
"idx": 1,
|
||||
"image_field": "image",
|
||||
"modified": "2019-09-06 06:43:02.159233",
|
||||
"modified": "2019-09-06 20:23:15.088231",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Contacts",
|
||||
"name": "Contact",
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ class Contact(Document):
|
|||
if self.email_id and not self.image:
|
||||
self.image = has_gravatar(self.email_id)
|
||||
|
||||
if self.sync_with_google_contacts and not self.google_contacts:
|
||||
frappe.throw(_("Select Google Contacts to which contact should be synced."))
|
||||
|
||||
deduplicate_dynamic_links(self)
|
||||
|
||||
def set_user(self):
|
||||
|
|
|
|||
|
|
@ -136,6 +136,18 @@ doc_events = {
|
|||
"on_change": [
|
||||
"frappe.social.doctype.energy_point_rule.energy_point_rule.process_energy_points"
|
||||
],
|
||||
},
|
||||
"Email Group Member": {
|
||||
"validate": "frappe.email.doctype.email_group.email_group.restrict_email_group"
|
||||
},
|
||||
"Event": {
|
||||
"after_insert": "frappe.integrations.doctype.google_calendar.google_calendar.insert_event_in_google_calendar",
|
||||
"on_update": "frappe.integrations.doctype.google_calendar.google_calendar.update_event_in_google_calendar",
|
||||
"on_trash": "frappe.integrations.doctype.google_calendar.google_calendar.delete_event_from_google_calendar",
|
||||
},
|
||||
"Contact": {
|
||||
"after_insert": "frappe.integrations.doctype.google_contacts.google_contacts.insert_contacts_to_google_contacts",
|
||||
"on_update": "frappe.integrations.doctype.google_contacts.google_contacts.update_contacts_to_google_contacts",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,12 +10,11 @@ import google.oauth2.credentials
|
|||
|
||||
from frappe.model.document import Document
|
||||
from frappe import _
|
||||
from googleapiclient.errors import HttpError
|
||||
from frappe.utils import get_request_site_address
|
||||
from frappe.integrations.doctype.google_settings.google_settings import get_auth_url
|
||||
|
||||
SCOPES = "https://www.googleapis.com/auth/contacts"
|
||||
REQUEST = "https://people.googleapis.com/v1/people/me/connections"
|
||||
PARAMS = {"personFields": "names,emailAddresses,organizations,phoneNumbers"}
|
||||
|
||||
class GoogleContacts(Document):
|
||||
|
||||
|
|
@ -135,24 +134,28 @@ def sync(g_contact=None):
|
|||
for g in google_contacts:
|
||||
return sync_contacts_from_google_contacts(g.name)
|
||||
|
||||
def sync_contacts_from_google_contacts(g_contact, page_length=10):
|
||||
def sync_contacts_from_google_contacts(g_contact):
|
||||
"""
|
||||
Syncs Contacts from Google Contacts.
|
||||
https://developers.google.com/people/api/rest/v1/contactGroups/list
|
||||
"""
|
||||
google_contacts, account = get_google_contacts_object(g_contact)
|
||||
|
||||
if not account.pull_from_google_contacts:
|
||||
return
|
||||
|
||||
results = []
|
||||
contacts_updated = 0
|
||||
|
||||
while True:
|
||||
try:
|
||||
sync_token = account.get_password(fieldname="next_sync_token", raise_exception=False) or None
|
||||
contacts = google_contacts.people().connections().list(resourceName='people/me', maxResults=page_length,
|
||||
syncToken=sync_token).execute()
|
||||
contacts = google_contacts.people().connections().list(resourceName='people/me',syncToken=sync_token,
|
||||
personFields="names,emailAddresses,organizations,phoneNumbers").execute()
|
||||
except HttpError as err:
|
||||
frappe.throw(_("Google Contacts - Could not sync contacts from Google Contacts, error code {0}.").format(err.resp.status))
|
||||
frappe.throw(_("Google Contacts - Could not sync contacts from Google Contacts {0}, error code {1}.").format(account.name, err.resp.status))
|
||||
|
||||
for contact in contacts.get("items"):
|
||||
for contact in contacts.get("connections"):
|
||||
results.append(contact)
|
||||
|
||||
if not contacts.get("nextPageToken"):
|
||||
|
|
@ -161,29 +164,29 @@ def sync_contacts_from_google_contacts(g_contact, page_length=10):
|
|||
frappe.db.commit()
|
||||
break
|
||||
|
||||
frappe.db.set_value("Google Contacts", doc.name, "last_sync_on", frappe.utils.now_datetime())
|
||||
frappe.db.set_value("Google Contacts", account.name, "last_sync_on", frappe.utils.now_datetime())
|
||||
|
||||
for idx, connection in enumerate(results):
|
||||
frappe.publish_realtime('import_google_contacts', dict(progress=idx+1, total=r.get("totalPeople")), user=frappe.session.user)
|
||||
frappe.publish_realtime('import_google_contacts', dict(progress=idx+1, total=len(results)), user=frappe.session.user)
|
||||
|
||||
for name in connection.get("names"):
|
||||
if name.get("metadata").get("primary"):
|
||||
contacts_updated += 1
|
||||
contact = frappe.get_doc({
|
||||
"doctype": "Contact",
|
||||
"salutation": name.get("honorificPrefix") or "",
|
||||
"first_name": name.get("givenName") or "",
|
||||
"middle_name": name.get("middleName") or "",
|
||||
"last_name": name.get("familyName") or "",
|
||||
"designation": get_indexed_value(connection.get("organizations"), 0, "title"),
|
||||
"source": "Google Contacts",
|
||||
"pulled_from_google_contacts": 1,
|
||||
"google_contacts_description": get_indexed_value(connection.get("organizations"), 0, "name")
|
||||
})
|
||||
|
||||
for email in connection.get("emailAddresses", []):
|
||||
contact.add_email(email_id=email.get("value"), is_primary=1 if email.get("primary") else 0)
|
||||
contact.add_email(email_id=email.get("value"), is_primary=1 if email.get("metadata").get("primary") else 0)
|
||||
|
||||
for phone in connection.get("phoneNumbers", []):
|
||||
contact.add_phone(phone=phone.get("value"), is_primary=1 if phone.get("primary") else 0)
|
||||
contact.add_phone(phone=phone.get("value"), is_primary=1 if phone.get("metadata").get("primary") else 0)
|
||||
|
||||
contact.insert(ignore_permissions=True)
|
||||
|
||||
|
|
@ -191,7 +194,79 @@ def sync_contacts_from_google_contacts(g_contact, page_length=10):
|
|||
else _("No new Google Contacts synced.")
|
||||
|
||||
def insert_contacts_to_google_contacts(doc, method=None):
|
||||
pass
|
||||
"""
|
||||
Syncs Contacts from Google Contacts.
|
||||
https://developers.google.com/people/api/rest/v1/people/createContact
|
||||
"""
|
||||
if not frappe.db.exists("Google Contacts", {"name": doc.google_contacts}) or doc.pulled_from_google_contacts \
|
||||
or not doc.sync_with_google_contacts:
|
||||
return
|
||||
|
||||
google_contacts, account = get_google_contacts_object(doc.google_contacts)
|
||||
|
||||
if not account.push_to_google_contacts:
|
||||
return
|
||||
|
||||
names = {
|
||||
"givenName": doc.first_name,
|
||||
"middleName": doc.middle_name,
|
||||
"familyName": doc.last_name
|
||||
}
|
||||
|
||||
phoneNumbers = [{"value": phone_no.phone} for phone_no in doc.phone_nos]
|
||||
emailAddresses = [{"value": email_id.email_id} for email_id in doc.email_ids]
|
||||
|
||||
try:
|
||||
contact = google_contacts.people().createContact(parent='people/me', body={"names": [names],"phoneNumbers": phoneNumbers,
|
||||
"emailAddresses": emailAddresses}).execute()
|
||||
frappe.db.set_value("Contact", doc.name, "google_contacts_id", contact.get("resourceName"))
|
||||
except HttpError as err:
|
||||
frappe.msgprint(_("Google Calendar - Could not insert contact in Google Contacts {0}, error code {1}.").format(account.name, err.resp.status))
|
||||
|
||||
def update_contacts_to_google_contacts(doc, method=None):
|
||||
"""
|
||||
Syncs Contacts from Google Contacts.
|
||||
https://developers.google.com/people/api/rest/v1/people/updateContact
|
||||
"""
|
||||
# Workaround to avoid triggering updation when Event is being inserted since
|
||||
# creation and modified are same when inserting doc
|
||||
if not frappe.db.exists("Google Contacts", {"name": doc.google_contacts}) or doc.modified == doc.creation \
|
||||
or not doc.sync_with_google_contacts:
|
||||
return
|
||||
|
||||
if doc.sync_with_google_contacts and not doc.google_contacts_id:
|
||||
# If sync_with_google_contacts is checked later, then insert the contact rather than updating it.
|
||||
insert_contacts_to_google_contacts(doc)
|
||||
return
|
||||
|
||||
google_contacts, account = get_google_contacts_object(doc.google_contacts)
|
||||
|
||||
if not account.push_to_google_contacts:
|
||||
return
|
||||
|
||||
names = {
|
||||
"givenName": doc.first_name,
|
||||
"middleName": doc.middle_name,
|
||||
"familyName": doc.last_name
|
||||
}
|
||||
|
||||
phoneNumbers = [{"value": phone_no.phone} for phone_no in doc.phone_nos]
|
||||
emailAddresses = [{"value": email_id.email_id} for email_id in doc.email_ids]
|
||||
|
||||
try:
|
||||
contact = google_contacts.people().get(resourceName=doc.google_contacts_id, \
|
||||
personFields="names,emailAddresses,organizations,phoneNumbers").execute()
|
||||
|
||||
contact["names"] = [names]
|
||||
contact["phoneNumbers"] = phoneNumbers
|
||||
contact["emailAddresses"] = emailAddresses
|
||||
|
||||
google_contacts.people().updateContact(resourceName=doc.google_contacts_id,body={"names":[names],
|
||||
"phoneNumbers":phoneNumbers,"emailAddresses":emailAddresses},
|
||||
updatePersonFields="names,emailAddresses,organizations,phoneNumbers").execute()
|
||||
frappe.msgprint(_("Contact Synced with Google Contacts."))
|
||||
except HttpError as err:
|
||||
frappe.msgprint(_("Google Contacts - Could not update contact in Google Contacts {0}, error code {1}.").format(account.name, err.resp.status))
|
||||
|
||||
def get_indexed_value(d, index, key):
|
||||
if not d:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue