Commit 136ec9e2 authored by Pratik Vyas's avatar Pratik Vyas
Browse files

Merge branch 'develop'

parents 1466720a 1022a9b4
develop v11.1.5 v11.1.4 v11.1.3 v11.1.2 v11.1.1 v11.1.0 v11.0.3 v11.0.3-beta.51 v11.0.3-beta.50 v11.0.3-beta.49 v11.0.3-beta.48 v11.0.3-beta.47 v11.0.3-beta.46 v11.0.3-beta.45 v11.0.3-beta.44 v11.0.3-beta.43 v11.0.3-beta.42 v11.0.3-beta.41 v11.0.3-beta.40 v11.0.3-beta.39 v11.0.3-beta.38 v11.0.3-beta.37 v11.0.3-beta.36 v11.0.3-beta.35 v11.0.3-beta.34 v11.0.3-beta.33 v11.0.3-beta.32 v11.0.3-beta.31 v11.0.3-beta.30 v11.0.3-beta.29 v11.0.3-beta.28 v11.0.3-beta.27 v11.0.3-beta.26 v11.0.3-beta.25 v11.0.3-beta.24 v11.0.3-beta.23 v11.0.3-beta.22 v11.0.3-beta.21 v11.0.3-beta.20 v11.0.3-beta.19 v11.0.3-beta.18 v11.0.3-beta.17 v11.0.3-beta.16 v11.0.3-beta.15 v11.0.3-beta.14 v11.0.3-beta.13 v11.0.3-beta.12 v11.0.3-beta.11 v11.0.3-beta.10 v11.0.3-beta.9 v11.0.3-beta.8 v11.0.3-beta.7 v11.0.3-beta.6 v11.0.3-beta.5 v11.0.3-beta.4 v11.0.3-beta.3 v11.0.3-beta.2 v11.0.3-beta.1 v11.0.2 v11.0.1 v11.0.0-beta v10.1.71 v10.1.70 v10.1.69 v10.1.68 v10.1.67 v10.1.66 v10.1.65 v10.1.64 v10.1.63 v10.1.62 v10.1.61 v10.1.60 v10.1.59 v10.1.58 v10.1.57 v10.1.56 v10.1.55 v10.1.54 v10.1.53 v10.1.52 v10.1.51 v10.1.50 v10.1.49 v10.1.49-beta.1 v10.1.48 v10.1.47 v10.1.46 v10.1.45 v10.1.44 v10.1.43 v10.1.42 v10.1.41 v10.1.40 v10.1.39 v10.1.38 v10.1.37 v10.1.36 v10.1.35 v10.1.34 v10.1.33 v10.1.32 v10.1.31 v10.1.30 v10.1.29 v10.1.28 v10.1.27 v10.1.26 v10.1.25 v10.1.24 v10.1.23 v10.1.22 v10.1.21 v10.1.20 v10.1.19 v10.1.18 v10.1.17 v10.1.16 v10.1.15 v10.1.14 v10.1.13 v10.1.12 v10.1.11 v10.1.10 v10.1.9 v10.1.8 v10.1.7 v10.1.6 v10.1.5 v10.1.4 v10.1.3 v10.1.2 v10.1.1 v10.1.0 v10.0.25 v10.0.24 v10.0.23 v10.0.22 v10.0.21 v10.0.20 v10.0.19 v10.0.18 v10.0.17 v10.0.16 v10.0.15 v10.0.14 v10.0.13 v10.0.12 v10.0.11 v10.0.10 v10.0.9 v10.0.8 v10.0.7 v10.0.6 v10.0.5 v10.0.4 v10.0.3 v10.0.2 v10.0.1 v10.0.0 v9.2.25 v9.2.24 v9.2.23 v9.2.22 v9.2.21 v9.2.20 v9.2.19 v9.2.18 v9.2.17 v9.2.16 v9.2.15 v9.2.14 v9.2.13 v9.2.12 v9.2.11 v9.2.10 v9.2.9 v9.2.8 v9.2.7 v9.2.6 v9.2.5 v9.2.4 v9.2.3 v9.2.2 v9.2.1 v9.2.0 v9.1.11 v9.1.10 v9.1.9 v9.1.8 v9.1.7 v9.1.6 v9.1.5 v9.1.4 v9.1.3 v9.1.2 v9.1.1 v9.1.0 v9.0.10 v9.0.9 v9.0.8 v9.0.7 v9.0.6 v9.0.5 v9.0.4 v9.0.3 v9.0.2 v9.0.1 v9.0.0 v8.10.9 v8.10.8 v8.10.7 v8.10.6 v8.10.5 v8.10.4 v8.10.3 v8.10.2 v8.10.1 v8.10.0 v8.9.4 v8.9.3 v8.9.2 v8.9.1 v8.9.0 v8.8.5 v8.8.4 v8.8.3 v8.8.2 v8.8.1 v8.8.0 v8.7.11 v8.7.10 v8.7.9 v8.7.8 v8.7.7 v8.7.6 v8.7.5 v8.7.4 v8.7.3 v8.7.2 v8.7.1 v8.7.0 v8.6.8 v8.6.7 v8.6.6 v8.6.5 v8.6.4 v8.6.3 v8.6.2 v8.6.1 v8.6.0 v8.5.8 v8.5.7 v8.5.6 v8.5.5 v8.5.4 v8.5.3 v8.5.2 v8.5.1 v8.5.0 v8.4.1 v8.4.0 v8.3.10 v8.3.9 v8.3.8 v8.3.7 v8.3.6 v8.3.5 v8.3.4 v8.3.3 v8.3.2 v8.3.1 v8.3.0 v8.2.7 v8.2.6 v8.2.5 v8.2.4 v8.2.3 v8.2.2 v8.2.1 v8.2.0 v8.1.4 v8.1.3 v8.1.2 v8.1.1 v8.1.0 v8.0.71 v8.0.70 v8.0.69 v8.0.68 v8.0.67 v8.0.66 v8.0.65 v8.0.64 v8.0.63 v8.0.62 v8.0.61 v8.0.60 v8.0.59 v8.0.58 v8.0.57 v8.0.56 v8.0.55 v8.0.54 v8.0.53 v8.0.52 v8.0.51 v8.0.50 v8.0.49 v8.0.48 v8.0.47 v8.0.46 v8.0.45 v8.0.44 v8.0.43 v8.0.42 v8.0.41 v8.0.40 v8.0.39 v8.0.38 v8.0.37 v8.0.36 v8.0.35 v8.0.34 v8.0.33 v8.0.32 v8.0.31 v8.0.30 v8.0.29 v8.0.28 v8.0.27 v8.0.26 v8.0.25 v8.0.24 v8.0.23 v8.0.22 v8.0.21 v8.0.20 v8.0.19 v8.0.18 v8.0.17 v8.0.16 v8.0.15 v8.0.14 v8.0.13 v8.0.12 v8.0.11 v8.0.10 v8.0.9 v8.0.8 v8.0.7 v8.0.6 v8.0.5 v8.0.4 v8.0.3 v8.0.2 v8.0.1 v8.0.0 v7.2.31 v7.2.30 v7.2.29 v7.2.28 v7.2.27 v7.2.26 v7.2.25 v7.2.24 v7.2.23 v7.2.22 v7.2.21 v7.2.20 v7.2.19 v7.2.18 v7.2.17 v7.2.16 v7.2.15 v7.2.14 v7.2.13 v7.2.12 v7.2.11 v7.2.10 v7.2.9 v7.2.8 v7.2.7 v7.2.6 v7.2.5 v7.2.4 v7.2.3 v7.2.2 v7.2.1 v7.2.0 v7.1.29 v7.1.28 v7.1.27 v7.1.26 v7.1.25 v7.1.24 v7.1.23 v7.1.22 v7.1.21 v7.1.20 v7.1.19 v7.1.18 v7.1.17 v7.1.16 v7.1.15 v7.1.14 v7.1.13 v7.1.12 v7.1.11 v7.1.10 v7.1.9 v7.1.8 v7.1.7 v7.1.6 v7.1.5 v7.1.4 v7.1.3 v7.1.2 v7.1.1 v7.1.0 v7.0.47 v7.0.46 v7.0.45 v7.0.44 v7.0.43 v7.0.42 v7.0.41 v7.0.40 v7.0.39 v7.0.38 v7.0.37 v7.0.36 v7.0.35 v7.0.34 v7.0.33 v7.0.32 v7.0.31 v7.0.30 v7.0.29 v7.0.28 v7.0.27 v7.0.26 v7.0.25 v7.0.24 v7.0.23 v7.0.22 v7.0.21 v7.0.20 v7.0.19 v7.0.18 v7.0.17 v7.0.16 v7.0.15 v7.0.14 v7.0.13 v7.0.12 v7.0.11 v7.0.10 v7.0.9 v7.0.8 v7.0.7 v7.0.6 v7.0.5 v7.0.4 v7.0.3 v7.0.2 v7.0.1 v7.0.0 v6.27.24 v6.27.23 v6.27.22 v6.27.21 v6.27.20 v6.27.19 v6.27.18 v6.27.17 v6.27.16 v6.27.15 v6.27.14 v6.27.13 v6.27.12 v6.27.11 v6.27.10 v6.27.9 v6.27.8 v6.27.7 v6.27.6 v6.27.5 v6.27.4 v6.27.3 v6.27.2 v6.27.1 v6.27.0 v6.26.6 v6.26.5 v6.26.4 v6.26.3 v6.26.2 v6.26.1 v6.26.0 v6.25.6 v6.25.5 v6.25.4 v6.25.3 v6.25.2 v6.25.1 v6.25.0 v6.24.10 v6.24.9 v6.24.8 v6.24.7 v6.24.6 v6.24.5 v6.24.4 v6.24.3 v6.24.2 v6.24.1 v6.24.0 v6.23.3 v6.23.2 v6.23.1 v6.23.0 v6.22.7 v6.22.6 v6.22.5 v6.22.4 v6.22.3 v6.22.2 v6.22.1 v6.22.0 v6.21.0 v6.20.2 v6.20.1 v6.20.0 v6.19.3 v6.19.2 v6.19.1 v6.19.0 v6.18.1 v6.18.0 v6.17.6 v6.17.5 v6.17.4 v6.17.3 v6.17.2 v6.17.1 v6.17.0 v6.16.4 v6.16.3 v6.16.2 v6.16.1 v6.16.0 v6.15.4 v6.15.3 v6.15.2 v6.15.1 v6.15.0 v6.14.1 v6.14.0 v6.13.5 v6.13.4 v6.13.3 v6.13.2 v6.13.1 v6.13.0 v6.12.4 v6.12.3 v6.12.2 v6.12.1 v6.12.0 v6.11.0 v6.10.4 v6.10.3 v6.10.2 v6.10.1 v6.10.0 v6.9.3 v6.9.2 v6.9.1 v6.9.0 v6.8.2 v6.8.1 v6.8.0 v6.7.11 v6.7.10 v6.7.9 v6.7.8 v6.7.7 v6.7.6 v6.7.5 v6.7.4 v6.7.3 v6.7.2 v6.7.1 v6.7.0 v6.6.5 v6.6.4 v6.6.3 v6.6.2 v6.6.1 v6.6.0 v6.5.4 v6.5.3 v6.5.2 v6.5.1 v6.5.0 v6.4.9 v6.4.8 v6.4.7 v6.4.6 v6.4.5 v6.4.4 v6.4.3 v6.4.2 v6.4.1 v6.4.0 v6.3.0 v6.2.0 v6.1.2 v6.1.1 v6.1.0 v6.0.8 v6.0.7 v6.0.6 v6.0.5 v6.0.4 v6.0.3 v6.0.2 v6.0.1 v6.0.0 v5.4.2 v5.4.1 v5.4.0 v5.3.1 v5.3.0 v5.2.2 v5.2.1 v5.2.0 v5.1.5 v5.1.4 v5.1.3 v5.1.2 v5.1.1 v5.1.0 v5.0.35 v5.0.34 v5.0.33 v5.0.32 v5.0.31 v5.0.30 v5.0.29 v5.0.28 v5.0.27 v5.0.26 v5.0.25 v5.0.24 v5.0.23 v5.0.22 v5.0.21 v5.0.20 v5.0.19 v5.0.18 v5.0.17 v5.0.16 v5.0.15 v5.0.14 v5.0.13 v5.0.12 v5.0.11 v5.0.10 v5.0.9 v5.0.8 v5.0.7 v5.0.6 v5.0.5 v5.0.4 v5.0.3 v5.0.2 v5.0.1 v5.0.0
No related merge requests found
Showing with 1717 additions and 1261 deletions
+1717 -1261
......@@ -8,3 +8,4 @@ locale
*.egg-info
dist/
build/
docs/
......@@ -7,33 +7,26 @@ services:
- mysql
install:
- sudo service mysql stop
- sudo apt-get install python-software-properties
- sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db
- sudo add-apt-repository 'deb http://ftp.osuosl.org/pub/mariadb/repo/10.0/ubuntu precise main'
- sudo apt-get update
- sudo apt-get purge -y mysql-common
- sudo apt-get install mariadb-server mariadb-common libmariadbclient-dev
- ./ci/fix-mariadb.sh
- sudo apt-get install xfonts-75dpi xfonts-base -y
- wget http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.2.1/wkhtmltox-0.12.2.1_linux-precise-amd64.deb
- sudo dpkg -i wkhtmltox-0.12.2.1_linux-precise-amd64.deb
- CFLAGS=-O0 pip install -r requirements.txt
- pip install --editable .
- wget https://raw.githubusercontent.com/frappe/bench/master/install_scripts/setup_frappe.sh
- sudo bash setup_frappe.sh --skip-setup-bench --mysql-root-password travis
- sudo service redis-server start
- rm $TRAVIS_BUILD_DIR/.git/shallow
- cd ~/ && bench init frappe-bench --frappe-path $TRAVIS_BUILD_DIR
- cp -r $TRAVIS_BUILD_DIR/test_sites/test_site ~/frappe-bench/sites/
script:
- cd ./test_sites/
- frappe --use test_site
- frappe --reinstall
- frappe -b
- frappe --build_website
- frappe --serve_test &
- frappe --verbose --run_tests
- cd ~/frappe-bench
- bench use test_site
- bench reinstall
- bench build
- bench build-website
- bench serve &
- sleep 10
- bench --verbose run-tests
before_script:
- mysql -e 'create database test_frappe'
- echo "USE mysql;\nCREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe';\nFLUSH PRIVILEGES;\n" | mysql -u root
- echo "USE mysql;\nGRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost';\n" | mysql -u root
- echo "USE mysql;\nCREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe';\nFLUSH PRIVILEGES;\n" | mysql -u root -ptravis
- echo "USE mysql;\nGRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost';\n" | mysql -u root -ptravis
# Contributing to Frappe / ERPNext
### Update 16-Sep-14
Please send pull requests to branch v5.0
## Reporting issues
We only accept issues that are bug reports or feature requests. Bugs must be isolated and reproducible problems. Please read the following guidelines before opening any issue.
......@@ -17,7 +13,7 @@ We only accept issues that are bug reports or feature requests. Bugs must be iso
1. **Share as much information as possible:** Include operating system and version, browser and version, when did you last update ERPNext, how is it customized, etc. where appropriate. Also include steps to reproduce the bug.
1. **Include Screenshots if possible:** Consider adding screenshots annotated with what goes wrong.
1. **Find and post the trace for bugs:** If you are reporting an issue from the browser, Open the Javascript Console and paste us any error messages you see.
1. **Security Issues:** If you are reporting a security issue, please send a private email to <info@frappe.io>.
### Feature Requests
......
## Frappe framework includes these public works
### Javascript / CSS
- Bootstrap: MIT License, (c) Twitter Inc, https://getbootstrap.com
- JQuery: MIT License, (c) JQuery Foundation, http://jquery.org/license
- JQuery UI: MIT License / GPL 2, (c) JQuery Foundation, https://jqueryui.com/about
- JQuery UI Bootstrap Theme: MIT / GPL 2, (c) Addy Osmani, http://addyosmani.github.com/jquery-ui-bootstrap
- QUnit: MIT License, (c) JQuery Foundation, http://jquery.org/license
- jquery.event.drag, MIT License, (c) 2010 Three Dub Media - http://threedubmedia.com
- JQuery Cookie Plugin, MIT / GPL 2, (c) 2011, Klaus Hartl
- JQuery Time Picker, MIT License, (c) 2013 Trent Richardson, http://trentrichardson.com/examples/timepicker
- JQuery Hotkeys Plugin, MIT License, (c) 2010, John Resig
- prettydate.js, MIT License, (c) 2011, John Resig
- jquery.flot.downsample, MIT License, (c) 2013, Sveinn Steinarsson
- JQuery Resize Event, MIT License, (c) 2010 "Cowboy" Ben Alman
- excanvas.js, Apache License Version 2.0, (c) 2006 Google Inc
- showdown.js - Javascript Markdown, BSD-style Open Source License, (c) 2007 John Fraser
- Beautify HTML - MIT License, (c) 2007-2013 Einar Lielmanis and contributors.
- JQuery Gantt - MIT License, http://taitems.github.com/jQuery.Gantt/
- SlickGrid - MIT License, https://github.com/mleibman/SlickGrid
- MomentJS - MIT License, https://github.com/moment/moment
- JSColor - LGPL, (c) Jan Odvarko, http://jscolor.com
- FullCalendar - MIT License, (c) 2013 Adam Shaw, http://fullcalendar.io/license/
- Sortable - MIT License (c) 2013-2015 Lebedev Konstantin http://rubaxa.github.io/Sortable/
### Python
- minify.js - MIT License, (c) 2002 Douglas Crockford
### Icon Fonts
- Font Awesome - http://fontawesome.io/
- Font License: SIL OFL 1.1 (http://scripts.sil.org/OFL)
- Code License: MIT (http://choosealicense.com/licenses/mit/)
- Octicons (c) GitHub Inc, https://octicons.github.com/
- Font License: SIL OFL 1.1 (http://scripts.sil.org/OFL)
- Code License: MIT (http://choosealicense.com/licenses/mit/)
- Ionicons - MIT License, http://ionicons.com/
### IP Address Database
- GeoIP: (c) 2014 MaxMind, http://dev.maxmind.com/geoip/geoip2/downloadable/
### Wallpaper
- Version 5 Wallpaper: http://magdeleine.co/photo-nick-west-n-139/ (Public Domain)
---
Last updated: 1st Jan 2015
This diff is collapsed.
from __future__ import unicode_literals
__version__ = "4.14.3"
__version__ = "v5.0.0"
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
......@@ -6,25 +6,32 @@ import json
import frappe
import frappe.handler
import frappe.client
import frappe.widgets.reportview
import frappe.desk.reportview
from frappe.utils.response import build_response
from frappe import _
def handle():
"""
/api/method/{methodname} will call a whitelisted method
/api/resource/{doctype} will query a table
Handler for `/api` methods
### Examples:
`/api/method/{methodname}` will call a whitelisted method
`/api/resource/{doctype}` will query a table
examples:
?fields=["name", "owner"]
?filters=[["Task", "name", "like", "%005"]]
?limit_start=0
?limit_page_length=20
/api/resource/{doctype}/{name} will point to a resource
GET will return doclist
POST will insert
PUT will update
DELETE will delete
/api/resource/{doctype}/{name}?run_method={method} will run a whitelisted controller method
- `?fields=["name", "owner"]`
- `?filters=[["Task", "name", "like", "%005"]]`
- `?limit_start=0`
- `?limit_page_length=20`
`/api/resource/{doctype}/{name}` will point to a resource
`GET` will return doclist
`POST` will insert
`PUT` will update
`DELETE` will delete
`/api/resource/{doctype}/{name}?run_method={method}` will run a whitelisted controller method
"""
parts = frappe.request.path[1:].split("/",3)
call = doctype = name = None
......@@ -71,10 +78,15 @@ def handle():
if frappe.local.request.method=="PUT":
data = json.loads(frappe.local.form_dict.data)
doc = frappe.get_doc(doctype, name)
if "flags" in data:
del data["flags"]
# Not checking permissions here because it's checked in doc.save
doc.update(data)
frappe.local.response.update({
"data": doc.save().as_dict()
"data": doc.save().as_dict()
})
frappe.db.commit()
......@@ -90,8 +102,9 @@ def handle():
if frappe.local.request.method=="GET":
if frappe.local.form_dict.get('fields'):
frappe.local.form_dict['fields'] = json.loads(frappe.local.form_dict['fields'])
frappe.local.form_dict.setdefault('limit_page_length', 20)
frappe.local.response.update({
"data": frappe.call(frappe.widgets.reportview.execute,
"data": frappe.call(frappe.client.get_list,
doctype, **frappe.local.form_dict)})
if frappe.local.request.method=="POST":
......
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
......@@ -77,9 +77,9 @@ def application(request):
# 1205 = lock wait timeout
# 1213 = deadlock
# code 409 represents conflict
http_status_code = 409
http_status_code = 508
if frappe.local.is_ajax:
if frappe.local.is_ajax or 'application/json' in request.headers.get('Accept', ''):
response = frappe.utils.response.report_error(http_status_code)
else:
frappe.respond_as_web_page("Server Error",
......@@ -129,6 +129,10 @@ def make_form_dict(request):
frappe.local.form_dict = frappe._dict({ k:v[0] if isinstance(v, (list, tuple)) else v \
for k, v in (request.form or request.args).iteritems() })
if "_" in frappe.local.form_dict:
# _ is passed by $.ajax so that the request is not cached by the browser. So, remove _ from form_dict
frappe.local.form_dict.pop("_")
application = local_manager.make_middleware(application)
def serve(port=8000, profile=False, site=None, sites_path='.'):
......
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
......@@ -22,10 +22,17 @@ class HTTPRequest:
if self.domain and self.domain.startswith('www.'):
self.domain = self.domain[4:]
frappe.local.request_ip = frappe.get_request_header('REMOTE_ADDR') \
or frappe.get_request_header('X-Forwarded-For') or '127.0.0.1'
if frappe.get_request_header('X-Forwarded-For'):
frappe.local.request_ip = frappe.get_request_header('X-Forwarded-For')
elif frappe.get_request_header('REMOTE_ADDR'):
frappe.local.request_ip = frappe.get_request_header('REMOTE_ADDR')
else:
frappe.local.request_ip = '127.0.0.1'
# language
self.set_lang(frappe.get_request_header('HTTP_ACCEPT_LANGUAGE'))
self.set_lang(frappe.request.accept_languages.values())
# load cookies
frappe.local.cookie_manager = CookieManager()
......@@ -47,19 +54,22 @@ class HTTPRequest:
# check status
check_session_stopped()
# load user
self.setup_user()
# run login triggers
if frappe.form_dict.get('cmd')=='login':
frappe.local.login_manager.run_trigger('on_session_creation')
self.clear_active_sessions()
def clear_active_sessions(self):
if not frappe.conf.get("deny_multiple_sessions"):
return
def set_lang(self, lang):
from frappe.translate import guess_language_from_http_header
frappe.local.lang = guess_language_from_http_header(lang)
if frappe.session.user != "Guest":
clear_sessions(frappe.session.user, keep_current=True)
def setup_user(self):
frappe.local.user = frappe.utils.user.User()
def set_lang(self, lang_codes):
from frappe.translate import guess_language
frappe.local.lang = guess_language(lang_codes)
def get_db_name(self):
"""get database name from conf"""
......@@ -73,6 +83,10 @@ class HTTPRequest:
class LoginManager:
def __init__(self):
self.user = None
self.info = None
self.full_name = None
self.user_type = None
if frappe.local.form_dict.get('cmd')=='login' or frappe.local.request.path=="/api/method/login":
self.login()
else:
......@@ -85,6 +99,11 @@ class LoginManager:
self.post_login()
def post_login(self):
self.info = frappe.db.get_value("User", self.user,
["user_type", "first_name", "last_name", "user_image"], as_dict=1)
self.full_name = " ".join(filter(None, [self.info.first_name, self.info.last_name]))
self.user_type = self.info.user_type
self.run_trigger('on_login')
self.validate_ip_address()
self.validate_hour()
......@@ -95,24 +114,22 @@ class LoginManager:
# set sid again
frappe.local.cookie_manager.init_cookies()
info = frappe.db.get_value("User", self.user,
["user_type", "first_name", "last_name", "user_image"], as_dict=1)
if info.user_type=="Website User":
if self.info.user_type=="Website User":
frappe.local.cookie_manager.set_cookie("system_user", "no")
frappe.local.response["message"] = "No App"
else:
frappe.local.cookie_manager.set_cookie("system_user", "yes")
frappe.local.response['message'] = 'Logged In'
full_name = " ".join(filter(None, [info.first_name, info.last_name]))
frappe.response["full_name"] = full_name
frappe.local.cookie_manager.set_cookie("full_name", full_name)
frappe.response["full_name"] = self.full_name
frappe.local.cookie_manager.set_cookie("full_name", self.full_name)
frappe.local.cookie_manager.set_cookie("user_id", self.user)
frappe.local.cookie_manager.set_cookie("user_image", info.user_image or "")
frappe.local.cookie_manager.set_cookie("user_image", self.info.user_image or "")
def make_session(self, resume=False):
# start session
frappe.local.session_obj = Session(user=self.user, resume=resume)
frappe.local.session_obj = Session(user=self.user, resume=resume,
full_name=self.full_name, user_type=self.user_type)
# reset user if changed to Guest
self.user = frappe.local.session_obj.user
......@@ -175,7 +192,7 @@ class LoginManager:
return
from frappe.utils import now_datetime
current_hour = int(now_datetime().strftime('%H'))
current_hour = int(now_datetime(user=frappe.form_dict.get('usr')).strftime('%H'))
if login_before and current_hour > login_before:
frappe.throw(_("Login not allowed at this time"), frappe.AuthenticationError)
......@@ -185,7 +202,10 @@ class LoginManager:
def login_as_guest(self):
"""login as guest"""
self.user = 'Guest'
self.login_as("Guest")
def login_as(self, user):
self.user = user
self.post_login()
def logout(self, arg='', user=None):
......
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
......@@ -8,8 +8,10 @@ bootstrap client session
import frappe
import frappe.defaults
import frappe.widgets.page
from frappe.utils import get_gravatar
import frappe.desk.desk_page
from frappe.utils import get_gravatar, get_url
from frappe.desk.form.load import get_meta_bundle
from frappe.change_log import get_versions
def get_bootinfo():
"""build and return boot info"""
......@@ -43,15 +45,14 @@ def get_bootinfo():
bootinfo.hidden_modules = frappe.db.get_global("hidden_modules")
bootinfo.doctype_icons = dict(frappe.db.sql("""select name, icon from
tabDocType where ifnull(icon,'')!=''"""))
bootinfo.doctype_icons.update(dict(frappe.db.sql("""select name, icon from
tabPage where ifnull(icon,'')!=''""")))
bootinfo.single_types = frappe.db.sql_list("""select name from tabDocType where ifnull(issingle,0)=1""")
add_home_page(bootinfo, doclist)
add_allowed_pages(bootinfo)
bootinfo.page_info = get_allowed_pages()
load_translations(bootinfo)
add_timezone_info(bootinfo)
load_conf_settings(bootinfo)
load_print(bootinfo, doclist)
doclist.extend(get_meta_bundle("Page"))
# ipinfo
if frappe.session['data'].get('ipinfo'):
......@@ -65,8 +66,10 @@ def get_bootinfo():
if bootinfo.lang:
bootinfo.lang = unicode(bootinfo.lang)
bootinfo['versions'] = {k: v['version'] for k, v in get_versions().items()}
bootinfo.error_report_email = frappe.get_hooks("error_report_email")
bootinfo.default_background_image = get_url("/assets/frappe/images/ui/into-the-dawn.jpg")
return bootinfo
......@@ -75,9 +78,10 @@ def load_conf_settings(bootinfo):
for key in ['developer_mode']:
if key in conf: bootinfo[key] = conf.get(key)
def add_allowed_pages(bootinfo):
def get_allowed_pages():
roles = frappe.get_roles()
bootinfo.page_info = {}
page_info = {}
for p in frappe.db.sql("""select distinct
tabPage.name, tabPage.modified, tabPage.title
from `tabPage Role`, `tabPage`
......@@ -85,7 +89,7 @@ def add_allowed_pages(bootinfo):
and `tabPage Role`.parent = `tabPage`.name""" % ', '.join(['%s']*len(roles)),
roles, as_dict=True):
bootinfo.page_info[p.name] = {"modified":p.modified, "title":p.title}
page_info[p.name] = {"modified":p.modified, "title":p.title}
# pages where role is not set are also allowed
for p in frappe.db.sql("""select name, modified, title
......@@ -93,7 +97,9 @@ def add_allowed_pages(bootinfo):
(select count(*) from `tabPage Role`
where `tabPage Role`.parent=tabPage.name) = 0""", as_dict=1):
bootinfo.page_info[p.name] = {"modified":p.modified, "title":p.title}
page_info[p.name] = {"modified":p.modified, "title":p.title}
return page_info
def load_translations(bootinfo):
if frappe.local.lang != 'en':
......@@ -106,7 +112,7 @@ def get_fullnames():
concat(ifnull(first_name, ''),
if(ifnull(last_name, '')!='', ' ', ''), ifnull(last_name, '')) as fullname,
user_image as image, gender, email
from tabUser where ifnull(enabled, 0)=1""", as_dict=1)
from tabUser where ifnull(enabled, 0)=1 and user_type!="Website User" """, as_dict=1)
d = {}
for r in ret:
......@@ -116,15 +122,9 @@ def get_fullnames():
return d
def get_startup_js():
startup_js = []
for method in frappe.get_hooks().startup_js or []:
startup_js.append(frappe.get_attr(method)() or "")
return "\n".join(startup_js)
def get_user(bootinfo):
"""get user info"""
bootinfo.user = frappe.user.load_user()
bootinfo.user = frappe.get_user().load_user()
def add_home_page(bootinfo, docs):
"""load home page"""
......@@ -132,10 +132,10 @@ def add_home_page(bootinfo, docs):
return
home_page = frappe.db.get_default("desktop:home_page")
try:
page = frappe.widgets.page.get(home_page)
page = frappe.desk.desk_page.get(home_page)
except (frappe.DoesNotExistError, frappe.PermissionError):
frappe.message_log.pop()
page = frappe.widgets.page.get('desktop')
page = frappe.desk.desk_page.get('desktop')
bootinfo['home_page'] = page.name
docs.append(page)
......
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
......@@ -8,21 +8,38 @@ from frappe.utils.minify import JavascriptMinify
Build the `public` folders and setup languages
"""
import os, sys, frappe, json, shutil
from cssmin import cssmin
import os, frappe, json, shutil, re
# from cssmin import cssmin
app_paths = None
def setup():
global app_paths
pymodules = []
for app in frappe.get_all_apps(True):
try:
pymodules.append(frappe.get_module(app))
except ImportError: pass
app_paths = [os.path.dirname(pymodule.__file__) for pymodule in pymodules]
def bundle(no_compress, make_copy=False, verbose=False):
"""concat / minify js files"""
# build js files
setup()
make_asset_dirs(make_copy=make_copy)
build(no_compress, verbose)
def watch(no_compress):
"""watch and rebuild if necessary"""
setup()
import time
compile_less()
build(no_compress=True)
while True:
compile_less()
if files_dirty():
build(no_compress=True)
......@@ -61,8 +78,6 @@ def build(no_compress=False, verbose=False):
def get_build_maps():
"""get all build.jsons with absolute paths"""
# framework js and css files
pymodules = [frappe.get_module(app) for app in frappe.get_all_apps(True)]
app_paths = [os.path.dirname(pymodule.__file__) for pymodule in pymodules]
build_maps = {}
for app_path in app_paths:
......@@ -81,7 +96,7 @@ def get_build_maps():
source_paths.append(s)
build_maps[target] = source_paths
except Exception, e:
except Exception:
print path
raise
......@@ -118,14 +133,12 @@ def pack(target, sources, no_compress, verbose):
print "{0}: {1}k".format(f, int(len(minified) / 1024))
elif outtype=="js" and extn=="html":
# add to frappe.templates
content = data.replace("\n", " ").replace("'", "\'")
outtxt += """frappe.templates["{key}"] = '{content}';\n""".format(\
key=f.rsplit("/", 1)[1][:-5], content=content)
outtxt += html_to_js_template(f, data)
else:
outtxt += ('\n/*\n *\t%s\n */' % f)
outtxt += '\n' + data + '\n'
except Exception, e:
except Exception:
print "--Error in:" + f + "--"
print frappe.get_traceback()
......@@ -138,6 +151,16 @@ def pack(target, sources, no_compress, verbose):
print "Wrote %s - %sk" % (target, str(int(os.path.getsize(target)/1024)))
def html_to_js_template(path, content):
# remove whitespace to a single space
content = re.sub("\s+", " ", content).replace("'", "\'")
# strip comments
content = re.sub("(<!--.*?-->)", "", content)
return """frappe.templates["{key}"] = '{content}';\n""".format(\
key=path.rsplit("/", 1)[-1][:-5], content=content)
def files_dirty():
for target, sources in get_build_maps().iteritems():
for f in sources:
......@@ -149,3 +172,20 @@ def files_dirty():
else:
return False
def compile_less():
for path in app_paths:
less_path = os.path.join(path, "public", "less")
if os.path.exists(less_path):
for fname in os.listdir(less_path):
if fname.endswith(".less") and fname != "variables.less":
fpath = os.path.join(less_path, fname)
mtime = os.path.getmtime(fpath)
if fpath in timestamps and mtime == timestamps[fpath]:
continue
timestamps[fpath] = mtime
print "compiling {0}".format(fpath)
css_path = os.path.join(path, "public", "css", fname.rsplit(".", 1)[0] + ".css")
os.system("which lessc && lessc {0} > {1}".format(fpath, css_path))
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals, absolute_import
......
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
import os
import json
from semantic_version import Version
import frappe
from frappe.utils import cstr
def get_change_log(user=None):
if not user: user = frappe.session.user
last_known_versions = frappe._dict(json.loads(frappe.db.get_value("User", user, "last_known_versions") or "{}"))
current_versions = get_versions()
if not last_known_versions:
update_last_known_versions()
return []
change_log = []
for app, opts in current_versions.items():
from_version = last_known_versions.get(app, {}).get("version") or "0.0.1"
to_version = opts["version"]
if from_version != to_version:
app_change_log = get_change_log_for_app(app, from_version=from_version, to_version=to_version)
if app_change_log:
change_log.append({
"title": opts["title"],
"description": opts["description"],
"version": to_version,
"change_log": app_change_log
})
return change_log
def get_change_log_for_app(app, from_version, to_version):
change_log_folder = os.path.join(frappe.get_app_path(app), "change_log")
if not os.path.exists(change_log_folder):
return
from_version = Version(from_version)
to_version = Version(to_version)
# remove pre-release part
to_version.prerelease = None
major_version_folders = ["v{0}".format(i) for i in xrange(from_version.major, to_version.major + 1)]
app_change_log = []
for folder in os.listdir(change_log_folder):
if folder in major_version_folders:
for file in os.listdir(os.path.join(change_log_folder, folder)):
version = Version(os.path.splitext(file)[0][1:].replace("_", "."))
if from_version < version <= to_version:
file_path = os.path.join(change_log_folder, folder, file)
content = frappe.read_file(file_path)
app_change_log.append([version, content])
app_change_log = sorted(app_change_log, key=lambda d: d[0], reverse=True)
# convert version to string and send
return [[cstr(d[0]), d[1]] for d in app_change_log]
@frappe.whitelist()
def update_last_known_versions():
frappe.db.set_value("User", frappe.session.user, "last_known_versions", json.dumps(get_versions()), update_modified=False)
@frappe.whitelist()
def get_versions():
"""Get versions of all installed apps.
Example:
{
"frappe": {
"title": "Frappe Framework",
"version": "5.0.0"
}
}"""
versions = {}
for app in frappe.get_installed_apps(sort=True):
versions[app] = {
"title": frappe.get_hooks("app_title", app_name=app),
"description": frappe.get_hooks("app_description", app_name=app)
}
try:
versions[app]["version"] = frappe.get_attr(app + ".__version__")
except AttributeError:
versions[app]["version"] = '0.0.1'
return versions
### Version 5
Please see https://frappe.io/version-5
Changes include:
1. New Visual Design
1. Custom DocTypes
1. Email Accounts
1. Email Replies and Notifications
1. Print Format Builder
1. Document Sharing
This diff is collapsed.
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
......@@ -8,6 +8,12 @@ import frappe.model
import frappe.utils
import json, os
@frappe.whitelist()
def get_list(doctype, fields=None, filters=None, order_by=None,
limit_start=None, limit_page_length=20):
return frappe.get_list(doctype, fields=fields, filters=filters, order_by=order_by,
limit_start=limit_start, limit_page_length=limit_page_length, ignore_permissions=False)
@frappe.whitelist()
def get(doctype, name=None, filters=None):
if filters and not name:
......@@ -26,9 +32,19 @@ def get_value(doctype, fieldname, filters=None, as_dict=True, debug=False):
if not frappe.has_permission(doctype):
frappe.throw(_("Not permitted"), frappe.PermissionError)
if fieldname and fieldname.startswith("["):
try:
filters = json.loads(filters)
except ValueError:
# name passed, not json
pass
try:
fieldname = json.loads(fieldname)
return frappe.db.get_value(doctype, json.loads(filters), fieldname, as_dict=as_dict, debug=debug)
except ValueError:
# name passed, not json
pass
return frappe.db.get_value(doctype, filters, fieldname, as_dict=as_dict, debug=debug)
@frappe.whitelist()
def set_value(doctype, name, fieldname, value):
......@@ -36,7 +52,7 @@ def set_value(doctype, name, fieldname, value):
frappe.throw(_("Cannot edit standard fields"))
doc = frappe.db.get_value(doctype, name, ["parenttype", "parent"], as_dict=True)
if doc and doc.parent:
if doc and doc.parent and doc.parenttype:
doc = frappe.get_doc(doc.parenttype, doc.parent)
child = doc.getone({"doctype": doctype, "name": name})
child.set(fieldname, value)
......@@ -53,30 +69,26 @@ def set_value(doctype, name, fieldname, value):
return doc.as_dict()
@frappe.whitelist()
def insert(doclist):
if isinstance(doclist, basestring):
doclist = json.loads(doclist)
if isinstance(doclist, dict):
doclist = [doclist]
def insert(doc=None):
if isinstance(doc, basestring):
doc = json.loads(doc)
if doclist[0].get("parent") and doclist[0].get("parenttype"):
if doc.get("parent") and doc.get("parenttype"):
# inserting a child record
d = doclist[0]
doc = frappe.get_doc(d["parenttype"], d["parent"])
doc.append(d)
doc.save()
return [d]
parent = frappe.get_doc(doc.parenttype, doc.parent)
parent.append(doc)
parent.save()
return parent.as_dict()
else:
doc = frappe.get_doc(doclist).insert()
doc = frappe.get_doc(doc).insert()
return doc.as_dict()
@frappe.whitelist()
def save(doclist):
if isinstance(doclist, basestring):
doclist = json.loads(doclist)
def save(doc):
if isinstance(doc, basestring):
doc = json.loads(doc)
doc = frappe.get_doc(doclist).save()
doc = frappe.get_doc(doc).save()
return doc.as_dict()
@frappe.whitelist()
......@@ -85,14 +97,14 @@ def rename_doc(doctype, old_name, new_name, merge=False):
return new_name
@frappe.whitelist()
def submit(doclist):
if isinstance(doclist, basestring):
doclist = json.loads(doclist)
def submit(doc):
if isinstance(doc, basestring):
doc = json.loads(doc)
doclistobj = frappe.get_doc(doclist)
doclistobj.submit()
doc = frappe.get_doc(doc)
doc.submit()
return doclistobj.as_dict()
return doc.as_dict()
@frappe.whitelist()
def cancel(doctype, name):
......
This diff is collapsed.
......@@ -3,9 +3,18 @@ from frappe import _
def get_data():
return {
"Activity": {
"color": "#e67e22",
"icon": "icon-play",
"icon": "octicon octicon-pulse",
"label": _("Activity"),
"link": "activity",
"type": "page"
},
"Calendar": {
"color": "#2980b9",
"icon": "icon-calendar",
"icon": "octicon octicon-calendar",
"label": _("Calendar"),
"link": "Calendar/Event",
"type": "view"
......@@ -13,6 +22,7 @@ def get_data():
"Messages": {
"color": "#9b59b6",
"icon": "icon-comments",
"icon": "octicon octicon-comment-discussion",
"label": _("Messages"),
"link": "messages",
"type": "page"
......@@ -20,19 +30,31 @@ def get_data():
"To Do": {
"color": "#f1c40f",
"icon": "icon-check",
"icon": "octicon octicon-check",
"label": _("To Do"),
"link": "List/ToDo",
"doctype": "ToDo",
"type": "list"
},
"Notes": {
"color": "#95a5a6",
"doctype": "Note",
"icon": "icon-file-alt",
"icon": "octicon octicon-file-text",
"label": _("Notes"),
"link": "List/Note",
"type": "list"
},
"Website": {
"color": "#16a085",
"icon": "icon-globe",
"icon": "octicon octicon-globe",
"type": "module"
},
"Installer": {
"color": "#888",
"color": "#5ac8fb",
"icon": "icon-download",
"icon": "octicon octicon-cloud-download",
"link": "applications",
"type": "page",
"label": _("Installer")
......@@ -40,11 +62,13 @@ def get_data():
"Setup": {
"color": "#bdc3c7",
"icon": "icon-wrench",
"icon": "octicon octicon-settings",
"type": "module"
},
"Core": {
"color": "#589494",
"icon": "icon-cog",
"icon": "octicon octicon-file-binary",
"type": "module",
"system_manager": 1
},
......
from __future__ import unicode_literals
from frappe import _
from frappe.widgets.moduleview import add_setup_section
from frappe.desk.moduleview import add_setup_section
def get_data():
data = [
{
"label": _("Users and Permissions"),
"label": _("Users"),
"icon": "icon-group",
"items": [
{
......@@ -17,7 +17,13 @@ def get_data():
"type": "doctype",
"name": "Role",
"description": _("User Roles")
},
}
]
},
{
"label": _("Permissions"),
"icon": "icon-lock",
"items": [
{
"type": "page",
"name": "permission-manager",
......@@ -39,6 +45,13 @@ def get_data():
"icon": "icon-eye-open",
"name": "Permitted Documents For User",
"description": _("Check which Documents are readable by a User")
},
{
"type": "report",
"doctype": "DocShare",
"icon": "icon-share",
"name": "Document Share Report",
"description": _("Report of all document shares")
}
]
},
......@@ -93,60 +106,66 @@ def get_data():
]
},
{
"label": _("Workflow"),
"icon": "icon-random",
"label": _("Email"),
"icon": "icon-envelope",
"items": [
{
"type": "doctype",
"name": "Workflow",
"description": _("Define workflows for forms.")
"name": "Email Account",
"description": _("Add / Manage Email Accounts.")
},
{
"type": "doctype",
"name": "Workflow State",
"description": _("States for workflow (e.g. Draft, Approved, Cancelled).")
"name": "Email Alert",
"description": _("Setup Email Alert based on various criteria.")
},
{
"type": "doctype",
"name": "Workflow Action",
"description": _("Actions for workflow (e.g. Approve, Cancel).")
"name": "Standard Reply",
"description": _("Standard replies to common queries.")
},
]
},
{
"label": _("Email"),
"icon": "icon-envelope",
"label": _("Printing"),
"icon": "icon-print",
"items": [
{
"type": "doctype",
"name": "Outgoing Email Settings",
"description": _("Set outgoing mail server.")
"type": "page",
"label": "Print Format Builder",
"name": "print-format-builder",
"description": _("Drag and Drop tool to build and customize Print Formats.")
},
{
"type": "doctype",
"name": "Email Alert",
"description": _("Setup Email Alert based on various criteria.")
"name": "Print Settings",
"description": _("Set default format, page size, print style etc.")
},
{
"type": "doctype",
"name": "Standard Reply",
"description": _("Standard replies to common queries.")
"name": "Print Format",
"description": _("Customized HTML Templates for printing transactions.")
},
]
},
{
"label": _("Printing and Branding"),
"icon": "icon-print",
"label": _("Workflow"),
"icon": "icon-random",
"items": [
{
"type": "doctype",
"name": "Print Settings",
"description": _("Set default format, page size, print style etc.")
"name": "Workflow",
"description": _("Define workflows for forms.")
},
{
"type": "doctype",
"name": "Print Format",
"description": _("Customized HTML Templates for printing transctions.")
"name": "Workflow State",
"description": _("States for workflow (e.g. Draft, Approved, Cancelled).")
},
{
"type": "doctype",
"name": "Workflow Action",
"description": _("Actions for workflow (e.g. Approve, Cancel).")
},
]
},
......@@ -169,7 +188,13 @@ def get_data():
"type": "doctype",
"name": "Custom Script",
"description": _("Add custom javascript to forms.")
},
{
"type": "doctype",
"name": "DocType",
"description": _("Add custom forms.")
}
]
},
{
......
......@@ -27,16 +27,6 @@ def get_data():
"name": "Blogger",
"description": _("User ID of a blog writer."),
},
{
"type": "doctype",
"name": "Website Group",
"description": _("Web Site Forum Page."),
},
{
"type": "doctype",
"name": "Post",
"description": _("List of Web Site Forum's Posts."),
},
{
"type": "doctype",
"name": "Website Slideshow",
......@@ -85,8 +75,8 @@ def get_data():
},
{
"type": "doctype",
"name": "Website Page Permission",
"description": _("Define read, write, admin permissions for a Website Page."),
"name": "Website Theme",
"description": _("List of themes for Website."),
},
{
"type": "doctype",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment