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