From 8333562e1acf7b4fc22548ddabd6b0a9c57dac47 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Thu, 27 Feb 2014 12:54:46 +0530 Subject: [PATCH] Build and Watch without passing site argument, Finishing touches to Google OAuth --- frappe/__init__.py | 8 +-- frappe/build.py | 3 - frappe/cli.py | 8 ++- frappe/core/doctype/profile/profile.py | 47 ------------ frappe/core/doctype/profile/profile.txt | 31 ++++---- frappe/handler.py | 2 +- frappe/templates/includes/login.js | 14 +--- frappe/templates/pages/login.html | 3 +- frappe/templates/pages/login.py | 95 +++++++++++++++++++++---- requirements.txt | 1 + 10 files changed, 110 insertions(+), 102 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index bfe6a58718..feaf501d06 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -119,14 +119,14 @@ def init(site, sites_path=None): def get_site_config(): config = {} - sites_config_filepath = os.path.join(local.sites_path, "site_config.json") + common_site_config_filepath = os.path.join(local.sites_path, "common_site_config.json") site_config_filepath = os.path.join(local.site_path, "site_config.json") - if os.path.exists(sites_config_filepath): - config = get_file_json(sites_config_filepath) + if os.path.exists(common_site_config_filepath): + config = get_file_json(common_site_config_filepath) if os.path.exists(site_config_filepath): config.update(get_file_json(site_config_filepath)) return _dict(config) - + def destroy(): """closes connection and releases werkzeug local""" if db: diff --git a/frappe/build.py b/frappe/build.py index 7f5342efb0..79ac453547 100644 --- a/frappe/build.py +++ b/frappe/build.py @@ -10,14 +10,12 @@ Build the `public` folders and setup languages import os, sys, frappe, json, shutil from cssmin import cssmin -import frappe.translate def bundle(no_compress): """concat / minify js files""" # build js files make_asset_dirs() build(no_compress) - frappe.translate.clear_cache() def watch(no_compress): """watch and rebuild if necessary""" @@ -32,7 +30,6 @@ def watch(no_compress): def make_asset_dirs(): assets_path = os.path.join(frappe.local.sites_path, "assets") - site_public_path = os.path.join(frappe.local.site_path, 'public') for dir_path in [ os.path.join(assets_path, 'js'), os.path.join(assets_path, 'css')]: diff --git a/frappe/cli.py b/frappe/cli.py index e2f6dc6a2e..b0f0ed7d7e 100755 --- a/frappe/cli.py +++ b/frappe/cli.py @@ -8,7 +8,7 @@ import sys, os import frappe -site_arg_optional = ['serve'] +site_arg_optional = ['serve', 'build', 'watch'] def get_site(parsed_args): if not parsed_args.get("site") and os.path.exists(os.path.join(parsed_args["sites_path"], "currentsite.txt")): @@ -41,6 +41,9 @@ def main(): exit(1) elif site: frappe.init(site, sites_path=sites_path) + else: + # site argument optional + frappe.init("", sites_path=sites_path) run(fn, parsed_args) else: run(fn, parsed_args) @@ -298,6 +301,7 @@ def latest(verbose=True, rebuild_website_config=True): import frappe.model.sync from frappe.website import rebuild_config from frappe.utils.fixtures import sync_fixtures + import frappe.translate frappe.connect() @@ -317,6 +321,8 @@ def latest(verbose=True, rebuild_website_config=True): sync_fixtures() + frappe.translate.clear_cache() + except frappe.modules.patch_handler.PatchError, e: print "\n".join(frappe.local.patch_log_list) raise diff --git a/frappe/core/doctype/profile/profile.py b/frappe/core/doctype/profile/profile.py index daba515c09..0d281b9a0e 100644 --- a/frappe/core/doctype/profile/profile.py +++ b/frappe/core/doctype/profile/profile.py @@ -357,53 +357,6 @@ def reset_password(user): return "Password reset details sent to your email." else: return "No such user (%s)" % user - -@frappe.whitelist(allow_guest=True) -def facebook_login(data): - data = json.loads(data) - - if not (data.get("id") and data.get("fb_access_token")): - raise frappe.ValidationError - - user = data["email"] - - if not get_fb_userid(data.get("fb_access_token")): - # garbage - raise frappe.ValidationError - - if not frappe.db.exists("Profile", user): - if data.get("birthday"): - b = data.get("birthday").split("/") - data["birthday"] = b[2] + "-" + b[0] + "-" + b[1] - - profile = frappe.bean({ - "doctype":"Profile", - "first_name": data["first_name"], - "last_name": data["last_name"], - "email": data["email"], - "enabled": 1, - "new_password": frappe.generate_hash(data["email"]), - "fb_username": data["username"], - "fb_userid": data["id"], - "location": data.get("location", {}).get("name"), - "birth_date": data.get("birthday"), - "user_type": "Website User" - }) - profile.ignore_permissions = True - profile.get_controller().no_welcome_mail = True - profile.insert() - - frappe.local.login_manager.user = user - frappe.local.login_manager.post_login() - -def get_fb_userid(fb_access_token): - import requests - response = requests.get("https://graph.facebook.com/me?access_token=" + fb_access_token) - if response.status_code==200: - print response.json() - return response.json().get("id") - else: - return frappe.AuthenticationError def profile_query(doctype, txt, searchfield, start, page_len, filters): from frappe.widgets.reportview import get_match_cond diff --git a/frappe/core/doctype/profile/profile.txt b/frappe/core/doctype/profile/profile.txt index 9e7af19117..63cd6407b3 100644 --- a/frappe/core/doctype/profile/profile.txt +++ b/frappe/core/doctype/profile/profile.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-07 11:54:44", "docstatus": 0, - "modified": "2014-01-29 16:52:01", + "modified": "2014-02-26 17:40:31", "modified_by": "Administrator", "owner": "Administrator" }, @@ -34,6 +34,7 @@ }, { "cancel": 0, + "delete": 0, "doctype": "DocPerm", "name": "__common__", "parent": "Profile", @@ -454,9 +455,9 @@ }, { "doctype": "DocField", - "fieldname": "facebook_authentication", + "fieldname": "third_party_authentication", "fieldtype": "Section Break", - "label": "Facebook Authentication", + "label": "Third Party Authentication", "permlevel": 0 }, { @@ -475,9 +476,16 @@ "permlevel": 0, "read_only": 1 }, + { + "doctype": "DocField", + "fieldname": "google_userid", + "fieldtype": "Data", + "label": "Google User ID", + "permlevel": 0, + "read_only": 1 + }, { "create": 1, - "delete": 1, "doctype": "DocPerm", "email": 1, "permlevel": 0, @@ -489,7 +497,6 @@ }, { "create": 0, - "delete": 0, "doctype": "DocPerm", "email": 1, "permlevel": 0, @@ -497,23 +504,9 @@ "role": "All", "write": 0 }, - { - "create": 0, - "delete": 0, - "doctype": "DocPerm", - "email": 1, - "permlevel": 0, - "print": 1, - "report": 1, - "restricted": 1, - "role": "All", - "submit": 0, - "write": 0 - }, { "amend": 0, "create": 0, - "delete": 0, "doctype": "DocPerm", "permlevel": 1, "report": 1, diff --git a/frappe/handler.py b/frappe/handler.py index d694299fb8..cb9dc3d389 100755 --- a/frappe/handler.py +++ b/frappe/handler.py @@ -79,7 +79,7 @@ def handle(): else: if frappe.local.request.method in ("POST", "PUT") and frappe.db: frappe.db.commit() - + build_response() if frappe.db: diff --git a/frappe/templates/includes/login.js b/frappe/templates/includes/login.js index f81db639b6..d6b1275fcb 100644 --- a/frappe/templates/includes/login.js +++ b/frappe/templates/includes/login.js @@ -145,7 +145,7 @@ login.via_facebook = function() { url:"/", type: "POST", data: { - cmd:"frappe.core.doctype.profile.profile.facebook_login", + cmd:"frappe.templates.pages.login.login_via_facebook", data: JSON.stringify(response) }, statusCode: login.login_handlers @@ -174,15 +174,3 @@ frappe.ready(function() { }); {%- endif %} - -{% if google_sign_in is defined -%} - -frappe.ready(function() { - $(".btn-google").click(function() { - frappe.call({ - method: "frappe.templates.pages.login.get_google_auth_url" - }) - }) -}) - -{%- endif -%} \ No newline at end of file diff --git a/frappe/templates/pages/login.html b/frappe/templates/pages/login.html index 0c1f813edb..8b3616a560 100644 --- a/frappe/templates/pages/login.html +++ b/frappe/templates/pages/login.html @@ -23,8 +23,7 @@ {%- if google_sign_in is defined %}

or

- + {{ _("Login via Google") }}

{%- endif -%}

diff --git a/frappe/templates/pages/login.py b/frappe/templates/pages/login.py index e2ba627f68..7edd544e8e 100644 --- a/frappe/templates/pages/login.py +++ b/frappe/templates/pages/login.py @@ -4,6 +4,8 @@ from __future__ import unicode_literals import frappe, os import httplib2 +import json +from werkzeug.utils import redirect no_cache = True @@ -19,30 +21,99 @@ def get_context(context): return context def get_google_auth_url(): - from oauth2client.client import flow_from_clientsecrets - flow = flow_from_clientsecrets(frappe.get_site_path("google_config.json"), - scope=['https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email'], - redirect_uri='http://localhost:8000/api/method/frappe.templates.pages.login.login_via_google') - + flow = get_google_auth_flow() return flow.step1_get_authorize_url() -@frappe.whitelist(allow_guest=True) -def login_via_google(code): +def get_google_auth_flow(): from oauth2client.client import flow_from_clientsecrets + google_config_path = frappe.get_site_path("google_config.json") + google_config = frappe.get_file_json(google_config_path) - - flow = flow_from_clientsecrets(frappe.get_site_path("google_config.json"), + flow = flow_from_clientsecrets(google_config_path, scope=['https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email'], - redirect_uri='http://localhost:8000/api/method/frappe.templates.pages.login.login_via_google') + redirect_uri=google_config.get("web").get("redirect_uris")[0]) + return flow + +@frappe.whitelist(allow_guest=True) +def login_via_google(code): + flow = get_google_auth_flow() credentials = flow.step2_exchange(code) http = httplib2.Http() http = credentials.authorize(http) resp, content = http.request('https://www.googleapis.com/oauth2/v2/userinfo', 'GET') + info = json.loads(content) - print content + if not info.get("verified_email"): + frappe.throw("You need to verify your email with Google before you can proceed.") + frappe.local._response = redirect("/") - \ No newline at end of file + login_oauth_user(info, oauth_provider="google") + + # because of a GET request! + frappe.db.commit() + +@frappe.whitelist(allow_guest=True) +def login_via_facebook(data): + data = json.loads(data) + + if not (data.get("id") and data.get("fb_access_token")): + raise frappe.ValidationError + + if not get_fb_userid(data.get("fb_access_token")): + # garbage + raise frappe.ValidationError + + login_oauth_user(data, oauth_provider="facebook") + +def login_oauth_user(data, oauth_provider=None): + user = data["email"] + + if not frappe.db.exists("Profile", user): + create_oauth_user(data, oauth_provider) + + frappe.local.login_manager.user = user + frappe.local.login_manager.post_login() + +def create_oauth_user(data, oauth_provider): + if data.get("birthday"): + b = data.get("birthday").split("/") + data["birthday"] = b[2] + "-" + b[0] + "-" + b[1] + + profile = frappe.bean({ + "doctype":"Profile", + "first_name": data.get("first_name") or data.get("given_name"), + "last_name": data.get("last_name") or data.get("family_name"), + "email": data["email"], + "gender": data.get("gender"), + "enabled": 1, + "new_password": frappe.generate_hash(data["email"]), + "location": data.get("location", {}).get("name"), + "birth_date": data.get("birthday"), + "user_type": "Website User", + "user_image": data.get("picture") + }) + + if oauth_provider=="facebook": + profile.doc.fields.update({ + "fb_username": data["username"], + "fb_userid": data["id"] + }) + elif oauth_provider=="google": + profile.doc.google_userid = data["id"] + + profile.ignore_permissions = True + profile.get_controller().no_welcome_mail = True + profile.insert() + +def get_fb_userid(fb_access_token): + import requests + response = requests.get("https://graph.facebook.com/me?access_token=" + fb_access_token) + if response.status_code==200: + print response.json() + return response.json().get("id") + else: + return frappe.AuthenticationError \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 5c8b554743..66915e8cdd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ chardet cssmin dropbox +rauth oauth2client gunicorn httplib2