Compare commits

...

747 Commits

Author SHA1 Message Date
mdipierro
cda35fd48a R-2.14.6 2016-05-09 19:19:07 -05:00
mdipierro
85c37af1f4 removed unwanted file 2016-05-09 19:11:08 -05:00
mdipierro
87935a45ba Merge branch 'master' of github.com:web2py/web2py 2016-05-09 00:24:29 -05:00
mdipierro
0692272991 going back to dal 16.03 to prepare for 2.14.6 2016-05-09 00:24:14 -05:00
mdipierro
c9f11c068c Merge pull request #1322 from ShySec/oneall_optimization
simplified oneall dname handling
2016-05-09 00:05:06 -05:00
mdipierro
54b0feeffb Merge pull request #1321 from ShySec/master
fixed timing attack in gluon.utils.compare
2016-05-09 00:04:39 -05:00
mdipierro
8666f993d1 Merge pull request #1320 from niphlod/enhancement/redis_scheduler
sync with main scheduler
2016-05-09 00:03:42 -05:00
kelson
822e68ac16 simplified oneall dname handling 2016-05-06 16:10:19 -04:00
kelson
292af5adc6 fixed timing attack in gluon.utils.compare 2016-05-06 14:14:32 -04:00
niphlod
c6d4fb8f38 sync with main scheduler 2016-05-05 21:36:51 +02:00
mdipierro
82d79e74c6 Merge pull request #1318 from leonelcamara/admin_lockout
Check if host is denied before verifying password
2016-05-04 13:30:14 -05:00
Leonel Câmara
944d8bd8f3 Check if host is denied before verifying password 2016-05-04 19:02:53 +01:00
mdipierro
33c1144e2e fixing merge issue 2016-05-04 09:29:30 -05:00
mdipierro
ca21bb0b9a added contributor Narendra Bhati(security) 2016-05-04 09:28:25 -05:00
mdipierro
a2b98cd6df Merge pull request #1317 from leonelcamara/test_week9
more tests for validators
2016-05-04 09:25:30 -05:00
mdipierro
51c3b633fe remove XSS attack in installing plugin, thanks Nerendra Bhati 2016-05-04 09:21:20 -05:00
mdipierro
1e74c332d0 Merge branch 'master' of github.com:web2py/web2py 2016-05-04 09:12:52 -05:00
mdipierro
4bd002aee9 fixed CSRF in admin enabled/disable. thanks Nerendra Bhati 2016-05-04 09:11:55 -05:00
Leonel Câmara
1b42fe6547 Fixes #1316 2016-05-03 19:17:58 +01:00
Leonel Câmara
810520b3f0 more tests for validators 2016-05-03 02:38:50 +01:00
mdipierro
af18582198 Merge pull request #1315 from niphlod/enhancement/scheduler
can now process tasks with huge_results
2016-05-02 10:16:38 -05:00
mdipierro
2d6ca49675 Merge pull request #1314 from chenl/issue_1310
issue#1310
2016-05-02 10:16:03 -05:00
mdipierro
db36e4380d Merge pull request #1308 from leonelcamara/test_week8
partial tests for appadmin, testing a bunch of other stuff in the pro…
2016-05-02 10:13:54 -05:00
niphlod
2031a43058 can now process tasks with huge_results
Added tests, too. Cleanups leftovers better, so fixes #1304
2016-05-01 22:01:49 +02:00
Chen Rotem Levy
07d764f3c6 issue#1310
undo PR#1194
2016-04-30 13:41:11 +03:00
Leonel Câmara
b8b63302f4 add test_appadmin to tests/__init__.py 2016-04-26 17:17:19 +01:00
Leonel Câmara
fa1af36adf partial tests for appadmin, testing a bunch of other stuff in the process 2016-04-26 04:31:22 +01:00
mdipierro
2fc1378399 Merge pull request #1307 from zvolsky/master
script for language files update has new param to update existing tra…
2016-04-25 20:32:24 -05:00
zvolsky
b6ee82bbde script for language files update has new param to update existing translations 2016-04-25 11:06:02 +02:00
mdipierro
8ed6736e82 Merge pull request #1306 from BuhtigithuB/improve/html-and-it-tests
improve html.py, new url_encode=True/False test, review/close #1279
2016-04-24 18:44:38 -05:00
mdipierro
99b083ad43 Merge pull request #1305 from leonelcamara/test_week7
100% coverage for recfile
2016-04-24 18:43:31 -05:00
Hardirc
c6b844a3e4 minor improve html.py, new url_encode=True/False test, review and close 1279 2016-04-24 09:47:57 -04:00
Leonel Câmara
c7bb69a0b0 consistent naming 2016-04-21 20:12:00 +01:00
Leonel Câmara
8b402b491c 100% coverage for recfile 2016-04-21 20:01:23 +01:00
mdipierro
735d79c211 latest pydal fixed connection issue 2016-04-19 22:45:49 -05:00
mdipierro
4177b4fe58 included fixes from dal 2016-04-19 11:42:24 -05:00
mdipierro
82aec9ba39 new fixes from Giovanni 2016-04-19 11:30:40 -05:00
Giovanni Barillari
dc28664270 Tracking pydal 85c530c 2016-04-19 17:41:29 +02:00
Giovanni Barillari
78bb8e9b26 Updated to latest pydal, fixed IS_IN_DB validator for new pydal 2016-04-19 17:24:09 +02:00
mdipierro
0a633236e5 pydal fixes, thanks Giovanni 2016-04-19 08:17:55 -05:00
mdipierro
42d1544478 new experimental dal 2016-04-18 21:28:27 -05:00
mdipierro
85819a5f83 Merge pull request #1299 from BuhtigithuB/improve/auth-tests
New Auth tests
2016-04-17 21:27:35 -05:00
mdipierro
9ca1c28db3 Merge pull request #1298 from BuhtigithuB/new/prettydate-test-suite
New test suite for prettydate() + fix wrong number of days for month
2016-04-17 21:27:18 -05:00
Hardirc
37fa90fbd2 .has_..., .add_..., .del_permission tests cases 2016-04-17 13:28:41 -04:00
Hardirc
2f0de8d8a0 New Auth tests & del_membership('role') api harmonization 2016-04-17 11:35:17 -04:00
Hardirc
70a0209e31 Reorder tests cases and make inventory + news tests 2016-04-16 21:33:24 -04:00
Hardirc
92b3c8f777 New Auth tests 2016-04-16 19:35:06 -04:00
Hardirc
d622a8aa66 New test suite for prettydate() + fix wrong number of days for month 2016-04-16 14:54:34 -04:00
mdipierro
2a2771c4cc Merge pull request #1297 from BuhtigithuB/update/markdown2-contrib
Update markdown2.py 2.2.4 -> 2.3.1 (latest release)
2016-04-15 22:10:22 -05:00
mdipierro
4fbd612d1b Merge pull request #1296 from BuhtigithuB/enhancement/pep8-tools-py
Enhancement tools.py PEP8
2016-04-15 22:10:12 -05:00
mdipierro
190c77e0e7 Merge pull request #1295 from BuhtigithuB/refactor/auth-tools-tests
Refactor Auth tests, new test, old implementation commented for now
2016-04-15 22:09:44 -05:00
Richard Vézina
4fa8b3ed67 Update markdown2.py 2.2.4 -> 2.3.1 (latest release) 2016-04-15 12:33:04 -04:00
Richard Vézina
f109be363d Enhancement tools.py PEP8 2016-04-14 11:17:27 -04:00
Hardirc
b7cc1b2db5 Refactor Auth tests, new tests, old implementation commented for now 2016-04-14 03:01:15 -04:00
mdipierro
81d0291ce2 R-2.14.5 2016-04-13 22:22:39 -05:00
mdipierro
894ff3c140 Merge pull request #1294 from leonelcamara/fix_1274
fixes #1274
2016-04-13 22:16:46 -05:00
mdipierro
216ce5507c Merge pull request #1293 from leonelcamara/fix_1266
fixes #1266 and adds tests to make sure it doesn't happen again
2016-04-13 22:15:53 -05:00
mdipierro
068aecff93 Merge pull request #1292 from BuhtigithuB/add-more-html-test
Some more coverage for XML() and DIV()
2016-04-13 22:15:22 -05:00
Leonel Câmara
59cbe99347 pep8 and force travis to rebuild 2016-04-14 04:13:18 +01:00
Leonel Câmara
bdbc053285 fixes #1274 2016-04-14 03:57:20 +01:00
Leonel Câmara
d746d43be5 pep8 and make travis run again 2016-04-14 01:21:23 +01:00
Leonel Câmara
9a3e73031b fixes #1266 and adds tests to make sure it doesn't happen again 2016-04-14 01:02:25 +01:00
Richard Vézina
0468c16bc2 Some more coverage for XML() and DIV() 2016-04-13 11:44:16 -04:00
mdipierro
8c5858b6b7 fixed merge issue 2016-04-13 08:41:09 -05:00
mdipierro
6400e28a85 fixed stupid 2016-04-13 08:40:19 -05:00
mdipierro
3e46d50aa1 Merge pull request #1290 from carpaIdea/patch-3
box-sizing best practice
2016-04-13 08:33:29 -05:00
mdipierro
cb94fde80b Merge pull request #1289 from carpaIdea/patch-2
<main> semantic element IE fix
2016-04-13 08:30:20 -05:00
mdipierro
98593eefce Merge pull request #1291 from leonelcamara/test_week6
Test emails with alternative text and html
2016-04-13 08:27:33 -05:00
Leonel Câmara
4bbfe70927 install a more modern pypy version 2016-04-13 14:17:30 +01:00
Leonel Câmara
02a0d1c9b0 minor reorder 2016-04-13 14:01:36 +01:00
Leonel Câmara
2bf0ad9268 test emails with alternative text and html 2016-04-13 14:00:33 +01:00
carpaIdea
2e63b7637a box-sizing best practice
This code was updated to match new box-sizing best practices. Also prefixes are pretty much dead. (quote from http://www.paulirish.com/2012/box-sizing-border-box-ftw/).

More info on https://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/
2016-04-13 00:53:42 +02:00
mdipierro
67485d16a5 R-2.14.4 2016-04-12 16:21:05 -05:00
carpaIdea
a9c5cf3072 <main> semantic element IE fix
Some versions of Internet Explorer consider the <main> semantic element as "unknown". So its initial value is "inline".If we want the behavior of the <main> element to be the same as in other browsers, we must set it explicitly as a "block."
2016-04-12 23:07:27 +02:00
mdipierro
eba8ad4b55 fixed CHANGELOG 2016-04-12 15:45:54 -05:00
mdipierro
4ed6fb7ed9 Merge pull request #1288 from carpaIdea/patch-1
Missing <!DOCTYPE html>
2016-04-12 15:44:19 -05:00
carpaIdea
294c67194f Missing <!DOCTYPE html>
Of course if there is not any intentional reason to turn on "quirks mode" in browsers.

https://developer.mozilla.org/en-US/docs/Web/CSS/Common_CSS_Questions#Why_doesn't_my_CSS_which_is_valid_render_correctly
https://developer.mozilla.org/it/docs/Quirks_Mode_and_Standards_Mode
2016-04-12 22:24:30 +02:00
mdipierro
70f793b422 Merge pull request #1287 from leonelcamara/test_week6
Test week6
2016-04-12 11:14:14 -05:00
Leonel Câmara
9552d9d6d0 fixed sort=True test 2016-04-12 16:28:33 +01:00
Leonel Câmara
9ead66b6db test IS_IN_DB label is a Field and self.sort = True 2016-04-12 16:00:33 +01:00
Leonel Câmara
00c65ad160 Complete coverage for Mail.Attachment 2016-04-12 15:28:48 +01:00
Leonel Câmara
b5c8b3ad25 closes #1286 2016-04-12 15:10:14 +01:00
mdipierro
5ca65d55d2 Merge pull request #1284 from BuhtigithuB/more-markmin-pep8
More markmin pep8
2016-04-11 13:38:54 -05:00
mdipierro
3f200fdc22 Merge pull request #1283 from leonelcamara/grid_issues
closes #1188
2016-04-11 13:38:37 -05:00
Hardirc
409c973dc4 Enhance markmin2pdf.py PEP8 2016-04-10 09:36:06 -04:00
Hardirc
59a194842d Enhance markmin2latex.py PEP8 2016-04-10 09:34:29 -04:00
Leonel Câmara
ee8b11db2c closes #1188 2016-04-10 12:08:25 +01:00
mdipierro
8ef04ac425 Merge pull request #1282 from BuhtigithuB/Feature/heading-anchor
Feature/heading anchor
2016-04-09 18:39:39 -05:00
mdipierro
83cf098c07 fixed stupid.css and impersonate 2016-04-09 10:30:31 -05:00
mdipierro
70b41fa15e Merge pull request #1280 from BuhtigithuB/pep8-gluon-html-py
Enhance gluon/html.py PEP8
2016-04-08 23:37:54 -05:00
mdipierro
56af81f247 Merge pull request #1278 from BuhtigithuB/pep8-welcome
Pep8 welcome
2016-04-08 23:37:32 -05:00
mdipierro
7fd30d8360 Merge pull request #1276 from BuhtigithuB/Improve/web2py-com-display
Improve/web2py com display
2016-04-08 23:35:43 -05:00
mdipierro
e1aefa2307 Merge pull request #1275 from BuhtigithuB/Improve/gluon-tools-py
PEP8 Recaptcha/2 docstring
2016-04-08 23:35:10 -05:00
mdipierro
7a2316ec9a Merge pull request #1260 from BuhtigithuB/add-test-sqlform
SQLFORM() basic check
2016-04-08 23:34:51 -05:00
Hardirc
e48e47beb2 Enhance markmin2html.py contrib PEP8 2016-04-08 22:12:43 -04:00
Hardirc
864c308246 Enhance gluon/html.py PEP8 2016-04-08 21:11:25 -04:00
Hardirc
994f3e7ae4 Enhance welcome menu.py PEP8 2016-04-08 20:17:35 -04:00
Hardirc
1d2f74440e Enhance welcome routes.example.py PEP8 2016-04-08 20:13:58 -04:00
Hardirc
704ceec16f Enhance welcome controllers/default.py PEP8 2016-04-08 20:13:30 -04:00
Hardirc
038e25c259 Enhance welcome db.py PEP8 2016-04-08 20:05:21 -04:00
Richard Vézina
c3aa02b3ce Improve welcome (web2py.com) site aesthetic 2016-04-08 15:16:58 -04:00
Richard Vézina
5cc4487d8c Improve PEP8 download.html 2016-04-08 14:17:56 -04:00
Richard Vézina
d50e6aab6b Improve default.py PEP8 2016-04-08 11:52:09 -04:00
Richard Vézina
1d21f45e3e PEP8 Recaptcha/2 docstring 2016-04-07 10:19:57 -04:00
mdipierro
99a323c7ad Merge pull request #1272 from BuhtigithuB/new-logout-bare
New logout_bare() for shell logout and refactor test using it
2016-04-07 09:17:19 -05:00
Hardirc
e0d86462c8 New logout_bare() for shell logout and refactor test using it 2016-04-06 22:46:24 -04:00
mdipierro
ff0d10ac4f Merge pull request #1271 from leonelcamara/delete_unused_reserved
delete unused reserved_sql_keywords.py because the DAL uses this one …
2016-04-06 20:58:05 -05:00
mdipierro
eee7be75c8 Merge pull request #1265 from BuhtigithuB/improve-tools-tests-some-more
Improve tools tests some more
2016-04-06 20:57:30 -05:00
mdipierro
3c69716672 Merge pull request #1270 from leonelcamara/test_week5b
Test Mail.Attachment sending test_tools.py itself
2016-04-06 20:57:06 -05:00
Leonel Câmara
ad4b0eee54 delete unused reserved_sql_keywords.py because the DAL uses this one pydal/contrib/reserved_sql_keywords.py 2016-04-06 23:06:57 +01:00
Richard Vézina
0128ce3a93 Make test_login_bare() works, new test_impersonate() 2016-04-06 16:58:58 -04:00
Leonel Câmara
0629df71ef Test Mail.Attachment sending test_tools.py itself 2016-04-06 20:04:21 +01:00
mdipierro
4d1a4c48e6 Merge pull request #1268 from mbelletti/fix/cas_login
Fix #1267 cas_login
2016-04-06 13:49:28 -05:00
Massimiliano Belletti
2ffdb716cd Fix #1267 cas_login 2016-04-06 17:06:23 +02:00
mdipierro
40f04de9d2 fixed scripts/setup-web2py-nginx-uwsgi-ubuntu.sh 2016-04-06 09:20:13 -05:00
mdipierro
52615fbca7 Merge pull request #1263 from niphlod/tests/scheduler
initial tests for scheduler.py, plus a minor fix for JobGraph
2016-04-05 17:00:00 -05:00
niphlod
6abb78c559 initial tests for scheduler.py 2016-04-04 22:58:42 +02:00
Hardirc
db701ffea8 correct unproperly generated SQLFORM methods and basic tests 2016-04-03 16:24:13 -04:00
mdipierro
0804c28331 Merge pull request #1259 from BuhtigithuB/new-test-sqlform
let start testing sqlhtml.py
2016-04-02 15:02:02 -05:00
mdipierro
24bc51447c Merge pull request #1257 from BuhtigithuB/improve-tools-tests
Improve tools tests
2016-04-02 15:00:41 -05:00
mdipierro
ccbbdc2493 Merge branch 'leonelcamara-prettier_examples' 2016-04-02 14:59:23 -05:00
mdipierro
d94e8415c7 reverted stupid 2016-04-02 14:57:36 -05:00
mdipierro
0a62e86156 Merge pull request #1254 from leonelcamara/test_week4b
Seriously increase template.py coverage
2016-04-02 14:53:39 -05:00
mdipierro
5744c06f59 Merge pull request #1253 from leonelcamara/test_week4
More test coverage for validators.py
2016-04-02 14:52:42 -05:00
mdipierro
947f92774b Merge pull request #1252 from BuhtigithuB/improve-test-chache
Improve test chache
2016-04-02 14:52:26 -05:00
Hardirc
4001407add let start testing sqlhtml.py 2016-04-02 15:49:18 -04:00
mdipierro
46ffaa6aea improved search form 2016-04-02 14:48:03 -05:00
mdipierro
ba2be80080 updated stupic.css and suport page 2016-04-02 14:35:28 -05:00
Richard Vézina
3a9221a2b9 Reach fully some partially hit lines 2016-03-31 17:00:50 -04:00
Richard Vézina
e0eb425223 Little improvement of tools.py 2016-03-31 16:25:55 -04:00
Richard Vézina
f7ad31f066 Refactor TestAuth() with setUp() and add test case 2016-03-31 16:25:02 -04:00
Leonel Câmara
d0f6ef4783 made stuff prettier
added myself to the contributor list :P
2016-03-31 00:29:28 +01:00
Richard Vézina
104d616cb9 Reorder test case and make inventory of what missing 2016-03-30 16:32:37 -04:00
Richard Vézina
a8703270da PEP8 enhancement 2016-03-30 16:20:02 -04:00
Leonel Câmara
ad57c3c613 test block extend, super, delimiters, etc. 2016-03-30 02:33:29 +01:00
Leonel Câmara
5c292640ba Complete coverage for IS_IN_SET
Removed unreachable code in IS_IN_SET
        if failures and self.theset:
            if self.multiple and (value is None or value == '')
It's impossible to have *failures* and have value be None or '' at the same time
2016-03-28 14:47:58 +01:00
Leonel Câmara
5cbf381a2c More test coverage for validators.py
Fixed a bug in IS_EMAIL throwing exceptions when asked to validate anything other than a string which was problematic for ANY_OF
Fixed a bug in ANY_OF.formatter where it was trying to format with a validator that didn't validate
2016-03-27 14:23:24 +01:00
mdipierro
a0bbd7885a Merge branch 'master' of github.com:web2py/web2py 2016-03-26 17:56:23 -05:00
mdipierro
c2ce90a1fe R-2.14.3 2016-03-26 17:55:52 -05:00
mdipierro
197b018534 fixed stupid.css again 2016-03-26 17:54:11 -05:00
Hardirc
9ac1e7188f tests inventory and reordering + PEP8 enhancement 2016-03-26 13:19:29 -04:00
Hardirc
58a8ba067c cache.py PEP8 enhancement 2016-03-26 13:11:27 -04:00
mdipierro
060aeff867 Merge pull request #1251 from BuhtigithuB/add-even-more-test-over-html-py
More coverage and some PEP8 enhencement to html.py
2016-03-26 00:00:43 -05:00
mdipierro
d4572c5f38 Merge branch 'master' of github.com:web2py/web2py 2016-03-25 23:57:24 -05:00
mdipierro
46dc83a1bb synced to latest stupid.css 2016-03-25 23:57:13 -05:00
Hardirc
f414356b67 More coverage and some PEP8 enhencement to html.py 2016-03-26 00:44:28 -04:00
mdipierro
460a017bab Merge pull request #1250 from Pierre-Thibault/strange_lines
Nonsense sys.exc_info parameter of traceback.format_exc calls.
2016-03-25 18:07:25 -05:00
mdipierro
0b966d7c0a Merge pull request #1249 from leonelcamara/patch-1
imageutils.py missing comma bug
2016-03-25 18:06:56 -05:00
Pierre Thibault
d2d16d4081 I was forgetting line 200. 2016-03-25 15:54:01 -04:00
Pierre Thibault
ebcf6e5671 Nonsense sys.exc_info parameter of traceback.format_exc calls. 2016-03-25 15:48:58 -04:00
Leonel Câmara
778cc3902b Update imageutils.py
missing comma
2016-03-25 12:45:33 +00:00
mdipierro
32650f0cbf R-2.14.2 2016-03-24 17:44:41 -05:00
mdipierro
8f8ef4cca5 fixed sessions for long keys 2016-03-24 16:58:04 -05:00
mdipierro
c9e92fc686 restored pickles in sessions 2016-03-24 16:50:02 -05:00
mdipierro
0820926b50 more secure sessions in cookies using json 2016-03-24 16:46:51 -05:00
mdipierro
1856c9dc7a fixed changelog 2016-03-24 12:33:43 -05:00
mdipierro
973bb4a16f R-2.14.1 2016-03-24 12:20:58 -05:00
mdipierro
2fa54f069c Merge pull request #1246 from BuhtigithuB/improve-test-validators
Improve PEP8 just a bit + more coverage
2016-03-24 12:10:17 -05:00
mdipierro
b11260d2e2 Merge pull request #1244 from mbelletti/fix/admin_enable_disable_apps
Fix missing w2p_ajax_disable_with_message #1234
2016-03-24 12:10:01 -05:00
mdipierro
a6a9b004ea Merge pull request #1235 from kjkuan/avoid-query-per-row-for-virtual-fields
Avoid issuing a separate sql query for each row in sqlform grid search results, for virtual fields
2016-03-24 12:09:36 -05:00
mdipierro
6ed204301d ok dropped backward compatibility in redis_*.py 2016-03-24 12:08:43 -05:00
Richard Vézina
52392a10ae Improve PEP8 just a bit + more coverage 2016-03-24 10:44:37 -04:00
Jack Kuan
6d68a40ddf Fix to work in cases, in which the query for the grid is not a join. 2016-03-24 10:25:37 -04:00
Jack Kuan
51bf802978 When deriving the value for a virtual field in a sqlform grid,
avoid issuing a separate sql query for each row found in the search
results.
2016-03-24 10:25:37 -04:00
Massimiliano Belletti
34267b7673 Fix missing w2p_ajax_disable_with_message #1234 2016-03-24 11:17:59 +01:00
mdipierro
26eb5e6f38 Merge pull request #1242 from BuhtigithuB/fix-assert-raise-test-html
fix some assertRaises leave commented + more coverage
2016-03-24 03:03:24 -05:00
mdipierro
13964c2c9b Merge pull request #1241 from gi0baro/master
Updated pyDAL to 16.03
2016-03-24 03:03:03 -05:00
mdipierro
6a876fffc2 Merge pull request #1240 from BuhtigithuB/add-utils-test
test_utils inventory and new tests
2016-03-24 03:02:50 -05:00
mdipierro
cd7850cc36 Merge pull request #1239 from BuhtigithuB/rework-fileutils-tests
rework test_fileutils.py mostly
2016-03-24 03:02:34 -05:00
Hardirc
e4705dd48a fix some assertRaises leave commented + more coverage 2016-03-24 03:09:47 -04:00
Richard Vézina
2ef079289b test_utils inventory and new tests 2016-03-24 01:59:39 -04:00
mdipierro
76e95a9f1c edited CHANGELOG 2016-03-23 19:32:23 -05:00
mdipierro
4c5664f701 backward compatible syntax for redis 2016-03-23 19:14:37 -05:00
mdipierro
cafba3fbe2 requires 2.14.1 2016-03-23 18:52:40 -05:00
Giovanni Barillari
8cb6678505 Updated pyDAL to 16.03 2016-03-24 00:38:48 +01:00
Richard Vézina
9fabfaac96 rework test_fileutils.py mostly 2016-03-23 14:32:14 -04:00
mdipierro
797ade202f Merge pull request #1238 from BuhtigithuB/add-more-test-over-html-py
BEAUTIFY, MENU, MARKMIN and ASSIGNJS basic tests and attempt ASSIGNJS…
2016-03-23 11:34:58 -05:00
Hardirc
dda81d1b95 SELECT('Option 1', 'Option 2') what else... 2016-03-23 00:25:56 -04:00
Hardirc
13ed29ffc3 OPTGROUP with OPTION 2016-03-23 00:18:17 -04:00
Hardirc
785276d294 some more corner cases for SELECT 2016-03-23 00:16:27 -04:00
Hardirc
52f634cb58 some more corner cases for TEXTAREA and commented DIV SyntaxError 2016-03-22 23:50:23 -04:00
Hardirc
f921b24a95 SELECT corner cases with option, multiple and selected 2016-03-22 23:25:37 -04:00
Hardirc
753c54dbfc HTML corner case for doctype=CustomDocType 2016-03-22 23:11:45 -04:00
Hardirc
89cf314358 XHTML corner tests for doctype=None/strict/transitional/frameset/xmlns 2016-03-22 22:47:59 -04:00
Hardirc
9299ecb64d HTML corner tests for doctype=stric/transitional/frameset/html5/None 2016-03-22 22:40:06 -04:00
Hardirc
94afe61477 BEAUTIFY, MENU, MARKMIN and ASSIGNJS basic tests and attempt ASSIGNJS documentation 2016-03-22 22:27:21 -04:00
mdipierro
a22f56ca0c removed unwanted print statements 2016-03-22 17:55:29 -05:00
mdipierro
656c490a21 Merge pull request #1232 from BuhtigithuB/improve-grib-button-display
a space between grid button icon and text is much more beautiful
2016-03-22 17:15:25 -05:00
mdipierro
8859ef04d3 Merge pull request #1231 from leonelcamara/test_week3b
tests for basic Mail functionality
2016-03-22 17:15:06 -05:00
mdipierro
5cf835d856 fixed session_cookie_key leak 2016-03-21 17:25:16 -05:00
mdipierro
6a569bf56e restored some of the deleted files 2016-03-21 10:37:36 -05:00
mdipierro
bd6115ad62 fixed Host header vulnerability #1196 2016-03-21 01:15:46 -05:00
Hardirc
3a265e3111 a space between grid button icon and text is much more beautiful 2016-03-20 14:05:40 -04:00
Leonel Câmara
78fc14df81 minor - pep8 and naming consistency 2016-03-20 12:46:26 +00:00
Leonel Câmara
4311820494 tests for basic Mail functionality 2016-03-20 12:33:38 +00:00
mdipierro
d1094e7b0c 2.14.1.beta 2016-03-19 17:16:01 -05:00
mdipierro
dbbbd44642 fixed space in bootstrap forms 2016-03-19 17:10:44 -05:00
mdipierro
fa9d1ccb8b fixed color or calendar popup 2016-03-19 17:05:43 -05:00
mdipierro
e6fad4f007 fixed default validators 2016-03-19 17:00:35 -05:00
mdipierro
23292754e3 fixed gae logging issue 2016-03-19 15:10:19 -05:00
mdipierro
dcd7f8b46c no more copy of the logfile, thanks Luca 2016-03-19 14:29:01 -05:00
mdipierro
7fd67c4e2e fixed default validators ofr string and boolean 2016-03-19 14:15:08 -05:00
mdipierro
ec3ae8211f possibly fixed #1162, validation of required notnull fields, hope this does not break something else 2016-03-19 13:39:27 -05:00
mdipierro
e8c0e0df92 #1192 again, going it the way Anthony suggests 2016-03-19 13:24:06 -05:00
mdipierro
7f9262f8f8 partially addressed issue #1192, comments there 2016-03-19 13:10:23 -05:00
mdipierro
11da1ed19a fixed issue #1206, translate T.M 2016-03-19 13:02:45 -05:00
mdipierro
9735477c35 requires version 2016-03-19 12:05:19 -05:00
mdipierro
f6f946f867 Merge pull request #1230 from leonelcamara/test_week3
test_IS_IMAGE and more
2016-03-19 11:29:58 -05:00
Leonel Câmara
8683b0680d add test for something that is NOT an image 2016-03-19 14:55:16 +00:00
Leonel Câmara
fbb5776432 test_IS_IMAGE
Removed unused and undocumented IS_IN_SUBSET
Fixed _options IS_EMPTY_OR not passing arguments to the other options method
Some tests for formatters
2016-03-19 12:52:48 +00:00
mdipierro
92b4bc4f94 fixed #778 PRE(repr()) in admin, thanks Simone 2016-03-19 04:08:33 -05:00
mdipierro
d886bf759e removed lots of junk from scripts folder 2016-03-19 04:02:22 -05:00
mdipierro
d5d25e8110 jquery 1.12.2 2016-03-18 20:49:19 -05:00
mdipierro
86c70df1e7 updated style and spacing 2016-03-18 20:47:59 -05:00
mdipierro
b6d923753a Merge pull request #1228 from cvaroqui/master
LDAP auth login method enhancements
2016-03-18 20:33:56 -05:00
mdipierro
d4cad7634c Merge pull request #1227 from BuhtigithuB/update-feedparser-contrib
Update feedparser.py 5.1.3 -> 5.2.1
2016-03-18 20:33:24 -05:00
mdipierro
45c28b1d76 Merge pull request #1226 from BuhtigithuB/patch-1
Delete obsolete comment left behind
2016-03-18 20:32:39 -05:00
mdipierro
b978bb90de Merge pull request #1225 from BuhtigithuB/pep8-test-web
Improve test_web.py PEP8
2016-03-18 20:32:16 -05:00
mdipierro
e76ecec14f Merge pull request #1224 from BuhtigithuB/pep8-html-py
Improve PEP8
2016-03-18 20:31:15 -05:00
mdipierro
8ce528327c Merge pull request #1164 from BuhtigithuB/fix/flash-w2p-flash
flash -> w2p_flash
2016-03-18 20:26:33 -05:00
mdipierro
fe0e23f4b9 Merge pull request #1223 from BuhtigithuB/add-missing-helpers-test
Add missing helpers test
2016-03-18 20:25:42 -05:00
mdipierro
e05da97b1d Merge branch 'master' of github.com:web2py/web2py 2016-03-18 19:38:22 -05:00
mdipierro
5290308dea global options are back 2016-03-18 19:37:46 -05:00
Christophe Varoqui
5817a1893b LDAP auth login method enhancements
1/
Allow user to pass a group mapping in manage_groups=True mode.
A group mapping is a structure like:

{
  "ldap_grp1": ["web2py_grp1", "web2py_grp2"],
  "ldap_grp2": ["ldap_grp2", "web2py_grp3"],
}

After fetching the ldap user's ldap groups, the list entries are
translated, before janitoring the auth_group and auth_membership
tables.

2/
Allow to define a callback to execute if the auth_group or
auth_membership tables are changed.

Typical use-case are cache flushing and app-driven replication.
2016-03-18 21:24:08 +01:00
Richard Vézina
aa2e302936 Update feedparser.py 5.1.3 -> 5.2.1 2016-03-18 12:04:27 -04:00
Hardirc
d02755eac2 add basic tests for html.py 2016-03-17 11:57:08 -04:00
BuhtigithuB
d037eaab44 Delete obsolete comment left behind
Comment at L111 :
         # COMMENTED BECAUSE FAILS BUT WHY?

Seems left behind and not useful anymore
2016-03-16 16:58:24 -04:00
Richard Vézina
9aa5995924 Improve test_web.py PEP8 2016-03-16 16:43:24 -04:00
Richard Vézina
a981ca52e8 Improve PEP8 2016-03-16 09:38:26 -04:00
mdipierro
327c40cd17 Merge pull request #1218 from leonelcamara/test_week2
Tests for IS_IN_DB, IS_NOT_IN_DB, IS_URL (also tests IS_HTTP_URL IS_G…
2016-03-15 11:54:25 -05:00
mdipierro
f9745e8a63 Merge pull request #1217 from niphlod/fix/redis_docstrings
fixes just docstrings about usage
2016-03-15 11:53:44 -05:00
mdipierro
51ce35c4e5 Merge pull request #1216 from BuhtigithuB/improve-rocket-test
create test_rocket.py with TODO inside about pathoc tests
2016-03-15 11:53:29 -05:00
mdipierro
0f7e4d774b Merge pull request #1215 from BuhtigithuB/improve-helper-test
Improve helper test
2016-03-15 11:53:11 -05:00
Richard Vézina
6e6612a57d add a todo about remain test() which may be deleted 2016-03-15 12:41:08 -04:00
Richard Vézina
83a3149849 Order tests in test_html.py todo for missing test + add many missing tests 2016-03-15 12:40:13 -04:00
Leonel Câmara
98d33bdded Tests for IS_IN_DB, IS_NOT_IN_DB, IS_URL (also tests IS_HTTP_URL IS_GENERIC_URL) 2016-03-14 23:59:08 +00:00
mdipierro
f370187332 removed double json.loads(body), thanks Simone 2016-03-14 18:03:54 -05:00
niphlod
1b15b0c6dc fixes just docstrings about usage 2016-03-14 23:32:53 +01:00
mdipierro
507c3d6c33 fixed typo 2016-03-14 15:20:08 -05:00
mdipierro
e62069c8b7 another error due to removing global settings from request 2016-03-14 15:13:10 -05:00
mdipierro
d94ea6b295 simplified beautify example 2016-03-14 15:08:18 -05:00
mdipierro
9533978b37 fixed error in previous commit 2016-03-14 14:57:21 -05:00
mdipierro
9706d125b4 DO NOT LEAK GLOBALS SETTINGS INTO request object 2016-03-14 14:52:41 -05:00
Richard Vézina
01aa9de919 create test_rocket.py with TODO inside about pathoc tests 2016-03-14 15:28:50 -04:00
Richard Vézina
55994c489b Improve test naming convention test_ 2016-03-14 15:09:33 -04:00
Richard Vézina
983627daa4 Improve PEP8 test_html.py 2016-03-14 15:02:40 -04:00
mdipierro
7c299936e4 plugins link broken 2016-03-14 13:57:59 -05:00
mdipierro
df55f52d8f fixed #1187 Field(.)Virtual typo, thanks RekGRpth 2016-03-14 12:45:01 -05:00
mdipierro
c81f1fd6c8 reverting previous commit 2016-03-14 12:34:09 -05:00
mdipierro
f15dd4b6e5 fixed #1204, updating session when add_membership 2016-03-14 12:32:34 -05:00
mdipierro
e9e61cbca4 fixed #1213, custom password field name 2016-03-14 12:27:37 -05:00
mdipierro
700821e372 Merge pull request #1209 from zvolsky/transl_update_script
new script to update untranslated messages from other language file
2016-03-14 12:18:05 -05:00
mdipierro
1d04f8837e resorted tests as suggested by BuhtigithuB 2016-03-14 12:16:52 -05:00
mdipierro
a375e047e9 Leonel new tests gluon/tests/test_validators.py 2016-03-14 12:04:47 -05:00
mdipierro
fe6b222aaf Merge pull request #1212 from BuhtigithuB/improve-validators-test
Order tests to match validators.py and flag missing tests
2016-03-14 11:54:18 -05:00
mdipierro
0b5bb9b996 Merge pull request #1210 from zvolsky/nginx_uwsgi
nginx/ubuntu deploy script: added uWSGI Emperor configuration
2016-03-14 11:52:49 -05:00
mdipierro
be4df0dee7 Merge pull request #1208 from zvolsky/czech_translation
updated czech translation (in admin and welcome)
2016-03-14 11:51:10 -05:00
mdipierro
d877e8b6d0 Merge pull request #1207 from niphlod/fix/redis_scheduler
fixes the same bugs reported in #1191 for the "standard" scheduler
2016-03-14 11:50:49 -05:00
Richard Vézina
2531c2c640 Improve PEP8 2016-03-10 22:09:38 -05:00
Richard Vézina
eca300af32 Order tests to match validators.py and flag missing tests 2016-03-10 21:56:46 -05:00
zvolsky
43c60df371 nginx/ubuntu deploy script: added uWSGI Emperor configuration 2016-03-10 10:20:36 +01:00
zvolsky
cdac608efc new script to update untranslated messages from other language file 2016-03-10 09:48:04 +01:00
zvolsky
3311486b14 updated czech translation (in admin and welcome) 2016-03-10 09:35:18 +01:00
niphlod
038d0d17a4 fixes the same bugs reported in #1191 for the "standard" scheduler 2016-03-10 00:01:39 +01:00
mdipierro
3999fd80f8 removed unwanted icons 2016-03-09 12:41:12 -06:00
mdipierro
2db3975a32 social icons 2016-03-09 12:37:15 -06:00
mdipierro
ebe3434a86 fixed commit error 2016-03-09 11:54:27 -06:00
mdipierro
b487583f92 admin2 - experimental 2016-03-09 11:53:07 -06:00
mdipierro
702e7cbea2 added missing file 2016-03-09 11:50:48 -06:00
mdipierro
18a901cce4 fixed buttons in quick examples 2016-03-09 09:44:51 -06:00
mdipierro
f23115cb9c better spacing and buttons examples 2016-03-09 09:35:01 -06:00
mdipierro
ea5e86e11e powered by fixed 2016-03-09 09:25:52 -06:00
mdipierro
db223dc70a examples in stupid.css 2016-03-09 09:24:47 -06:00
mdipierro
bcc4ae2ec6 remporarily addressing issue #1203, thanks Simone 2016-03-08 17:22:02 -06:00
mdipierro
4b81f721ac Merge branch 'master' of github.com:web2py/web2py 2016-03-08 16:44:05 -06:00
mdipierro
66f231eb4b Merge pull request #1193 from CzechErface/master
Fixed a bug whereby calling 'delete_record()' on a row object caused …
2016-03-08 16:39:54 -06:00
mdipierro
5fc9517803 Merge pull request #1194 from chenl/master
invalid view for purely compiled app
2016-03-08 16:38:34 -06:00
mdipierro
98294e0c69 Merge pull request #1199 from boriscougar/master
Update imageutils.py
2016-03-08 16:37:20 -06:00
mdipierro
5e28112eda new welcome css 2016-03-02 08:47:58 -06:00
mdipierro
dc5cac07e1 fixed bs3 form alignment 2016-03-01 23:39:08 -06:00
Boris Aramis Aguilar Rodríguez
8058dc2ce6 Update imageutils.py
Adding a padding statement into imageutils, the goal is to allow a padding transparent/white border on pictures when being resized in different aspect ratio.
2016-03-01 20:24:28 -06:00
mdipierro
3808b1f6ae optional parameters for setup-web2py-nginx-uwsgi-ubuntu.sh 2016-02-29 11:34:57 -06:00
mdipierro
10f2e4c3ad updates support.html, thanks Gael 2016-02-27 08:16:19 -06:00
mdipierro
3c6af5f920 updated support page 2016-02-27 00:12:01 -06:00
mdipierro
a5269b1a1a Merge branch 'master' of github.com:web2py/web2py 2016-02-26 23:37:47 -06:00
mdipierro
9a079e092f fixed typo in auth 2016-02-26 14:24:21 -06:00
mdipierro
218817753a myconf.take, myconf.get 2016-02-26 14:20:18 -06:00
mdipierro
ef9bf73973 example in rocket.py 2016-02-26 13:52:00 -06:00
mdipierro
f92f21b060 Merge pull request #1195 from niphlod/fix/1191
fixes #1191
2016-02-25 13:59:14 -06:00
niphlod
642ec2b934 fixes #1191
fix is in lines 828-835 . needed to backport total_seconds for py2.6
(694-701).
everything else is just pep8.
2016-02-25 02:46:36 +01:00
Chen Levy
d494ec9c88 fix invalid view for purly complied app
When packing a compiled app, and distributing it without the non-compiled view views, run_view_in searches only the old style compiled view file: e.g. views_default_index.html.pyc and not in views.default.index.html.pyc, resulting in "invalid view (default/index.html)" 404 Exception.
2016-02-22 14:13:02 +02:00
Jonathan Vasek
c4d1f3f414 Fixed a bug whereby calling 'delete_record()' on a row object caused an AttributeError. 2016-02-21 00:19:49 -06:00
mdipierro
5a59149514 italian group 2016-02-12 16:03:16 -06:00
mdipierro
484f02cae1 fixed grid button alignment, thanks SanDiego 2016-02-10 16:04:27 -06:00
mdipierro
d5db67d5ea Merge pull request #1182 from preactive/patch-1
Update ldap_auth.py
2016-02-07 00:14:31 -06:00
mdipierro
1480a10d6b Merge pull request #1176 from cccaballero/master
Added virtual field support to autocomplete widget
2016-02-07 00:14:22 -06:00
mdipierro
7259f273f3 fixed some body padding in welcome 2016-02-07 00:12:33 -06:00
mdipierro
8645365f58 fixed some button style issues in grid 2016-02-07 00:10:38 -06:00
mdipierro
106930ed73 fabfile now reads applications/app/hosts 2016-02-07 00:09:55 -06:00
preactive
f79b38a335 Update ldap_auth.py
In regards to comments in:

0036d9c45b

And: 

https://github.com/web2py/web2py/issues/1178
2016-02-04 13:41:49 -08:00
mdipierro
35216db750 grid(Set(..)) as well as grid(Query(..)) 2016-02-03 22:11:38 -06:00
Carlos Cesar Caballero Díaz
faa3d1d477 Added virtual field support to autocomplete widget
Added support to use Virtual Fields in autocomplete widget.

Gotchas:
- Using Virtual Fields is slower than normal fields.
- Virtual Fields must be declared with name and table_name attributes.
2016-01-30 10:20:37 -05:00
mdipierro
7aff79ca57 Merge pull request #1172 from dmatic/master
Fixed error with oneall login when login provider doesn't send user's full name
2016-01-29 22:20:51 -06:00
mdipierro
63bb4a7e8a Merge pull request #1171 from matclab/fix/1043
Fix #1170 by reverting fix to #1043
2016-01-29 22:20:26 -06:00
mdipierro
8fc322254e Merge pull request #1169 from BuhtigithuB/Improve/cache-redis-contrib
PEP8 enhancements, improve docstring and some vars rename
2016-01-29 22:18:28 -06:00
mdipierro
b4c28516ae Merge pull request #1166 from Rimbo/overblown-sessions-cleanup
Make SessionSetDb.get() a generator.
2016-01-29 22:18:18 -06:00
mdipierro
d233d3babb Merge pull request #1163 from rafaelol/fixes_mail_encoding_bug_for_non_ascii_text
Fix bug on Mail.send() when text or input are Unicode
2016-01-29 22:17:07 -06:00
mdipierro
f18a1d0555 fabfile remove _update.zip 2016-01-29 22:14:38 -06:00
Dragan Matic
2cb55b52e9 fixed error with oneall login when login provider doesn't send full name 2016-01-17 22:45:38 +01:00
Mathieu Clabaut
4f361b5aad Fix #1170 by reverting fix to #1043
The problem is only a styling issue and not a HTML one.

It was solved  in 864dbe73f2 by adding a `readonly ` class to labels which allow for properly vertical align with CSS.

This reverts commit 353db90a64 which add
specific HTML for some filed types and which breaks display of comments.
2016-01-16 10:02:12 +01:00
Dragan Matic
db122e7709 Merge pull request #2 from web2py/master
update from original
2016-01-15 17:05:39 +01:00
Richard Vézina
005e565a11 PEP8 enhancements, improve docstring and some vars rename 2016-01-14 12:28:05 -05:00
Jimmy Rimmer
1656c6cdeb Make the same change for SessionSetDb that's in SessionSetFiles: Make get() a generator, so that memory doesn't get blown out if there are 18 million sessions there to clean up. 2016-01-11 14:09:25 -08:00
mdipierro
b7a0f2043c fixed fabfile error 2016-01-09 22:20:42 -06:00
mdipierro
05df3b3029 smarter request.restful checks content-type for json body 2016-01-08 21:29:04 -06:00
Richard Vézina
dc1c85928d flash -> w2p_flash 2016-01-08 13:13:13 -05:00
rafaelol
ba2cb811be Changes encoding of text and subject on Mail.send()
On the previous commit we changed text and subject from unicode
to str. After a better solution from @cassiobotaro, we're using
unicode again, selecting the encoding as the one passed via encoding
parameter.
2016-01-07 14:59:58 -02:00
rafaelol
6a7c0525f5 Fix bug on Mail.send() when text or input are Unicode
On PR #964 @matclab forced the encoding of both subject and
text variables to unicode.

After merging it, matclab realized that when we send Unicode
text to the method it raises an exception and asked if he should
change the commit. Unfortunately this thing was kept untouched.

This problem exists because we previously encode the unicode variables
to utf-8 (for instance here https://github.com/web2py/web2py/blob/master/gluon/tools.py#L478-L481) and then force again to unicode. This piece of code shows what happens:

```
>>> a = u'áéí'
>>> a
u'\xe1\xe9\xed'
>>> b = a.encode('utf-8')
>>> b
'\xc3\xa1\xc3\xa9\xc3\xad'
>>> unicode(a)
u'\xe1\xe9\xed'
>>> unicode(b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
```

If we force to str, just like @matclab suggested, we solve this issue.
2016-01-07 11:47:29 -02:00
mdipierro
5132616c6c check_all 2016-01-05 07:29:53 -06:00
mdipierro
e528c10c21 Merge pull request #1160 from sceeter89/portalocker-issues
Changed order of imports
2016-01-04 09:44:20 -06:00
mdipierro
41fd02fa2c Merge pull request #1158 from niphlod/enhancement/redis_toolset
new redis toolset to use with web2py
2016-01-04 09:43:58 -06:00
mdipierro
26dab37d9f Merge pull request #1157 from niphlod/fix/scheduler_stopped
fix for STOPPED tasks via stop_task()
2016-01-04 09:43:13 -06:00
mdipierro
cc40018e87 Merge pull request #1155 from niphlod/tests/recfile
tests for modules NEED to be in a separate unittest
2016-01-04 09:42:23 -06:00
mdipierro
b6db314612 Merge pull request #1154 from niphlod/fix/1044
fixes #1044
2016-01-04 09:41:58 -06:00
mdipierro
3498666115 Merge pull request #1153 from niphlod/fix/1100
fixes #1100
2016-01-04 09:41:43 -06:00
mdipierro
562a559169 Merge pull request #1152 from niphlod/fix/1143
fixes #1143
2016-01-04 09:40:35 -06:00
mdipierro
47cec80939 Merge pull request #1151 from niphlod/tests/reorg
better test_utils and reorg to compileapp
2016-01-04 09:39:59 -06:00
mdipierro
eceb579cdd Merge pull request #1149 from niphlod/enhancement/constant_time_compare
bultin constant time checking
2016-01-04 09:39:38 -06:00
Adam Marszałek
bd19986380 Changed order of imports 2016-01-04 13:23:22 +01:00
niphlod
12acdb51d7 new redis toolset to use with web2py
This is a refactor of everything web2py uses with redis.
Specifically:
- a refactored redis_cache.py that fixes #958, allowing a "fail
gracefully" behaviour in case redis is not available
- a refactored redis_session.py that blocks less with with_lock=True
(although still not optimal)
- a new (and NEEDED) redis_utils.py that serves as the base for
everything else, allowing an RConn object that you can freely use as a
redis.StrictRedis connection, and that you can override in case you're
using a different library (or that web2py will use in case redis-py
won't be the de-facto standard around)
- a newly - and much anticipated - redis_scheduler.py. It's a slip-in
replacement for the standard scheduler that uses redis for workers
coordination. Feel free to dig in the code and improve it.

For redis_cache and redis_session changes are BREAKING. It means that
users will need to change the import locations and tune a bit the code.
Now every module depends on an gluon.contrib.redis_utils.RConn object
(or similar) that in turns is very similar to a redis.StrictRedis one.
The redis instance is EXTERNAL to the modules themselves (no more "host,
port, db, password" parameters in RedisCache or RedisSession)
See the relevant docstrings for usage examples
2016-01-02 23:15:00 +01:00
niphlod
918590d1f3 fix for STOPPED tasks via stop_task()
they previously killed the main process
2016-01-02 22:50:27 +01:00
niphlod
d57428e8f0 fixes #1156 and other few issues 2016-01-01 20:48:55 +01:00
niphlod
13e3adf22d tests for modules NEED to be in a separate unittest 2015-12-30 21:20:24 +01:00
niphlod
d4ffcaf1b1 fixes #1044
This shouldn't have took that much to solve. Really sorry for the delay
2015-12-30 16:38:43 +01:00
niphlod
17f1a51133 fixes #1100
now elements with data-w2p_disable are not disabled.
in addition, for non-ajax forms, disabled submit buttons are reenabled
after 5 seconds

plus reindented, refactored AND jslinted
2015-12-30 16:19:39 +01:00
niphlod
d4bca008a8 better docstrings 2015-12-30 14:55:37 +01:00
niphlod
90c33911ab fixes #1143
don't even get me started about the current messy status of admin
2015-12-30 12:07:18 +01:00
niphlod
0a263ffc8d better test_utils and reorg to compileapp 2015-12-30 11:42:49 +01:00
niphlod
e94946d3d5 bultin constant time checking
- if hmac.compare_digest is there, we should use it instead of our own
fallback.
- jwt handler has been updated to use utils.compare (reported in
#web2py-users)
- includes the same mods as https://github.com/web2py/web2py/pull/1146
2015-12-30 10:37:14 +01:00
mdipierro
1ca0c9b0c0 Merge pull request #1145 from niphlod/fix/1142
fixes #1142
2015-12-29 12:07:40 -06:00
mdipierro
cee0f91b36 Merge pull request #1144 from niphlod/fix/external_folder
better support for -f
2015-12-29 12:06:54 -06:00
niphlod
eb49831726 fixes #1142 2015-12-28 15:05:51 +01:00
niphlod
b517c898b8 better support for -f
as exposed in
https://groups.google.com/d/msg/web2py-developers/uJoQeUlCABw/-MCXocwGAgAJ
2015-12-28 14:48:29 +01:00
mdipierro
71fba07e3a some sqlhtml renaming 2015-12-27 07:12:56 -06:00
mdipierro
2a7a4a3d04 removed print statements 2015-12-27 05:39:08 -06:00
mdipierro
999f235b75 IS_IN_DB(...,delimiter=',',auto_add=True) 2015-12-27 05:33:29 -06:00
mdipierro
da22554aed allow for IS_IN_DB(db,db.thing.id,db.thing.name) 2015-12-27 02:46:23 -06:00
mdipierro
0409d6f725 R-2.13.4 2015-12-25 22:56:50 -06:00
mdipierro
b6235249da fixed path issue when starting web2py 2015-12-25 22:56:13 -06:00
mdipierro
fabadcd21f do not remove gluon/packages/dal/.* files 2015-12-24 09:40:08 -06:00
mdipierro
8e4ea3497b fixed issue #1138, ldap and python 2.6.x problem 2015-12-24 09:15:19 -06:00
mdipierro
4b0e1856b5 reverted 2a245d36 2015-12-24 09:04:45 -06:00
mdipierro
94841c90c3 R-2.13.3 2015-12-24 08:50:24 -06:00
mdipierro
f14e5f728c fixing mess 2015-12-24 08:48:19 -06:00
mdipierro
8443c17839 sync'ed appadmins 2015-12-24 08:36:16 -06:00
mdipierro
be8114127e Merge pull request #1141 from gi0baro/master
Tracking latest pyDAL changes
2015-12-24 08:30:31 -06:00
gi0baro
4eaef303ff Tracking latest pyDAL changes 2015-12-24 15:21:52 +01:00
mdipierro
319a3fc1dc Merge branch 'BuhtigithuB-fix/no-more-deprecated-has-key' 2015-12-23 23:11:55 -06:00
mdipierro
463d643e2c fmerged 2015-12-23 23:11:34 -06:00
mdipierro
0cbed12952 Merge pull request #1137 from cassiobotaro/fix_logging
fixing logging old behaviour
2015-12-23 23:08:17 -06:00
mdipierro
b5994e57a4 Merge pull request #1136 from cassiobotaro/remove_25_support
update files removing 2.5 things
2015-12-23 23:07:54 -06:00
Cássio Botaro
e239b975be Change to re-run AppVeyor 2015-12-23 11:19:19 -02:00
Richard Vézina
0259ea3d29 no more deprecated .has_key(...) 2015-12-22 15:39:32 -05:00
cassiobotaro
db4c008de3 Minor changes 2015-12-21 15:40:25 -02:00
cassiobotaro
7921e5148a fixing logging old behaviour 2015-12-21 12:10:50 -02:00
cassiobotaro
ee23eab77a update files removing 2.5 things 2015-12-21 11:55:44 -02:00
mdipierro
2344386f77 better docstring for Auth.jwt 2015-12-18 19:19:43 -06:00
mdipierro
b5e12031c5 added Auth(db,jwt=dict(secret_key='secret')) and auth.allows_jwt() before auth.requires_login() 2015-12-18 19:12:41 -06:00
mdipierro
85e6840cf0 Merge branch 'master' of github.com:web2py/web2py 2015-12-18 18:09:09 -06:00
mdipierro
4c3006acb4 Merge pull request #1135 from gi0baro/master
Track latest pyDAL GAE fix by @mdipierro
2015-12-18 18:08:53 -06:00
gi0baro
f8f008cab5 Track latest pyDAL GAE fix by @mdipierro 2015-12-18 12:51:17 +01:00
mdipierro
6bff8af458 CHANGELOG 2015-12-18 04:52:43 -06:00
mdipierro
b67edb083e fixed compileapp problem in appveyor test (2nd attempt) 2015-12-18 04:44:03 -06:00
mdipierro
4125a97ce1 fixed compileapp problem in appveyor test 2015-12-18 04:39:51 -06:00
mdipierro
78cf55bf9a R-2.13.2 2015-12-18 04:28:16 -06:00
mdipierro
931daaff89 fixed security issue in reset password when registration_requires_authorization, thanks Giovanni Verde 2015-12-18 04:11:26 -06:00
mdipierro
c6550f0adc fixed a condition that allows reset_password if a reset link is sent before a user is blocked 2015-12-18 03:40:12 -06:00
mdipierro
22c89d8dcc version 2.13.1 2015-12-17 21:19:08 -06:00
mdipierro
1636528a0f Merge pull request #1132 from gi0baro/master
Tracking pyDAL v15.12
2015-12-17 21:08:30 -06:00
gi0baro
c02229d79c Tracking pyDAL v15.12 2015-12-16 21:55:23 +01:00
mdipierro
acb05dbfe1 added retrieve to fabfile and fixed minor bug 2015-12-15 23:13:46 -06:00
mdipierro
fda1117dd7 fixed import 2015-12-14 15:44:34 -06:00
mdipierro
d1fde23182 create_user spelling fixed 2015-12-14 15:43:50 -06:00
mdipierro
adf4c93860 Merge pull request #1124 from matclab/issue1123
Convert attachments to a list if necessary.
2015-12-14 15:32:07 -06:00
mdipierro
02f1903c3d Merge pull request #1127 from gi0baro/appveyor-skip
Avoid to run pyDAL adapters tests on appveyor
2015-12-14 15:31:23 -06:00
mdipierro
1137027ecc Merge pull request #1126 from nextghost/master
Parse GET vars from rewritten query string, not the original. Fixes #730
2015-12-14 15:31:10 -06:00
mdipierro
229616b9fc added fabfile form deployment and maintenance tasks 2015-12-14 15:16:00 -06:00
gi0baro
a75a8cbf46 Avoid to run pyDAL adapters tests on appveyor 2015-12-13 12:34:54 +01:00
Martin Doucha
9650ff7516 Parse GET vars from rewritten query string, not the original. Fixes #730 2015-12-12 23:59:15 +01:00
Mathieu Clabaut
5b90f3f532 Convert attachments to a list if necessary.
Also corrects a typo that was apparently silenced by the bug.
This closes issue #1123
2015-12-09 14:46:05 +01:00
mdipierro
483092787b Merge pull request #1120 from dokime7/patch-10
Fix oauth2 renew token
2015-12-07 19:58:24 -06:00
Jeremie Dokime
9b17048882 Fix oauth2 renew token
When getting an oauth token, we must use code or refresh_token but not twice.
2015-12-07 11:18:59 +01:00
mdipierro
30fe7400f9 syncing latest mydal 2015-12-04 15:14:02 -06:00
mdipierro
ada9353a7e removed unwanted referene to jwt in tools 2015-12-04 15:10:25 -06:00
mdipierro
b0373297e0 Browser auto-fill can corrupt data while using admin database interface #1045, thanks dkleissa 2015-12-04 12:31:35 -06:00
mdipierro
2dbbef724c DIV.elements fails when searching for an attribute with an integer value #1074 2015-12-04 12:21:05 -06:00
mdipierro
eb7017fd9a fixed auth.settings.register_onaccept is not firing when signing up through third-party #1081 2015-12-04 12:14:39 -06:00
mdipierro
4c039574df skip failed views, thanks Anthony 2015-12-04 12:06:46 -06:00
mdipierro
ab900957fe fixed Cookie parsing stopped after first invalid cookie #1084, thanks paultuckey 2015-12-04 11:44:51 -06:00
mdipierro
f960c8f6df fixed add_membership, del_membership, add_membership = IntegrityError (when auth.enable_record_versioning) #1087 2015-12-04 11:42:06 -06:00
mdipierro
d2910327c0 temp fix for IS_DATETIME with timezone info & record versioning causes TypeError: can't compare offset-naive and offset-aware datetimes #1094 2015-12-04 11:31:55 -06:00
mdipierro
dfd6d52192 fixed missing helper.get(attribute) 2015-12-04 11:28:39 -06:00
mdipierro
7dd8a3c853 fixed Reference to http://..../[app]/default/user/manage_users in welcome's default controller #1102 2015-12-04 11:24:00 -06:00
mdipierro
71ae754fcd fixed #1110, allow passing unicode to template render 2015-12-04 11:16:15 -06:00
mdipierro
0520770a7e fixed #1111, Validator IS_IPV4: options is_private=False not working, thanks Nbushkov 2015-12-04 11:12:44 -06:00
mdipierro
6b880fb455 fixed class concatenation 2015-12-04 10:46:20 -06:00
mdipierro
dd180019a1 Merge pull request #1118 from matclab/readonly-label
Add readonly class to labels of readonly fields and set padding to 0
2015-12-04 10:43:17 -06:00
mdipierro
638f1f902a Merge pull request #1116 from timnyborg/patch-7
Fix IS_NOT_IN_DB to work with custom primarykey
2015-12-04 10:42:25 -06:00
mdipierro
73061e3bf5 Merge pull request #1114 from BuhtigithuB/Improve/ldap-contrib-self-signed-certificate
Improve/ldap contrib self signed certificate
2015-12-04 10:42:05 -06:00
mdipierro
5a18e29c2e Merge pull request #1113 from timnyborg/patch-6
Fix grid count when using groupby on MSSQL
2015-12-04 10:41:36 -06:00
mdipierro
721af77c90 Merge pull request #1108 from dokime7/patch-9
Send client_secret when get oauth2 refresh_token
2015-12-04 10:38:04 -06:00
mdipierro
2cf6797b43 Merge pull request #1106 from erilyth/master
Added XML to retrieve pickled XML data #1067
2015-12-04 10:37:50 -06:00
mdipierro
5c4145743f Merge pull request #1103 from ilvalle/w2p_target
added w2p_target attribute in form to control the output destination
2015-12-04 10:37:14 -06:00
mdipierro
b4733e4617 added gluon/contrib/web2py_jwt.py, thanks Niphlod 2015-12-04 10:30:56 -06:00
mdipierro
b51d217d9b french pluralizaiton rules, thanks Mathieu Clabaut 2015-12-04 10:07:38 -06:00
Mathieu Clabaut
864dbe73f2 Add readonly class to labels of readonly fields and set padding to 0
This allow for readonly fields content to be vertical aligned with their label
2015-12-04 15:29:45 +01:00
Tim Nyborg
b942fc8f7a Fix IS_NOT_IN_DB to work with custom primarykey
Validator currently selects custom id properly, but then explicitly checks .id
2015-12-03 15:02:21 +00:00
Hardirc
b2a65dbba4 Support for self-signed certificate LDAPS implementation 2015-12-02 14:18:09 -05:00
Hardirc
d36d4d77f7 replace .has_key() by in, .has_key() is deprecated 2015-12-02 14:04:51 -05:00
Hardirc
c8db6d5fb7 Improve PEP8 and readability 2015-12-02 14:02:27 -05:00
Tim Nyborg
1b77c2294a Fix grid count when using groupby on MSSQL
Any query like SELECT COUNT(*) from (SELECT COUNT(*) FROM ...) will fail with 'No column name was specified for column 1 of '_tmp'', so I'm providing an alias for the subquery's field
2015-11-30 16:09:53 +00:00
Jeremie Dokime
98a81c9fbd Send client_secret when get oauth2 refresh_token
With some oauth2 providers, the oauth client_secret is required when getting a refresh_token.
2015-11-23 10:10:00 +01:00
Batchu Venkat Vishal
4bf5a70dc0 Added XML to retrieve pickled XML data #1067 2015-11-19 15:01:23 +05:30
ilvalle
d883e3d84e added w2p_target attribute in form to control the output destination 2015-11-14 12:03:20 +01:00
mdipierro
db37cf6a58 Revert "Labels should get their information from the render function of the records."
This reverts commit 65c87386c1.
2015-11-12 18:25:48 -06:00
mdipierro
dba5c97d51 fixed check for form tampering 2015-11-11 18:38:48 -06:00
mdipierro
948bd0c671 fixed check for form tampering 2015-11-11 18:20:37 -06:00
mdipierro
5d8ff8ba2c removed login_once_after_registration 2015-11-11 09:14:05 -06:00
mdipierro
503cd59adc auth.settings.login_once_after_registration 2015-11-11 09:03:54 -06:00
mdipierro
a0bcd2287b Merge branch 'josedesoto-issue/1095' 2015-10-30 23:10:35 -05:00
mdipierro
430163f70b fixed conflict 2015-10-30 23:10:25 -05:00
mdipierro
52b59e9b71 Merge pull request #1092 from niphlod/fix/1090
fixes #1090
2015-10-30 23:08:47 -05:00
mdipierro
e8f87ea274 Merge pull request #1091 from dokime7/patch-8
Add renew token by using refresh_token
2015-10-30 23:08:37 -05:00
mdipierro
fb6fa0c448 Merge pull request #1088 from niphlod/fix/1083
fixes #1083
2015-10-30 23:07:58 -05:00
mdipierro
935c95ccfc Merge pull request #1086 from gi0baro/pydal-tests
Run pydal's tests inside web2py using contrib adapters
2015-10-30 23:07:37 -05:00
mdipierro
e180e69467 fixed a typo, thanks James Burke 2015-10-30 23:06:00 -05:00
engeens
5c9d197f93 issue #1095. Added two-factor authentication methods and onvalidation. Fixed last attempt two-factor retry login
issue #1095. Added return user for two_factor_onvalidation
2015-10-30 15:09:51 +01:00
mdipierro
e417d311e5 added link to http://www.web2pyref.com/ 2015-10-29 20:59:15 -05:00
mdipierro
199f93f262 fixed typo in tools.py, thanks James Burke 2015-10-29 20:56:40 -05:00
niphlod
64a8880c80 fixes #1090
removed timezone for IS_DATE* validators
2015-10-26 09:50:09 +01:00
Jeremie Dokime
257c514bd4 Add renew token by using refresh_token
Handle the refresh_token mechanism to renew the access_token when expire.
2015-10-25 20:48:04 +01:00
niphlod
12f848c899 fixes #1083 2015-10-19 21:50:34 +02:00
mdipierro
4de007a946 fixed possible problem with cache.action 2015-10-16 21:39:30 -05:00
gi0baro
b59a93e24e Run pydal's tests inside web2py using contrib adapters 2015-10-16 14:44:41 +02:00
mdipierro
bbed326c20 fixed commit error 2015-10-07 13:15:39 -05:00
mdipierro
874398c38c Merge pull request #1080 from BuhtigithuB/improve/ldap-auth-more-dry
Make ldap_auth a bit more DRY
2015-10-07 13:12:30 -05:00
mdipierro
a9f8fbadae Merge pull request #1077 from leonelcamara/fix_wiki_extra
Fixes #721
2015-10-07 13:08:16 -05:00
mdipierro
e62320ff9f Merge pull request #1076 from gi0baro/master
Tracking pydal 15.09
2015-10-07 13:07:54 -05:00
mdipierro
b3e606295e committed changelog and removed unwanted file 2015-10-07 13:04:12 -05:00
mdipierro
b8c2bd7303 fixed LazyCrypt and fixed git problem 2015-10-07 13:02:30 -05:00
mdipierro
1387b26606 fixed LazyCrypt, thanks Denes 2015-10-07 12:57:20 -05:00
Richard Vézina
c6a7732d32 Don't update record when values are the same 2015-10-06 14:36:45 -04:00
Richard Vézina
0036d9c45b Make ldap_auth a bit more DRY 2015-10-06 14:30:50 -04:00
Leonel Câmara
b99fb7dedf Fixes #721
Fixes a bug where auth.wiki was not respecting the extra keyword argument
2015-09-29 00:21:01 +01:00
gi0baro
344590470b Tracking pydal 15.09 2015-09-28 15:50:42 +02:00
mdipierro
2c57dc084e Merge pull request #1073 from niphlod/fix/1043
fixes #1043 , thanks @bobstjon
2015-09-27 14:40:27 -05:00
mdipierro
c17ba0a020 Merge pull request #1072 from niphlod/fix/1039
fixes #1039
2015-09-27 14:40:14 -05:00
mdipierro
7d4b460e1b Merge pull request #1071 from niphlod/fix/1068
fixes #1068
2015-09-27 14:39:58 -05:00
mdipierro
6680ea8ab7 Merge pull request #1061 from nklever/master
small changes in sqlhtml.py, validator.py, contrib/spreadsheet.py
2015-09-27 14:39:47 -05:00
niphlod
353db90a64 fixes #1043 , thanks @bobstjon 2015-09-21 22:24:59 +02:00
niphlod
827e663ac4 better list: widget 2015-09-21 22:18:18 +02:00
niphlod
de399691ce fixes #1039
It was a REEEAALLY good catch :-)
2015-09-21 22:09:17 +02:00
niphlod
46f081c45c fixes #1068
threw in also a better list:string widget repr for bs3

Updated also the bootswatch theme because something was wrong
2015-09-21 21:38:28 +02:00
mdipierro
0fa0dbaeea Merge branch 'master' of github.com:web2py/web2py 2015-09-20 14:07:06 -05:00
mdipierro
b47511c896 token default = web2py_uuid 2015-09-20 14:07:01 -05:00
mdipierro
e31318eaa8 Merge pull request #1066 from lraphael/master
fix unindented lines
2015-09-18 00:41:34 -05:00
mdipierro
72ee538883 Merge pull request #1065 from leonelcamara/pa_integration
PythonAnywhere integration
2015-09-18 00:41:20 -05:00
mdipierro
b6ddc6098e Merge pull request #1060 from viniciusban/1059-response-render-uses-original-response-view
Closes #1059: get `response.view` from the environment
2015-09-18 00:40:04 -05:00
mdipierro
90854eae44 Merge pull request #1058 from niphlod/fix/735
fixes issue #735
2015-09-18 00:39:08 -05:00
mdipierro
2bceb3f95f Merge pull request #1057 from niphlod/fix/823
fixes #823
2015-09-18 00:38:55 -05:00
mdipierro
9da1e29014 Merge pull request #1056 from niphlod/fix/wiki_typo
fixes typo in wiki.
2015-09-18 00:38:38 -05:00
Raphael Lechner
39ba9dc1a9 fix unindent lines 2015-09-16 17:12:45 +02:00
Leonel Câmara
36db9719ef Deal with the corner case of already created accounts
Polished everything a bit
2015-09-15 17:24:57 +01:00
Leonel Câmara
125cbd93a0 Allow deploying to pythonanywhere from the web2py admin that you're running locally. 2015-09-08 00:51:09 +01:00
Nik Klever
bc267ce17b Added Column- and Row-Headers to be more flexible with the headers of the
spreadsheet.

Added also a boolean "select" parameter for the sheet.cell function which
allows to use a HTML select tag instead of an input tag for this cell.
2015-09-05 15:01:02 +02:00
Nik Klever
65c87386c1 Labels should get their information from the render function of the records. 2015-09-05 14:57:55 +02:00
Nik Klever
2a245d36f4 If in any of the form fields are unicode strings entered as input, the
unicode characters in these strings are lost in self.vars.

This conditions sets it back to the original input.

Might be, that this should be done at another place, but it works.
2015-09-05 14:38:32 +02:00
viniciusban
dcf64a661d Closes #1059: get response.view from the environment 2015-09-03 20:39:37 -03:00
niphlod
1c74afc01b fixes issue #735 2015-09-03 18:33:54 +02:00
niphlod
5dbcda9f38 fixes #823 2015-09-03 18:08:33 +02:00
niphlod
ac02d52f05 fixes typo in wiki. As usual, lack of unittests made this possible.
We should really make each developer "adopt" a piece of web2py to test
and care if we don't want to write unittests.
2015-09-03 17:56:45 +02:00
mdipierro
d4270373e1 fixed bug in redirect to cas service, thanks Fernando González 2015-09-01 23:07:18 -05:00
mdipierro
e4b27080ca Merge pull request #1051 from ShySec/master
added HttpOnly cookies (default)
2015-08-30 20:41:23 -05:00
mdipierro
692791a518 Merge pull request #1053 from BuhtigithuB/feature/redirect-next-var-when-logged-on-page-reload
No credentials request if logged in and URL contains user/login?_next=
2015-08-30 00:58:27 -05:00
mdipierro
9190191c7a changed the default BS3 theme 2015-08-23 10:07:32 -05:00
mdipierro
7bd8f6a1a9 Merge pull request #1054 from BuhtigithuB/Improve/PEP8-gluon-tools-py
Improve PEP8 gluon/tools.py
2015-08-21 00:07:06 -05:00
mdipierro
64e115f442 Merge pull request #1050 from timnyborg/patch-5
Update simplejsonrpc.py - move default to method signature
2015-08-21 00:03:24 -05:00
Richard Vézina
61f685d225 Improve PEP8 gluon/tools.py 2015-08-20 17:16:13 -04:00
Richard Vézina
c56fc2f6a0 Improve proposed enhancement #1052 2015-08-20 15:23:59 -04:00
mdipierro
bb2aa29867 fixed google link to viewer in autolinks.py 2015-08-20 14:00:21 -05:00
Richard Vézina
08b6832809 No credentials request if logged in and URL contains user/login?_next= 2015-08-19 14:47:21 -04:00
kelson
cbbd1246db re import required for assertRegexpMatches port 2015-08-19 11:33:47 -04:00
kelson
0a79bf3afd assertRegexpMatches requires port for python2.5 and python2.6 2015-08-19 11:30:07 -04:00
kelson
db5e58e49f added HttpOnly cookies (default)
added unit tests for cookie layout, secure cookies, and HttpOnly cookies
Session.httponly_cookies=False to revert HttpOnly cookies
2015-08-19 11:25:00 -04:00
Tim Nyborg
5030d3144f Update simplejsonrpc.py
Default best placed in method signature, 
Thanks to cassiobotaro for pointing it out
2015-08-19 11:59:40 +01:00
mdipierro
edcc2e44dc R-2.12.3 2015-08-18 19:15:01 -05:00
mdipierro
2cf9f26b0d fixed pydal tracking again 2015-08-18 15:13:57 -05:00
mdipierro
4b99b6fdd7 adding debounced ajax calls 2015-08-18 14:16:10 -05:00
mdipierro
622430583f Merge pull request #1047 from web2py/revert-1046-master
Revert "added default HttpOnly cookies"
2015-08-18 13:59:07 -05:00
mdipierro
89cc5a5f70 Revert "added default HttpOnly cookies" 2015-08-18 13:57:44 -05:00
mdipierro
6899154fcd reverted DAL to v15.07 2015-08-18 13:46:38 -05:00
mdipierro
47c0e461f1 Merge pull request #1046 from ShySec/master
added default HttpOnly cookies
2015-08-18 11:53:54 -05:00
mdipierro
93237837ed Merge pull request #1042 from cassiobotaro/master
Allow change quality when RESIZE
2015-08-18 11:52:52 -05:00
kelson
cf20ce5fae _js_cookies => not httponly_cookies 2015-08-18 12:25:13 -04:00
mdipierro
04c86f07ef Merge pull request #1032 from dsk7/allow_requires_login_to_be_determined_dynamically
Allow to specify a function for requires_login at auth decoration.
2015-08-18 11:03:37 -05:00
mdipierro
1a12c4011b Merge pull request #1031 from mmunz/master
Repair cache status page in appadmin for welcome, admin and examples …
2015-08-18 11:02:14 -05:00
mdipierro
85bbe15758 Merge pull request #1030 from josedesoto/issue/1028
fixed issue #1028, saml2 bug
2015-08-18 11:01:46 -05:00
mdipierro
5816481a44 Merge pull request #1029 from timnyborg/patch-3
simplejsonrpc: Fix TypeError when data is None
2015-08-18 11:01:19 -05:00
kelson
2675e9d229 added default HttpOnly cookies 2015-08-18 10:23:29 -04:00
mdipierro
41498917d5 Autocomplete(...at_beginning=False) 2015-08-16 15:22:45 -05:00
Cássio Botaro
8f7acd8154 Allow change quality when RESIZE 2015-08-13 02:12:49 -03:00
mdipierro
26865421b6 email change 2015-08-11 00:32:09 -05:00
mdipierro
b9ee4d4730 R-2.12.2 2015-08-09 09:27:42 -05:00
mdipierro
8fd7a27d5f fixed problem with pack all and missing cache folder 2015-08-09 09:26:57 -05:00
mdipierro
69231bdd7f R-1.12.1 2015-08-07 02:20:08 -05:00
mdipierro
55dfb9e8c4 R-1.12.1 2015-08-07 02:12:17 -05:00
mdipierro
7761219cba jquery 1.11.3, bootstrap 3.3.5 2015-08-07 02:10:27 -05:00
mdipierro
e31e4e236f prettydate can do UTC, fixes #1036 2015-08-07 02:04:07 -05:00
mdipierro
a43d822412 changed version for testing 2015-08-06 22:02:17 -05:00
dsk7
f94bc250eb Allow to specify a function for requires_login at auth decoration. 2015-08-02 13:21:20 +02:00
mdipierro
5775d2788d reverted apache processes=1 2015-08-01 00:24:21 -05:00
mdipierro
048f275076 fixed TLS support in ldap, thanks backseat 2015-08-01 00:21:56 -05:00
Manuel Munz
8078d4b0f3 Repair cache status page in appadmin for welcome, admin and examples apps.
This fixes how values are read. For cache.disk, we need to use the second value in the dict.
For cache.ram everything is already there in the object, no need trying to get the stats (which are not there) in the loop.
Also small fix for buttons that did not open the detailed statistics when clicked (class hidden has !important in bootstrap3).
2015-08-01 00:29:34 +02:00
Tim Nyborg
5ee8c9c930 simplejsonrpc: Fix TypeError when data is none 2015-07-27 12:07:26 +01:00
Jose de Soto
6659bc0793 fixed issue #1028, saml2 bug 2015-07-27 13:05:36 +02:00
mdipierro
d7caaf04cc fixed issue #933, wiki bug 2015-07-26 14:24:53 -05:00
mdipierro
e95115deb4 fixed order of confirm-password field 2015-07-26 10:18:45 -05:00
mdipierro
42c69b6343 changed indent 2015-07-20 02:26:13 -05:00
mdipierro
d2347dec41 CacheRepresenter 2015-07-20 02:17:59 -05:00
mdipierro
8420020c21 caching only refault represent for references 2015-07-20 02:07:47 -05:00
mdipierro
571fc6d919 changed version 2015-07-20 01:51:22 -05:00
mdipierro
52ec228eeb Merge branch 'master' of github.com:web2py/web2py 2015-07-20 01:20:22 -05:00
mdipierro
5848d9acaa Merge pull request #1023 from dmatic/master
Script to install web2py with nginx and uwsgi on centos 7
2015-07-19 11:35:31 -05:00
Dragan Matic
3e8cbd5a0d Script to install web2py with nginx and uwsgi on centos 7 2015-07-16 13:35:27 +02:00
mdipierro
e276cc2fc1 Merge pull request #1019 from gi0baro/master
Updated to pydal 15.07
2015-07-16 03:57:13 -05:00
mdipierro
39a048db61 Merge pull request #1018 from cassiobotaro/master
fix validations IS_IPV6 and IS_IPADDRESS
2015-07-16 03:57:06 -05:00
mdipierro
df4b896334 models speed up 2015-07-13 07:52:38 -05:00
gi0baro
6d58845153 Using pydal 15.07 2015-07-13 14:25:43 +02:00
Dragan Matic
ba1f8bf741 Merge pull request #1 from web2py/master
Update from original
2015-07-10 13:09:43 +02:00
cassiobotaro
a378ab3e51 fix validations IS_IPV6 and IS_IPADDRESS 2015-07-10 01:11:16 -03:00
mdipierro
2d866647e2 Merge pull request #1017 from raj454raj/master
Small typo
2015-07-07 03:55:17 -05:00
Raj
81863d69c9 Small typo
Sorry! Can't resist when you see typo on the terminal !
2015-07-07 02:38:30 +05:30
mdipierro
ee2879442f tracking last master since that works better at this time 2015-07-06 10:13:47 -05:00
mdipierro
ad68d2415d possibly fixed issue #243, SQLFORM.factory(..) and DAL(None) 2015-07-06 10:04:14 -05:00
mdipierro
928de67f8d fixed DAL(None) 2015-07-06 10:01:40 -05:00
mdipierro
68296f9e65 Merge pull request #1016 from ShySec/master
fix Field.Virtual use in multi-table queries
2015-07-06 07:44:49 -05:00
kelson
7ac6edae52 fix Field.Virtual use in multi-table queries 2015-07-06 08:35:58 -04:00
mdipierro
1fc90fdb6d scripts/web2py-scheduler.conf 2015-07-06 04:46:56 -05:00
mdipierro
34a9d72cde mail.settings.server='logging:filename' 2015-07-06 04:45:14 -05:00
mdipierro
198ce939d0 fixed css of population table 2015-07-04 17:12:25 -05:00
mdipierro
e31a099cb3 Merge pull request #1012 from ortgit/master
Security fix: Validate for open redirect everywhere, not just in login()
2015-07-02 06:40:12 -05:00
mdipierro
cc7e10d216 Merge pull request #1009 from rserbitar/master
Fix compatibility with Tornado 4
2015-07-02 06:38:35 -05:00
mdipierro
d8b68036c2 Merge pull request #1006 from kjkuan/workaround-urllib-bug
Workaround http://bugs.python.org/issue9405 on OS X.
2015-07-02 06:38:18 -05:00
pallav_fdsi
f9cd7e4ef4 Open redirect attacks should be caught for all functions that use the _next variable (for example: logout()) instead of just for the login() function. 2015-07-01 18:38:43 -04:00
pallav_fdsi
896b45b838 Merge branch 'master' of https://github.com/web2py/web2py 2015-07-01 17:49:47 -04:00
mdipierro
d6146c9c5d no more text shadow in buttons, was horrible 2015-07-01 12:18:10 -05:00
mdipierro
b3be806244 Merge pull request #1008 from leonelcamara/pack_exe
Moved pack as exe functionality to the pack_custom.html form
2015-07-01 09:01:49 -05:00
rserbitar
eac12d3a57 Fix compatibility with Tornado 4
http://stackoverflow.com/questions/24851207/tornado-403-get-warning-when-opening-websocket
2015-07-01 12:06:52 +02:00
mdipierro
2fc081bc3c no more module_installer 2015-06-30 16:12:54 -05:00
Leonel Câmara
032af7c04d Moved pack as exe functionality to the pack_custom.html form 2015-06-30 19:19:38 +01:00
mdipierro
8e63825def Merge pull request #1007 from leonelcamara/pack_exe
Allow packing an application with the windows executable
2015-06-30 12:32:05 -05:00
Leonel Câmara
5d2e5dded3 Allow packing an application with the windows executable 2015-06-30 17:51:39 +01:00
mdipierro
61e33da844 module installer 2015-06-30 11:14:47 -05:00
Jack Kuan
da9dbaa5d6 Workaround http://bugs.python.org/issue9405 on OS X.
See https://groups.google.com/forum/#!topic/web2py/WSjhhDet1UM
for context.
2015-06-30 10:56:31 -04:00
mdipierro
7543c54bdb enable_tokens in welcome 2015-06-30 02:32:44 -05:00
mdipierro
00608e4f04 auth.settings.enable_tokens and header web2py_user_token 2015-06-29 13:38:54 -05:00
mdipierro
cdbf48f09b fixed margin-top in welcome 2015-06-29 13:03:23 -05:00
mdipierro
f39db6331a dealing with issue of accidentally redefining request/response, thanks Auden RovelleQuartz 2015-06-29 03:56:22 -05:00
mdipierro
ef433da190 improvements to token logic, thanks Niphlod 2015-06-28 17:01:21 -05:00
mdipierro
d2375b4187 always allow access to <app>/appadmin/manage/auth if used is admin 2015-06-28 16:41:09 -05:00
mdipierro
26d87967c5 always allow access to appadmin/manage.auth if used is admin 2015-06-28 16:40:23 -05:00
mdipierro
044b2331c3 bulk_register_enabled=False 2015-06-28 10:30:05 -05:00
mdipierro
c89614ada6 more strict conditions on bulk_register 2015-06-28 10:20:33 -05:00
mdipierro
f0aba167b4 _token, not token 2015-06-28 09:51:45 -05:00
mdipierro
bde9562b78 api_tokens in example 2015-06-28 09:49:50 -05:00
mdipierro
9a1229470a support for api_tokens 2015-06-28 09:48:08 -05:00
mdipierro
f781b9e1f5 Merge branch 'peregrinius-master' 2015-06-28 09:08:54 -05:00
mdipierro
fa32b7577b fixed a bug and added support for user/bulk_register 2015-06-28 09:01:10 -05:00
mdipierro
68526a0c6d allow unsorted multiword query in grid search 2015-06-28 07:52:34 -05:00
mdipierro
ad2003c618 fixed recently introduced sanitize bug 2015-06-27 00:33:16 -05:00
mdipierro
c1ecf823d8 added link to new tutorial 2015-06-26 08:07:31 -05:00
mdipierro
6134f82452 fixed issuer #239, locking error on FreeBSD, thanks josejachuf 2015-06-26 06:58:07 -05:00
mdipierro
fbb5a8b9bb fixed issue #968, IS_MATCH validator bug with unicode, thanks alex0834 2015-06-25 04:36:16 -05:00
mdipierro
df34869d65 fixes #978, autotypes and unicode strings, thanks remcoboerma 2015-06-25 04:31:41 -05:00
mdipierro
28e6999e7d fixed issue #980, Admin application: can't access directories with space in directory name, thanks mmihaltz 2015-06-25 04:30:10 -05:00
mdipierro
f4f77b0cb6 fixed issue #982, LOAD with ajax=False and args 2015-06-25 04:23:49 -05:00
mdipierro
23ddb6c3c2 fixed issue #999, gluon.sanitiizer.sanitze improvement, thanks macfiron 2015-06-25 04:19:01 -05:00
mdipierro
b636a5d6e9 more companies 2015-06-25 03:26:18 -05:00
mdipierro
efc392966e Merge pull request #1005 from cs09g/patch-3
change misspelling
2015-06-18 06:31:51 -05:00
mdipierro
cffa59a80c Merge pull request #1004 from cs09g/patch-2
simplified conditions
2015-06-18 06:31:22 -05:00
mdipierro
82a1b9f628 Merge pull request #1003 from cs09g/patch-1
remove duplicated execution
2015-06-18 06:31:08 -05:00
mdipierro
94d2f1453d Merge pull request #1002 from cs09g/patch-5
change initialization
2015-06-18 06:30:30 -05:00
mdipierro
a1875ee362 Merge pull request #1001 from cs09g/patch-3
Update appadmin.py
2015-06-18 06:29:57 -05:00
mdipierro
5f13dca712 Merge pull request #1000 from niphlod/fix/readme
after appveyor hooks have been defined...
2015-06-18 06:28:39 -05:00
Chase choi
f78d423c92 change misspelling 2015-06-18 17:13:38 +09:00
Chase choi
f60ae809b6 simplified conditions 2015-06-18 17:05:34 +09:00
Chase choi
34dd8af101 remove duplicated execution
is that really duplicated or missing something to add for difference?
2015-06-18 16:55:04 +09:00
Chase choi
6bf6ebab1b change initialization
ok must be True or False. 
set False is better for initialization
2015-06-18 16:40:59 +09:00
Chase choi
29bf50425b Update appadmin.py 2015-06-18 16:31:28 +09:00
niphlod
8a7612c976 after appveyor hooks have been defined... 2015-06-17 21:23:29 +02:00
mdipierro
97489fd277 Merge pull request #998 from niphlod/build/appveyor
move to codecov and enable appveyor too
2015-06-17 02:00:48 -05:00
mdipierro
b86184fe58 Merge pull request #997 from niphlod/fix/bs3_grid_checkbox
fix display of checkboxes in search form of grid
2015-06-17 02:00:34 -05:00
niphlod
2ce53e9957 move to codecov and enable appveyor too 2015-06-14 21:17:52 +02:00
niphlod
d61c372c95 fix display of checkboxes in search form of grid 2015-06-11 21:54:21 +02:00
mdipierro
73e176365f Merge pull request #995 from niphlod/fix/994
fixes #994
2015-06-07 21:47:28 -05:00
mdipierro
33f12d91a5 Merge pull request #992 from btreecat/master
Fixed authentication using different login methods.
2015-06-07 21:47:08 -05:00
mdipierro
d0f1286f03 Merge pull request #991 from cs09g/patch-2
Update appadmin.py
2015-06-07 21:44:44 -05:00
mdipierro
04d698109e Merge pull request #990 from cs09g/patch-1
remove invalid initialize
2015-06-07 21:44:19 -05:00
mdipierro
0e9c5caf4d added request_reset_password_on... 2015-06-07 21:28:18 -05:00
niphlod
509b0a6987 fixes is_in_set repr too 2015-06-06 09:50:44 +02:00
niphlod
e0074ebcac fixes #994
we were overriding default classes for specific widgets
2015-06-05 22:10:33 +02:00
Stephen Tanner
918fdf2f0c Fixed authentication using different login methods. 2015-06-02 12:24:35 -04:00
Chase choi
8e827f7a09 Update appadmin.py 2015-06-02 01:28:51 +09:00
Chase choi
cf2d5b637b remove invalid initialize 2015-06-02 01:00:25 +09:00
mdipierro
236fdcfafc R-2.11.2 2015-05-30 11:30:16 -05:00
mdipierro
ce0f83d00c Merge pull request #988 from gi0baro/master
Track pyDAL 15.05.29
2015-05-30 11:29:09 -05:00
gi0baro
156d771ab3 Track pyDAL 15.05.29 2015-05-29 13:45:52 -05:00
mdipierro
01474c99b0 R-2.11.1 2015-05-28 23:22:16 -05:00
mdipierro
66d15491ca Merge pull request #984 from ilvalle/minorfix
lazy request.uuid
2015-05-28 23:17:21 -05:00
mdipierro
376a27da73 Merge pull request #983 from Euphorbium/patch-1
fix cPickle not defined error
2015-05-28 23:16:33 -05:00
mdipierro
0f95c13dc7 Merge pull request #981 from gi0baro/master
Track pyDAL 15.05.26
2015-05-28 23:16:02 -05:00
peregrinius
a2e7794b92 Invite user
Invite by email another user to access your application. Note, my
initial version was built on Auth.register_bare which doesn't seem to be
in this repository???
2015-05-29 15:22:36 +12:00
mdipierro
926de90ee4 fixed bug in orderby when it is a list 2015-05-28 13:59:03 -05:00
ilvalle
538f375284 lazy request.uuid 2015-05-28 18:30:06 +02:00
Juozas Masiulis
4c61c0962d fix cPickle not defined error 2015-05-28 14:29:43 +03:00
gi0baro
9b71646fc5 Track pyDAL 15.05.26 2015-05-26 14:36:04 +02:00
mdipierro
1e66fa3a93 new version number 2015-05-24 19:14:49 -05:00
mdipierro
57a8dfe034 Merge pull request #977 from austinprog/patch-1
Changed "Import about this GIT repo" Line 16, typo
2015-05-24 18:58:22 -05:00
mdipierro
77e7631740 Merge pull request #976 from niphlod/fix/ubuntu_nginx_hardening
thanks  @wmunguiam for spotting
2015-05-24 18:57:51 -05:00
mdipierro
ba978d55cf Merge pull request #975 from gi0baro/master
Track pyDAL 15.05
2015-05-24 18:57:36 -05:00
mdipierro
12e8ee5c25 Merge pull request #974 from niphlod/fix/redis_cache_multiapp
redis multi-app. Thanks Lisandro for spotting it
2015-05-24 18:57:26 -05:00
Austin
d293e98b43 Changed "Import about this GIT repo" Line 16, typo
My proposal is to change it to "Important reminder about this GIT Repo", as I think the "Import" part in the current one is a typo.
2015-05-24 18:13:03 -05:00
niphlod
4f316d0294 thanks @wmunguiam for spotting 2015-05-24 21:25:27 +02:00
gi0baro
81e15879d4 Track pyDAL 15.05 2015-05-23 16:37:52 +02:00
niphlod
cd1d6c5af1 redis multi-app. Thanks Lisandro for spotting it
redis_cache didn't play well with multiple apps for a silly mistake.
Glad that Lisadro pointed out
2015-05-21 22:26:04 +02:00
mdipierro
c7d3758c77 Merge pull request #973 from omniavx/patch-1
Update dal.py
2015-05-20 08:27:41 -05:00
mdipierro
040e52278e Merge pull request #956 from cassiobotaro/master
More changes in List (request.args)
2015-05-20 08:27:16 -05:00
mdipierro
3daf953c66 syncing maintenance again 2015-05-20 08:26:03 -05:00
mdipierro
de3d722ac9 fixed import, thanks Auden RovelleQuartz 2015-05-20 08:24:33 -05:00
omniavx
ff10eab373 Update dal.py
I was running my application and got this error

{
<type 'exceptions.ImportError'> cannot import name Set

Version
web2py™	Version 2.10.4-stable+timestamp.2015.04.26.15.11.54
Python	Python 2.7.3: /usr/bin/python (prefix: /usr)
Traceback
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
Traceback (most recent call last):
  File "/home/www-data/web2py/gluon/restricted.py", line 227, in restricted
    exec ccode in environment
  File "/home/www-data/web2py/applications/omniavx_cxn/controllers/valuecache.py", line 6897, in <module>
  File "/home/www-data/web2py/gluon/globals.py", line 393, in <lambda>
    self._caller = lambda f: f()
  File "/home/www-data/web2py/applications/omniavx_cxn/controllers/valuecache.py", line 6584, in browse_bacct_callback
    from plugin_PowerGrid.CallBack import CallBack
  File "/home/www-data/web2py/gluon/custom_import.py", line 95, in custom_importer
    return base_importer(pname, globals, locals, fromlist, level)
  File "/home/www-data/web2py/gluon/custom_import.py", line 134, in __call__
    result = NATIVE_IMPORTER(name, globals, locals, fromlist, level)
  File "applications/omniavx_cxn/modules/plugin_PowerGrid/CallBack.py", line 41, in <module>
    from gluon.dal import Table ,Query, Set, Rows, Row
ImportError: cannot import name Set
}

same code produced no error in earlier version of web2py



line 15 of web2py/gluon/dal.py is 
{
from pydal.objects import Row, Rows, Table, Query, Expression
}

replacing that with 
{
from pydal.objects import Row, Rows, Table, Query, Set, Expression

}

solves the problem
2015-05-20 00:11:46 -05:00
mdipierro
eb4d159b37 fixed process_batch_upload 2015-05-18 23:28:17 -05:00
Cássio Botaro
5ef7a8e9a1 maintains web2py pattern 2015-05-14 12:24:58 -03:00
mdipierro
76cfba7047 Merge pull request #964 from matclab/mail-send-lazy-to-unicode
#963 : Convert subject and body to unicode before sending mail
2015-05-14 09:17:04 -05:00
mdipierro
f77f307869 Merge pull request #970 from ailnlv/patch-1
Fixing https://github.com/web2py/web2py/issues/969
2015-05-14 09:16:52 -05:00
mdipierro
5ef8648929 Merge pull request #967 from bletourmy/fix/966
fixes #966 - deadlock in cache.disk
2015-05-14 09:16:31 -05:00
mdipierro
ed042685ea Merge pull request #965 from niphlod/fix/962
fixes #962
2015-05-14 09:16:10 -05:00
mdipierro
d09ce57f12 Merge pull request #961 from niphlod/fix/628
fixes #628
2015-05-14 09:14:06 -05:00
ailnlv
169818b275 Fixing https://github.com/web2py/web2py/issues/969
Running readline.parse_and_bind("bind ^I rl_complete") makes the letter "b" stop working on the console. This patch solves the issue and correctly enables tab completition on OSX.
2015-05-13 19:23:56 -03:00
Bernard Letourmy
4b14a87463 fixes #966 - deadlock in cache.disk 2015-05-13 09:35:22 +08:00
niphlod
cadf38b4f6 fixes #962 2015-05-11 21:24:20 +02:00
Mathieu Clabaut
a6226d6391 Convert subject and body to unicode before sending mail
Not doing this was raising an exception :

Traceback (most recent call last):
  File /base/data/home/apps/e~sacred-bonus-88417/1.384178859090314065/gluon/restricted.py, line 227, in restricted
    exec ccode in environment
  File /base/data/home/apps/e~sacred-bonus-88417/1.384178859090314065/applications/foundit/controllers/default.py, line 127, in <module>
  File /base/data/home/apps/e~sacred-bonus-88417/1.384178859090314065/gluon/globals.py, line 393, in <lambda>
    self._caller = lambda f: f()
  File /base/data/home/apps/e~sacred-bonus-88417/1.384178859090314065/applications/foundit/controllers/default.py, line 34, in user
    return dict(form=auth())
  File /base/data/home/apps/e~sacred-bonus-88417/1.384178859090314065/gluon/tools.py, line 1595, in __call__
    return getattr(self, args[0])()
  File /base/data/home/apps/e~sacred-bonus-88417/1.384178859090314065/gluon/tools.py, line 3272, in request_reset_password
    if self.email_reset_password(user):
  File /base/data/home/apps/e~sacred-bonus-88417/1.384178859090314065/gluon/tools.py, line 3296, in email_reset_password
    message=self.messages.reset_password % d):
  File /base/data/home/apps/e~sacred-bonus-88417/1.384178859090314065/gluon/tools.py, line 798, in send
    subject=subject, body=text, **xcc)
  File /base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/api/mail.py, line 402, in send_mail
    message.send(make_sync_call=make_sync_call)
  File /base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/api/mail.py, line 1108, in send
    message = self.ToProto()
  File /base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/api/mail.py, line 1350, in ToProto
    message = super(EmailMessage, self).ToProto()
  File /base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/api/mail.py, line 1046, in ToProto
    message.set_subject(_to_str(self.subject))
  File cpp_message.pyx, line 124, in cpp_message.SetScalarAccessors.Setter (third_party/apphosting/python/protobuf/proto1/cpp_message.cc:2229)
TypeError: <class 'gluon.languages.lazyT'> has type <class 'gluon.languages.lazyT'>, but expected one of: str, unicode
2015-05-09 18:24:09 +02:00
niphlod
5c167907eb fixes #628
response.include_files is now cleaner and easier to maintain

You can specify a tuple of (type, url) to include external assets
without extension (such as the usecase described in #628)

Added tests for include_files, that was never included in CI tests
2015-05-08 21:51:56 +02:00
mdipierro
587ff56a94 linked 15.03-maintenance again 2015-05-07 22:26:42 -05:00
mdipierro
6f91fdd833 minor refactoring in grid(orderby) 2015-05-06 08:56:56 -05:00
mdipierro
6e2f9ad043 fixed examples support 2015-05-04 11:23:44 -05:00
Cássio Botaro
cdca2793e0 Maintain py2.6k compability 2015-05-04 12:55:44 -03:00
Cássio Botaro
a0ee649884 Update tests
- new tests to verify old behaviour 
- test otherwise without cast and defaut
- verify if behave like a list 
- more test with call function
2015-05-04 12:49:14 -03:00
Cássio Botaro
380b491724 Return old behaviours
- Better documented List
- Otherwise not binded with cast
2015-05-04 12:41:06 -03:00
mdipierro
f45bf73992 Merge branch 'master' of github.com:web2py/web2py 2015-05-03 16:42:42 -05:00
mdipierro
94461724f6 Merge pull request #954 from cassiobotaro/master
Mantain backward compatibility
2015-05-03 16:42:12 -05:00
Cássio Botaro
c36c391786 More test to prove backward compatibility 2015-05-03 14:03:26 -03:00
Cássio Botaro
f6db7c995f Its necessary because of default=None trick 2015-05-03 14:02:11 -03:00
Cássio Botaro
ccc4b96709 Added one more test
Added one more test to avoid mistake with backward compatibility
2015-05-03 13:36:24 -03:00
Cássio Botaro
71b02e3044 Maintain backward compatibility
Little change to maintain backward compatibility, related to #590
2015-05-03 13:35:05 -03:00
mdipierro
99fb1c3010 Merge branch 'master' of github.com:web2py/web2py 2015-05-03 10:31:37 -05:00
mdipierro
20067d7b93 Merge pull request #953 from niphlod/fix/691
fixes issue #691
2015-05-03 10:31:32 -05:00
mdipierro
44eb35c617 Merge pull request #952 from niphlod/fix/734
fixes #734
2015-05-03 10:31:21 -05:00
mdipierro
df03317054 Merge pull request #951 from niphlod/tests/cache_ram_and_disk
more tests, general cleanup
2015-05-03 10:31:08 -05:00
mdipierro
9d873cbd1c reverted last commit 2015-05-03 10:30:43 -05:00
mdipierro
1bb4117cbd Merge pull request #950 from cassiobotaro/master
Fix List behaviour and added new feature
2015-05-03 10:27:46 -05:00
mdipierro
e834186a86 Merge pull request #950 from cassiobotaro/master
Fix List behaviour and added new feature
2015-05-03 10:23:08 -05:00
mdipierro
1394942feb removed reference to python 2.5 2015-05-03 10:09:07 -05:00
niphlod
32b9b5c799 fixes issue #691 2015-05-03 16:06:10 +02:00
niphlod
340d7b5e6f fixes #734 2015-05-03 15:51:13 +02:00
niphlod
302f56ecc1 more tests, general cleanup 2015-05-03 15:33:19 +02:00
mdipierro
9b12459a82 Merge branch 'master' of github.com:web2py/web2py 2015-05-02 23:16:12 -05:00
mdipierro
8e3925820c allow disabling of confirmation in js delete 2015-05-02 23:16:05 -05:00
mdipierro
279d71d4cd Merge pull request #936 from niphlod/enhancement/919
added newer Recaptcha2 class to deal with v2.0. Fixes #919
2015-05-02 23:07:36 -05:00
Cássio Botaro
258e2e57ae Fix import errors 2015-05-02 20:36:35 -03:00
cassiobotaro
9357d810d8 Fix List behaviour and added new feature 2015-05-02 20:24:04 -03:00
mdipierro
54b385b321 grid(user_cursor=False) by default because it is broken 2015-04-26 17:16:19 -05:00
mdipierro
df039e734c 2.10.4 stable 2015-04-26 10:10:18 -05:00
mdipierro
58533954dc R-2.10.4 2015-04-26 09:07:07 -05:00
mdipierro
236dc4b943 fixed submodule tracking 2015-04-26 09:04:55 -05:00
mdipierro
6612fd1cfe told git to track the right submodule branch 2015-04-26 08:50:16 -05:00
mdipierro
520950ba74 track track 15.03-maintenance (19/04/15) 2015-04-26 08:44:45 -05:00
mdipierro
e943aa9c25 minor compatibility fix in ldap_auth 2015-04-26 08:39:47 -05:00
mdipierro
756aec7206 Merge pull request #944 from stephenrauch/ldap_auth-fix-nosql
Fix ldap_auth for NoSQL databases
2015-04-26 08:29:26 -05:00
mdipierro
970e2ed35c Merge pull request #939 from smorrison/slack_webhook_support
add support for reporting web2py errors via slack.com
2015-04-26 08:29:00 -05:00
mdipierro
1388c39636 Merge pull request #935 from niphlod/docs/dal
extend underline for proper sphinx formatting
2015-04-26 08:27:48 -05:00
mdipierro
6e84737924 Merge pull request #934 from niphlod/fix/931
fixes #931 . Thanks @butsyk for spotting the bug
2015-04-26 08:27:35 -05:00
stephenrauch
0ad50630f2 Fix ldap_auth for NoSQL databases
Unroll query with join to two queries when working with DB's which don't
support joins.
2015-04-24 11:02:18 -07:00
Sean Morrison
f42ee15f5f add support for reporting web2py errors via slack.com 2015-04-22 19:00:21 -05:00
niphlod
77f154a56b added newer Recaptcha2 class to deal with v2.0. Fixes #919
Improvements over the "old" v1.0
- behaves well also without javascript
- use_ssl is redundant, v2.0 works only in https mode
- ajax is not useful anymore as the newer API is a lot easier

Adjusted also the addrow() method that was missing newer formstyles.
2015-04-22 00:10:05 +02:00
niphlod
2b0bfba649 extend underline for proper sphinx formatting 2015-04-21 23:59:07 +02:00
niphlod
9f1edf267d fixes #931 . Thanks @butsyk for spotting the bug 2015-04-21 21:59:42 +02:00
mdipierro
f3bda9ad02 changed version 2015-04-20 18:02:17 -05:00
mdipierro
f8afc76263 Merge pull request #930 from gi0baro/master
pydal -> track 15.03-maintenance (20/04/15)
2015-04-20 10:39:29 -05:00
gi0baro
65b4aaf842 pydal -> track 15.03-maintenance (20/04/15) 2015-04-20 17:29:22 +02:00
mdipierro
1b729cfbfc Merge pull request #928 from niphlod/fix/920
small typo. Fixes #920
2015-04-19 15:32:28 -05:00
mdipierro
1aa5f30091 Merge pull request #926 from niphlod/enhancement/web2py_on_iis
added web.config to deploy web2py on IIS
2015-04-19 15:32:11 -05:00
mdipierro
b17174c04c Merge pull request #925 from gi0baro/master
pydal -> track 15.03-maintenance (19/04/15)
2015-04-19 15:31:41 -05:00
niphlod
ac80adc9b4 small typo. Fixes #920 2015-04-19 19:49:25 +02:00
niphlod
888fa3dfc8 added setup script 2015-04-19 19:00:59 +02:00
niphlod
f3d815e84b added web.config to deploy web2py on IIS 2015-04-19 15:51:17 +02:00
gi0baro
9915fdf093 pydal -> track 15.03-maintenance (19/04/15) 2015-04-19 14:45:19 +02:00
mdipierro
ef8f802df9 R-2.10.4.beta 2015-04-18 15:44:04 -05:00
mdipierro
f7bf1020df reverted gluon/packages/dal 2015-04-18 15:28:12 -05:00
mdipierro
75b8ceb022 Merge pull request #923 from gi0baro/validators
Fix serializers injection over new pydal
2015-04-18 15:17:06 -05:00
mdipierro
b4f3784136 Merge pull request #922 from dokime7/patch-7
Fix crash with list:reference field
2015-04-18 15:16:25 -05:00
mdipierro
f1297bb827 Merge pull request #918 from niphlod/enhancement/anyserver
added waitress to anyserver
2015-04-18 15:15:02 -05:00
mdipierro
435ebeaae4 more consulting companies 2015-04-18 15:13:03 -05:00
gi0baro
537045082c Updated dal test due to new serializers 2015-04-18 15:08:39 +02:00
gi0baro
4bea52a7b5 Fix serializers injection over new pydal 2015-04-18 15:04:01 +02:00
Jeremie Dokime
33295e516f Fix crash with list:reference field
When using validate_and_update() or validate_and_insert() on a table with a list:reference field, the request crashes after timeout with:
  File "web2py/gluon/globals.py", line 270, in body
    raise HTTP(400, "Bad Request - HTTP body is incomplete")

The request crashes because there is an hidden exception with the isinstance function:
isinstance() arg 2 must be a class, type, or tuple of classes and types

When no using GAE, the GoogleDatastoreAdapter variable is None, so isinstance crash.
See the last line of pydal/adapters/__init__.py

This is a regression intruduced after the v2.9.12.
2015-04-18 02:15:45 +02:00
mdipierro
f33ccf3366 experimental fix for represent 2015-04-16 16:53:12 -05:00
niphlod
0784680c90 added waitress to anyserver 2015-04-15 23:55:44 +02:00
mdipierro
e940228eaf Merge pull request #912 from ilvalle/sqlcustomtype
extend sqlcustomform to support widget/represent
2015-04-15 13:01:50 -05:00
mdipierro
50769a627a Merge pull request #916 from gi0baro/issue-904
Fixes #904
2015-04-15 13:01:19 -05:00
mdipierro
e68ecaa131 Merge pull request #915 from BuhtigithuB/update/gluon-contrib-pypyodbc
Update gluon/contrib/pypyodbc.py 1.3.0 -> 1.3.3
2015-04-15 13:01:01 -05:00
gi0baro
95e6e8577b Fixes #904 2015-04-14 15:25:26 +02:00
Hardirc
19c83d4ad6 Update gluon/contrib/pypyodbc.py 1.3.0 -> 1.3.3 2015-04-13 18:43:48 -04:00
ilvalle
9c92bd1050 extend sqlcustomform to support widget/represent (possible fix to web2py/pydal#127) 2015-04-12 21:04:05 +02:00
mdipierro
b3b95ccf5f Merge pull request #906 from niphlod/fix/895
file is already open at this point... fixes #895
2015-04-08 23:24:16 -05:00
niphlod
cefa30841b file is already open at this point... fixes #895 2015-04-08 21:47:04 +02:00
mdipierro
15ff8669cb fixed dal tracking, thanks Niphlod 2015-04-06 16:24:49 -05:00
mdipierro
a921751e8e stripe form bs3 compatible, disabled cache.ram max utilization 2015-04-05 18:17:27 -05:00
pallav_fdsi
842207ab33 Merge branch 'master' of https://github.com/web2py/web2py 2015-04-04 19:51:26 -04:00
mdipierro
b02e8a6d5f fixed problem with custom import and upgraded jquery.js 2015-04-02 16:30:15 -05:00
mdipierro
a2b17967cf Merge pull request #898 from ilvalle/issue-896
fix web2py/web2py#896, avoid to select blob fields in sqlform.grid
2015-04-02 16:24:26 -05:00
mdipierro
343ebf1714 Merge pull request #897 from BuhtigithuB/update-contrib/feedparser-py
Update gluon/contrib/feedparser.py from 5.1.2 -> 5.1.3
2015-04-02 16:23:34 -05:00
mdipierro
e330791fe3 Merge pull request #894 from niphlod/fix/windows_build
fix windows build
2015-04-02 16:22:49 -05:00
mdipierro
5e1e97ffc4 Merge pull request #893 from niphlod/fix/duplicate_module
not needed anymore module
2015-04-02 16:20:39 -05:00
ilvalle
60f8816a10 fix web2py/web2py#896, avoid to select blob fields in sqlform.grid 2015-04-02 21:38:05 +02:00
Richard Vézina
6187c89ba6 Update gluon/contrib/feedparser.py from 5.1.2 -> 5.1.3 2015-04-02 13:58:48 -04:00
niphlod
e441e15907 fix windows build 2015-04-01 21:35:52 +02:00
niphlod
e6c3410639 not needed anymore module 2015-04-01 20:55:47 +02:00
mdipierro
6b6cb5839c Merge branch 'master' of github.com:web2py/web2py 2015-04-01 13:55:07 -05:00
mdipierro
2a7e9c0c59 possible fix for issue #892 2015-04-01 13:54:48 -05:00
mdipierro
5b637c0a82 Merge pull request #891 from leonelcamara/cache_cleanup
Fixes issue with locked files during cleanup
2015-04-01 12:41:52 -05:00
Leonel Câmara
5cdd7c1215 Fixes issue with locked files during cleanup 2015-04-01 18:27:05 +01:00
mdipierro
0aade6b378 R-2.10.2 2015-03-31 22:26:25 -05:00
mdipierro
5b75130187 quick fix for cacheondisk problem and admin 2015-03-31 22:25:10 -05:00
pallav_fdsi
c58f29bb9c Merge branch 'master' of https://github.com/web2py/web2py 2015-01-25 15:58:39 -05:00
pallav_fdsi
0b0f82b514 Merge branch 'master' of https://github.com/web2py/web2py 2014-11-21 00:29:14 -05:00
pallav_fdsi
3ab8a7bfd6 Merge branch 'master' of https://github.com/web2py/web2py 2014-11-11 00:21:27 -05:00
pallav_fdsi
c5a9d2c456 Ignore the contents of the site-packages directory 2014-11-06 10:35:49 -05:00
184 changed files with 15760 additions and 13403 deletions

2
.gitignore vendored
View File

@@ -58,3 +58,5 @@ HOWTO-web2py-devel
*.sublime-project
*.sublime-workspace
.idea/*
site-packages/
logs/

View File

@@ -12,19 +12,40 @@ python:
- 'pypy'
install:
- |
if [ "$TRAVIS_PYTHON_VERSION" = "pypy" ]; then
export PYENV_ROOT="$HOME/.pyenv"
if [ -f "$PYENV_ROOT/bin/pyenv" ]; then
pushd "$PYENV_ROOT" && git pull && popd
else
rm -rf "$PYENV_ROOT" && git clone --depth 1 https://github.com/yyuu/pyenv.git "$PYENV_ROOT"
fi
export PYPY_VERSION="5.0.1"
"$PYENV_ROOT/bin/pyenv" install --skip-existing "pypy-$PYPY_VERSION"
virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python" "$HOME/virtualenvs/pypy-$PYPY_VERSION"
source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate"
fi
- pip install -e .
before_script:
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install --download-cache $HOME/.pip-cache unittest2; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --download-cache $HOME/.pip-cache coverage; fi;
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --download-cache $HOME/.pip-cache python-coveralls; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --download-cache $HOME/.pip-cache codecov; fi
- mysql -e 'create database pydal;'
- psql -c 'create database pydal;' -U postgres
- psql -c 'create extension postgis;' -U postgres -d pydal;
- psql -c 'SHOW SERVER_VERSION' -U postgres
script: export COVERAGE_PROCESS_START=gluon/tests/coverage.ini; ./web2py.py --run_system_tests --with_coverage
after_success:
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then coverage combine; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then coveralls --config_file=gluon/tests/coverage.ini; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then codecov; fi
notifications:
email: true
addons:
postgresql: "9.4"

View File

@@ -1,4 +1,97 @@
## 2.10.1
## 2.14.6
- Increased test coverage (thanks Richard)
- Fixed some newly discovered security issues in admin:
CSRF vulnerability in admin that allows disabling apps
Brute force password attack vulnerability in admin
(thanks Narendra and Leonel)
## 2.14.1-5
- fixed two major security issues that caused the examples app to leak information
- new Auth(…,host_names=[…]) to prevent host header injection
- improved scheduler
- pep8 enhancements
- many bug fixes
- restored GAE support that was broken in 2.13.*
- improved fabfile for deployment
- refactored examples with stupid.css
- new JWT implementation (experimental)
- new gluon.contrib.redis_scheduler
- myconf.get
- LDAP groups (experimental)
- .flash -> .w2p_flash
- Updated feedparser.py 5.2.1
- Updated jQuery 1.12.2
- welcome app now checks for version number
- Redis improvements. New syntax:
BEFORE:
from gluon.contrib.redis_cache import RedisCache
cache.redis = RedisCache('localhost:6379',db=None, debug=True)
NOW:
from gluon.contrib.redis_utils import RConn
from gluon.contrib.redis_cache import RedisCache
rconn = RConn()
# or RConn(host='localhost', port=6379,
# db=0, password=None, socket_timeout=None,
# socket_connect_timeout=None, .....)
# exactly as a redis.StrictRedis instance
cache.redis = RedisCache(redis_conn=rconn, debug=True)
BEFORE:
from gluon.contrib.redis_session import RedisSession
sessiondb = RedisSession('localhost:6379',db=0, session_expiry=False)
session.connect(request, response, db = sessiondb)
NOW:
from gluon.contrib.redis_utils import RConn
from gluon.contrib.redis_session import RedisSession
rconn = RConn()
sessiondb = RedisSession(redis_conn=rconn, session_expiry=False)
session.connect(request, response, db = sessiondb)
Many thanks to Richard and Simone for their work and dedication.
## 2.13.*
- fixed a security issue in request_reset_password
- added fabfile.py
- fixed oauth2 renew token, thanks dokime7
- fixed add_membership, del_membership, add_membership IntegrityError (when auth.enable_record_versioning)
- allow passing unicode to template render
- allow IS_NOT_IN_DB to work with custom primarykey, thanks timmyborg
- allow HttpOnly cookies
- french pluralizaiton rules, thanks Mathieu Clabaut
- fixed bug in redirect to cas service, thanks Fernando González
- allow deploying to pythonanywhere from the web2py admin that you're running locally, thanks Leonel
- better tests
- many more bug fixes
## 2.12.1-3
- security fix: Validate for open redirect everywhere, not just in login()
- allow to pack invidual apps and selected files as packed exe files
- allow bulk user registration with default bulk_register_enabled=False
- allow unsorted multiword query in grid search
- better MongoDB support with newer pyDAL
- enable <app>/appadmin/manage/auth by default for user admin
- allow mail.settings.server='logging:filename' to log emails to a file
- better caching logic
- fixed order of confirm-password field
- TLS support in ldap
- prettydate can do UTC
- jquery 1.11.3
- bootstrap 3.3.5
- moved to codecov and enabled appveyor
- many bug fixes
## 2.11.1
- Many small but significative improvements and bug fixes
## 2.10.1-2.10.2
- welcome app defaults to Bootstrap 3
- DAL -> pyDAL (thanks Giovanni, Niphlod, Paolo)

View File

@@ -11,7 +11,7 @@ clean:
find ./ -name '*.rej' -exec rm -f {} \;
find ./ -name '#*' -exec rm -f {} \;
find ./ -name 'Thumbs.db' -exec rm -f {} \;
find ./gluon/ -name '.*' -exec rm -f {} \;
# find ./gluon/ -name '.*' -exec rm -f {} \;
find ./gluon/ -name '*class' -exec rm -f {} \;
find ./applications/admin/ -name '.*' -exec rm -f {} \;
find ./applications/examples/ -name '.*' -exec rm -f {} \;
@@ -32,7 +32,7 @@ update:
echo "remember that pymysql was tweaked"
src:
### Use semantic versioning
echo 'Version 2.10.1-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
echo 'Version 2.14.6-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
### rm -f all junk files
make clean
### clean up baisc apps

View File

@@ -13,7 +13,7 @@ Learn more at http://web2py.com
Then edit ./app.yaml and replace "yourappname" with yourappname.
## Import about this GIT repo
## Important reminder about this GIT repo
An important part of web2py is the Database Abstraction Layer (DAL). In early 2015 this was decoupled into a separate code-base (PyDAL). In terms of git, it is a sub-module of the main repository.
@@ -38,9 +38,10 @@ PyDAL uses a separate stable release cycle to the rest of web2py. PyDAL releases
## Tests
[![Build Status](https://img.shields.io/travis/web2py/web2py.svg?style=flat-square)](https://travis-ci.org/web2py/web2py)
[![Build Status](https://img.shields.io/travis/web2py/web2py/master.svg?style=flat-square&label=Travis-CI)](https://travis-ci.org/web2py/web2py)
[![MS Build Status](https://img.shields.io/appveyor/ci/web2py/web2py/master.svg?style=flat-square&label=Appveyor-CI)](https://ci.appveyor.com/project/web2py/web2py)
[![Coverage Status](https://img.shields.io/codecov/c/github/web2py/web2py.svg?style=flat-square)](https://codecov.io/github/web2py/web2py)
[![Coverage Status](https://img.shields.io/coveralls/web2py/web2py.svg?style=flat-square)](https://coveralls.io/r/web2py/web2py)
## Installation Instructions
@@ -63,7 +64,7 @@ That's it!!!
packages/ > web2py submodules
dal/
contrib/ > third party libraries
tests/ > unittests
tests/ > unittests
applications/ > are the apps
admin/ > web based IDE
...

View File

@@ -1 +1 @@
Version 2.10.1-stable+timestamp.2015.03.31.15.15.31
Version 2.14.6-stable+timestamp.2016.05.09.19.18.48

View File

@@ -180,6 +180,11 @@ class Servers:
s = wsgi.WSGIServer(callable=app, bind="%s:%d" % address)
s.start()
@staticmethod
def waitress(app, address, **options):
from waitress import serve
serve(app, host=address[0], port=address[1], _quiet=True)
def mongrel2_handler(application, conn, debug=False):
"""

View File

@@ -49,7 +49,8 @@ if request.function == 'manage':
auth.table_group(),
auth.table_permission()])
manager_role = manager_action.get('role', None) if manager_action else None
auth.requires_membership(manager_role)(lambda: None)()
if not (gluon.fileutils.check_credentials(request) or auth.has_membership(manager_role)):
raise HTTP(403, "Not authorized")
menu = False
elif (request.application == 'admin' and not session.authorized) or \
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
@@ -80,7 +81,6 @@ if False and request.tickets_db:
def get_databases(request):
dbs = {}
for (key, value) in global_env.items():
cond = False
try:
cond = isinstance(value, GQLDB)
except:
@@ -420,7 +420,7 @@ def ccache():
'oldest': time.time(),
'keys': []
}
disk = copy.copy(ram)
total = copy.copy(ram)
disk['keys'] = []
@@ -445,30 +445,31 @@ def ccache():
gae_stats['oldest'] = GetInHMS(time.time() - gae_stats['oldest_item_age'])
total.update(gae_stats)
else:
# get ram stats directly from the cache object
ram_stats = cache.ram.stats[request.application]
ram['hits'] = ram_stats['hit_total'] - ram_stats['misses']
ram['misses'] = ram_stats['misses']
try:
ram['ratio'] = ram['hits'] * 100 / ram_stats['hit_total']
except (KeyError, ZeroDivisionError):
ram['ratio'] = 0
for key, value in cache.ram.storage.iteritems():
if isinstance(value, dict):
ram['hits'] = value['hit_total'] - value['misses']
ram['misses'] = value['misses']
try:
ram['ratio'] = ram['hits'] * 100 / value['hit_total']
except (KeyError, ZeroDivisionError):
ram['ratio'] = 0
else:
if hp:
ram['bytes'] += hp.iso(value[1]).size
ram['objects'] += hp.iso(value[1]).count
ram['entries'] += 1
if value[0] < ram['oldest']:
ram['oldest'] = value[0]
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
if hp:
ram['bytes'] += hp.iso(value[1]).size
ram['objects'] += hp.iso(value[1]).count
ram['entries'] += 1
if value[0] < ram['oldest']:
ram['oldest'] = value[0]
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
for key in cache.disk.storage:
value = cache.disk.storage[key]
if isinstance(value, dict):
disk['hits'] = value['hit_total'] - value['misses']
disk['misses'] = value['misses']
if isinstance(value[1], dict):
disk['hits'] = value[1]['hit_total'] - value[1]['misses']
disk['misses'] = value[1]['misses']
try:
disk['ratio'] = disk['hits'] * 100 / value['hit_total']
disk['ratio'] = disk['hits'] * 100 / value[1]['hit_total']
except (KeyError, ZeroDivisionError):
disk['ratio'] = 0
else:
@@ -480,12 +481,12 @@ def ccache():
disk['oldest'] = value[0]
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
total['entries'] = ram['entries'] + disk['entries']
total['bytes'] = ram['bytes'] + disk['bytes']
total['objects'] = ram['objects'] + disk['objects']
total['hits'] = ram['hits'] + disk['hits']
total['misses'] = ram['misses'] + disk['misses']
total['keys'] = ram['keys'] + disk['keys']
ram_keys = ram.keys() # ['hits', 'objects', 'ratio', 'entries', 'keys', 'oldest', 'bytes', 'misses']
ram_keys.remove('ratio')
ram_keys.remove('oldest')
for key in ram_keys:
total[key] = ram[key] + disk[key]
try:
total['ratio'] = total['hits'] * 100 / (total['hits'] +
total['misses'])
@@ -575,11 +576,9 @@ def bg_graph_model():
meta_graphmodel = dict(group=request.application, color='#ECECEC')
group = meta_graphmodel['group'].replace(' ', '')
if not subgraphs.has_key(group):
if group not in subgraphs:
subgraphs[group] = dict(meta=meta_graphmodel, tables=[])
subgraphs[group]['tables'].append(tablename)
else:
subgraphs[group]['tables'].append(tablename)
subgraphs[group]['tables'].append(tablename)
graph.add_node(tablename, name=tablename, shape='plaintext',
label=table_template(tablename))

View File

@@ -220,7 +220,7 @@ def list_breakpoints():
"Return a list of linenumbers for current breakpoints"
breakpoints = []
ok = None
ok = False
try:
filename = os.path.join(request.env['applications_parent'],
'applications', request.vars.filename)
@@ -235,5 +235,4 @@ def list_breakpoints():
ok = True
except Exception, e:
session.flash = str(e)
ok = False
return response.json({'ok': ok, 'breakpoints': breakpoints})

View File

@@ -32,15 +32,15 @@ from gluon.languages import (read_possible_languages, read_dict, write_dict,
if DEMO_MODE and request.function in ['change_password', 'pack',
'pack_custom','pack_plugin', 'upgrade_web2py', 'uninstall',
'cleanup', 'compile_app', 'remove_compiled_app', 'delete',
'delete_plugin', 'create_file', 'upload_file', 'update_languages',
'reload_routes', 'git_push', 'git_pull', 'install_plugin']:
'pack_custom', 'pack_plugin', 'upgrade_web2py', 'uninstall',
'cleanup', 'compile_app', 'remove_compiled_app', 'delete',
'delete_plugin', 'create_file', 'upload_file', 'update_languages',
'reload_routes', 'git_push', 'git_pull', 'install_plugin']:
session.flash = T('disabled in demo mode')
redirect(URL('site'))
if is_gae and request.function in ('edit', 'edit_language',
'edit_plurals', 'update_languages', 'create_file', 'install_plugin'):
'edit_plurals', 'update_languages', 'create_file', 'install_plugin'):
session.flash = T('disabled in GAE mode')
redirect(URL('site'))
@@ -74,8 +74,10 @@ def log_progress(app, mode='EDIT', filename=None, progress=0):
def safe_open(a, b):
if (DEMO_MODE or is_gae) and ('w' in b or 'a' in b):
class tmp:
def write(self, data):
pass
def close(self):
pass
return tmp()
@@ -119,6 +121,9 @@ def index():
send = URL('site')
if session.authorized:
redirect(send)
elif failed_login_count() >= allowed_number_of_attempts:
time.sleep(2 ** allowed_number_of_attempts)
raise HTTP(403)
elif request.vars.password:
if verify_password(request.vars.password[:1024]):
session.authorized = True
@@ -208,6 +213,7 @@ def site():
file_or_appurl = 'file' in request.vars or 'appurl' in request.vars
class IS_VALID_APPNAME(object):
def __call__(self, value):
if not re.compile('^\w+$').match(value):
return (value, T('Invalid application name'))
@@ -268,7 +274,7 @@ def site():
raise Exception("404 file not found")
except Exception, e:
session.flash = \
DIV(T('Unable to download app because:'), PRE(str(e)))
DIV(T('Unable to download app because:'), PRE(repr(e)))
redirect(URL(r=request))
fname = form_update.vars.url
@@ -292,9 +298,6 @@ def site():
log_progress(appname)
session.flash = T(msg, dict(appname=appname,
digest=md5_hash(installed)))
elif f and form_update.vars.overwrite:
msg = 'unable to install application "%(appname)s"'
session.flash = T(msg, dict(appname=form_update.vars.name))
else:
msg = 'unable to install application "%(appname)s"'
session.flash = T(msg, dict(appname=form_update.vars.name))
@@ -328,7 +331,7 @@ def report_progress(app):
if not m:
continue
days = -(request.now - datetime.datetime.strptime(m[0],
'%Y-%m-%d %H:%M:%S')).days
'%Y-%m-%d %H:%M:%S')).days
counter += int(m[1])
events.append([days, counter])
return events
@@ -356,6 +359,7 @@ def pack():
session.flash = T('internal error: %s', e)
redirect(URL('site'))
def pack_plugin():
app = get_app()
if len(request.args) == 2:
@@ -370,31 +374,66 @@ def pack_plugin():
session.flash = T('internal error')
redirect(URL('plugin', args=request.args))
def pack_exe(app, base, filenames=None):
import urllib
import zipfile
from cStringIO import StringIO
# Download latest web2py_win and open it with zipfile
download_url = 'http://www.web2py.com/examples/static/web2py_win.zip'
out = StringIO()
out.write(urllib.urlopen(download_url).read())
web2py_win = zipfile.ZipFile(out, mode='a')
# Write routes.py with the application as default
routes = u'# -*- coding: utf-8 -*-\nrouters = dict(BASE=dict(default_application="%s"))' % app
web2py_win.writestr('web2py/routes.py', routes.encode('utf-8'))
# Copy the application into the zipfile
common_root = os.path.dirname(base)
for filename in filenames:
fname = os.path.join(base, filename)
arcname = os.path.join('web2py/applications', app, filename)
web2py_win.write(fname, arcname)
web2py_win.close()
response.headers['Content-Type'] = 'application/zip'
response.headers['Content-Disposition'] = 'attachment; filename=web2py.app.%s.zip' % app
out.seek(0)
return response.stream(out)
def pack_custom():
app = get_app()
base = apath(app, r=request)
if request.post_vars.file:
files = request.post_vars.file
files = [files] if not isinstance(files,list) else files
fname = 'web2py.app.%s.w2p' % app
try:
filename = app_pack(app, request, raise_ex=True, filenames=files)
except Exception, e:
filename = None
if filename:
response.headers['Content-Type'] = 'application/w2p'
disposition = 'attachment; filename=%s' % fname
response.headers['Content-Disposition'] = disposition
return safe_read(filename, 'rb')
else:
session.flash = T('internal error: %s', e)
redirect(URL(args=request.args))
def ignore(fs):
return [f for f in fs if not (
f[:1] in '#' or f.endswith('~') or f.endswith('.bak'))]
files = {}
for (r,d,f) in os.walk(base):
files[r] = {'folders':ignore(d),'files':ignore(f)}
for (r, d, f) in os.walk(base):
files[r] = {'folders': ignore(d), 'files': ignore(f)}
if request.post_vars.file:
valid_set = set(os.path.relpath(os.path.join(r, f), base) for r in files for f in files[r]['files'])
files = request.post_vars.file
files = [files] if not isinstance(files, list) else files
files = [file for file in files if file in valid_set]
if request.post_vars.doexe is None:
fname = 'web2py.app.%s.w2p' % app
try:
filename = app_pack(app, request, raise_ex=True, filenames=files)
except Exception, e:
filename = None
if filename:
response.headers['Content-Type'] = 'application/w2p'
disposition = 'attachment; filename=%s' % fname
response.headers['Content-Disposition'] = disposition
return safe_read(filename, 'rb')
else:
session.flash = T('internal error: %s', e)
redirect(URL(args=request.args))
else:
return pack_exe(app, base, files)
return locals()
@@ -456,9 +495,15 @@ def cleanup():
def compile_app():
app = get_app()
c = app_compile(app, request)
c = app_compile(app, request,
skip_failed_views=(request.args(1) == 'skip_failed_views'))
if not c:
session.flash = T('application compiled')
elif isinstance(c, list):
session.flash = DIV(*[T('application compiled'), BR(), BR(),
T('WARNING: The following views could not be compiled:'), BR()] +
[CAT(BR(), view) for view in c] +
[BR(), BR(), T('DO NOT use the "Pack compiled" feature.')])
else:
session.flash = DIV(T('Cannot compile: there are errors in your app:'),
CODE(c))
@@ -499,8 +544,8 @@ def delete():
redirect(URL(sender, anchor=request.vars.id2))
return dict(dialog=dialog, filename=filename)
def enable():
if not URL.verify(request, hmac_key=session.hmac_key): raise HTTP(401)
app = get_app()
filename = os.path.join(apath(app, r=request), 'DISABLED')
if is_gae:
@@ -512,6 +557,7 @@ def enable():
safe_open(filename, 'wb').write('disabled: True\ntime-disabled: %s' % request.now)
return SPAN(T('Enable'), _style='color:red')
def peek():
""" Visualize object code """
app = get_app(request.vars.app)
@@ -575,7 +621,7 @@ def edit():
# Load json only if it is ajax edited...
app = get_app(request.vars.app)
app_path = apath(app, r=request)
preferences={'theme':'web2py', 'editor': 'default', 'closetag': 'true', 'codefolding': 'false', 'tabwidth':'4', 'indentwithtabs':'false', 'linenumbers':'true', 'highlightline':'true'}
preferences = {'theme': 'web2py', 'editor': 'default', 'closetag': 'true', 'codefolding': 'false', 'tabwidth': '4', 'indentwithtabs': 'false', 'linenumbers': 'true', 'highlightline': 'true'}
config = Config(os.path.join(request.folder, 'settings.cfg'),
section='editor', default_values={})
preferences.update(config.read())
@@ -583,14 +629,14 @@ def edit():
if not(request.ajax) and not(is_mobile):
# return the scaffolding, the rest will be through ajax requests
response.title = T('Editing %s') % app
return response.render ('default/edit.html', dict(app=app, editor_settings=preferences))
return response.render('default/edit.html', dict(app=app, editor_settings=preferences))
# show settings tab and save prefernces
if 'settings' in request.vars:
if request.post_vars: #save new preferences
if request.post_vars: # save new preferences
post_vars = request.post_vars.items()
# Since unchecked checkbox are not serialized, we must set them as false by hand to store the correct preference in the settings
post_vars+= [(opt, 'false') for opt in preferences if opt not in request.post_vars ]
post_vars += [(opt, 'false') for opt in preferences if opt not in request.post_vars]
if config.save(post_vars):
response.headers["web2py-component-flash"] = T('Preferences saved correctly')
else:
@@ -598,8 +644,8 @@ def edit():
response.headers["web2py-component-command"] = "update_editor(%s);$('a[href=#editor_settings] button.close').click();" % response.json(config.read())
return
else:
details = {'realfilename':'settings', 'filename':'settings', 'id':'editor_settings', 'force': False}
details['plain_html'] = response.render('default/editor_settings.html', {'editor_settings':preferences})
details = {'realfilename': 'settings', 'filename': 'settings', 'id': 'editor_settings', 'force': False}
details['plain_html'] = response.render('default/editor_settings.html', {'editor_settings': preferences})
return response.json(details)
""" File edit handler """
@@ -706,7 +752,7 @@ def edit():
B(ex_name), ' ' + T('at line %s', e.lineno),
offset and ' ' +
T('at char %s', offset) or '',
PRE(str(e)))
PRE(repr(e)))
if data_or_revert and request.args[1] == 'modules':
# Lets try to reload the modules
try:
@@ -717,7 +763,7 @@ def edit():
% (request.args[0], mopath)])
except Exception, e:
response.flash = DIV(
T('failed to reload module because:'), PRE(str(e)))
T('failed to reload module because:'), PRE(repr(e)))
edit_controller = None
editviewlinks = None
@@ -730,8 +776,8 @@ def edit():
view = request.args[3].replace('.html', '')
view_link = URL(request.args[0], request.args[2], view)
elif filetype == 'python' and request.args[1] == 'controllers':
## it's a controller file.
## Create links to all of the associated view files.
# it's a controller file.
# Create links to all of the associated view files.
app = get_app()
viewname = os.path.splitext(request.args[2])[0]
viewpath = os.path.join(app, 'views', viewname)
@@ -744,7 +790,7 @@ def edit():
viewlist.append(aviewpath + '.html')
if len(viewlist):
editviewlinks = []
for v in viewlist:
for v in sorted(viewlist):
vf = os.path.split(v)[-1]
vargs = "/".join([viewpath.replace(os.sep, "/"), vf])
editviewlinks.append(A(vf.split(".")[0],
@@ -754,6 +800,7 @@ def edit():
if len(request.args) > 2 and request.args[1] == 'controllers':
controller = (request.args[2])[:-3]
functions = find_exposed_functions(data)
functions = functions and sorted(functions) or []
else:
(controller, functions) = (None, None)
@@ -761,22 +808,22 @@ def edit():
return response.json({'file_hash': file_hash, 'saved_on': saved_on, 'functions': functions, 'controller': controller, 'application': request.args[0], 'highlight': highlight})
else:
file_details = dict(app=request.args[0],
lineno=request.vars.lineno or 1,
editor_settings=preferences,
filename=filename,
realfilename=realfilename,
filetype=filetype,
data=data,
edit_controller=edit_controller,
file_hash=file_hash,
saved_on=saved_on,
controller=controller,
functions=functions,
view_link=view_link,
editviewlinks=editviewlinks,
id=IS_SLUG()(filename)[0],
force= True if (request.vars.restore or
request.vars.revert) else False)
lineno=request.vars.lineno or 1,
editor_settings=preferences,
filename=filename,
realfilename=realfilename,
filetype=filetype,
data=data,
edit_controller=edit_controller,
file_hash=file_hash,
saved_on=saved_on,
controller=controller,
functions=functions,
view_link=view_link,
editviewlinks=editviewlinks,
id=IS_SLUG()(filename)[0],
force=True if (request.vars.restore or
request.vars.revert) else False)
plain_html = response.render('default/edit_js.html', file_details)
file_details['plain_html'] = plain_html
if is_mobile:
@@ -785,14 +832,16 @@ def edit():
else:
return response.json(file_details)
def todolist():
""" Returns all TODO of the requested app
"""
app = request.vars.app or ''
app_path = apath('%(app)s' % {'app':app}, r=request)
dirs=['models', 'controllers', 'modules', 'private' ]
app_path = apath('%(app)s' % {'app': app}, r=request)
dirs = ['models', 'controllers', 'modules', 'private']
def listfiles(app, dir, regexp='.*\.py$'):
files = sorted( listdir(apath('%(app)s/%(dir)s/' % {'app':app, 'dir':dir}, r=request), regexp))
files = sorted(listdir(apath('%(app)s/%(dir)s/' % {'app': app, 'dir': dir}, r=request), regexp))
files = [x.replace(os.path.sep, '/') for x in files if not x.endswith('.bak')]
return files
@@ -803,17 +852,18 @@ def todolist():
for d in dirs:
for f in listfiles(app, d):
matches = []
filename= apath(os.path.join(app, d, f), r=request)
filename = apath(os.path.join(app, d, f), r=request)
with open(filename, 'r') as f_s:
src = f_s.read()
for m in regex.finditer(src):
start = m.start()
lineno = src.count('\n', 0, start) + 1
matches.append({'text':m.group(0), 'lineno':lineno})
matches.append({'text': m.group(0), 'lineno': lineno})
if len(matches) != 0:
output.append({'filename':f,'matches':matches, 'dir':d})
output.append({'filename': f, 'matches': matches, 'dir': d})
return {'todo': output, 'app': app}
return {'todo':output, 'app': app}
def editor_sessions():
config = Config(os.path.join(request.folder, 'settings.cfg'),
@@ -823,13 +873,14 @@ def editor_sessions():
if request.vars.session_name and request.vars.files:
session_name = request.vars.session_name
files = request.vars.files
preferences.update({session_name:','.join(files)})
preferences.update({session_name: ','.join(files)})
if config.save(preferences.items()):
response.headers["web2py-component-flash"] = T('Session saved correctly')
else:
response.headers["web2py-component-flash"] = T('Session saved on session only')
return response.render('default/editor_sessions.html', {'editor_sessions':preferences})
return response.render('default/editor_sessions.html', {'editor_sessions': preferences})
def resolve():
"""
@@ -866,13 +917,9 @@ def resolve():
def getclass(item):
""" Determine item class """
operators = {' ': 'normal', '+': 'plus', '-': 'minus'}
if item[0] == ' ':
return 'normal'
if item[0] == '+':
return 'plus'
if item[0] == '-':
return 'minus'
return operators[item[0]]
if request.vars:
c = '\n'.join([item[2:].rstrip() for (i, item) in enumerate(d) if item[0]
@@ -890,7 +937,7 @@ def resolve():
diff = TABLE(*[TR(TD(gen_data(i, item)),
TD(item[0]),
TD(leading(item[2:]),
TT(item[2:].rstrip())),
TT(item[2:].rstrip())),
_class=getclass(item))
for (i, item) in enumerate(d) if item[0] != '?'])
@@ -937,11 +984,11 @@ def edit_language():
new_row = DIV(LABEL(prefix, k, _style="font-weight:normal;"),
CAT(elem, '\n', TAG.BUTTON(
T('delete'),
_onclick='return delkey("%s")' % name,
_class='btn')), _id=name, _class='span6 well well-small')
T('delete'),
_onclick='return delkey("%s")' % name,
_class='btn')), _id=name, _class='span6 well well-small')
rows.append(DIV(new_row,_class="row-fluid"))
rows.append(DIV(new_row, _class="row-fluid"))
rows.append(DIV(INPUT(_type='submit', _value=T('update'), _class="btn btn-primary"), _class='controls'))
form = FORM(*rows)
if form.accepts(request.vars, keepvalues=True):
@@ -1067,7 +1114,7 @@ def design():
for c in controllers:
data = safe_read(apath('%s/controllers/%s' % (app, c), r=request))
items = find_exposed_functions(data)
functions[c] = items
functions[c] = items and sorted(items) or []
# Get all views
views = sorted(
@@ -1097,18 +1144,18 @@ def design():
# Get all static files
statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*',
maxnum = MAXNFILES)
maxnum=MAXNFILES)
statics = [x.replace(os.path.sep, '/') for x in statics]
statics.sort()
# Get all languages
langpath = os.path.join(apath(app, r=request),'languages')
langpath = os.path.join(apath(app, r=request), 'languages')
languages = dict([(lang, info) for lang, info
in read_possible_languages(langpath).iteritems()
if info[2] != 0]) # info[2] is langfile_mtime:
# get only existed files
# get only existed files
#Get crontab
# Get crontab
cronfolder = apath('%s/cron' % app, r=request)
crontab = apath('%s/cron/crontab' % app, r=request)
if not is_gae:
@@ -1205,7 +1252,7 @@ def plugin():
for c in controllers:
data = safe_read(apath('%s/controllers/%s' % (app, c), r=request))
items = find_exposed_functions(data)
functions[c] = items
functions[c] = items and sorted(items) or []
# Get all views
views = sorted(
@@ -1234,7 +1281,7 @@ def plugin():
# Get all static files
statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*',
maxnum = MAXNFILES)
maxnum=MAXNFILES)
statics = [x.replace(os.path.sep, '/') for x in statics]
statics.sort()
@@ -1242,9 +1289,9 @@ def plugin():
languages = sorted([lang + '.py' for lang, info in
T.get_possible_languages_info().iteritems()
if info[2] != 0]) # info[2] is langfile_mtime:
# get only existed files
# get only existed files
#Get crontab
# Get crontab
crontab = apath('%s/cron/crontab' % app, r=request)
if not os.path.exists(crontab):
safe_write(crontab, '#crontab')
@@ -1267,6 +1314,7 @@ def plugin():
languages=languages,
crontab=crontab)
def create_file():
""" Create files handler """
if request.vars and not request.vars.token == session.token:
@@ -1278,7 +1326,7 @@ def create_file():
path = abspath(request.vars.location)
else:
if request.vars.dir:
request.vars.location += request.vars.dir + '/'
request.vars.location += request.vars.dir + '/'
app = get_app(name=request.vars.location.split('/')[0])
path = apath(request.vars.location, r=request)
filename = re.sub('[^\w./-]+', '_', request.vars.filename)
@@ -1388,7 +1436,7 @@ def create_file():
elif (path[-8:] == '/static/') or (path[-9:] == '/private/'):
if (request.vars.plugin and
not filename.startswith('plugin_%s/' % request.vars.plugin)):
not filename.startswith('plugin_%s/' % request.vars.plugin)):
filename = 'plugin_%s/%s' % (request.vars.plugin, filename)
text = ''
@@ -1408,17 +1456,17 @@ def create_file():
log_progress(app, 'CREATE', filename)
if request.vars.dir:
result = T('file "%(filename)s" created',
dict(filename=full_filename[len(path):]))
dict(filename=full_filename[len(path):]))
else:
session.flash = T('file "%(filename)s" created',
dict(filename=full_filename[len(path):]))
dict(filename=full_filename[len(path):]))
vars = {}
if request.vars.id:
vars['id'] = request.vars.id
if request.vars.app:
vars['app'] = request.vars.app
redirect(URL('edit',
args=[os.path.join(request.vars.location, filename)], vars=vars))
args=[os.path.join(request.vars.location, filename)], vars=vars))
except Exception, e:
if not isinstance(e, HTTP):
@@ -1429,7 +1477,7 @@ def create_file():
response.headers['web2py-component-content'] = 'append'
response.headers['web2py-component-command'] = "%s %s %s" % (
"$.web2py.invalidate('#files_menu');",
"load_file('%s');" % URL('edit', args=[app,request.vars.dir,filename]),
"load_file('%s');" % URL('edit', args=[app, request.vars.dir, filename]),
"$.web2py.enableElement($('#form form').find($.web2py.formInputClickSelector));")
return ''
else:
@@ -1437,32 +1485,35 @@ def create_file():
def listfiles(app, dir, regexp='.*\.py$'):
files = sorted(
listdir(apath('%(app)s/%(dir)s/' % {'app':app, 'dir':dir}, r=request), regexp))
files = [x.replace('\\', '/') for x in files if not x.endswith('.bak')]
return files
files = sorted(
listdir(apath('%(app)s/%(dir)s/' % {'app': app, 'dir': dir}, r=request), regexp))
files = [x.replace('\\', '/') for x in files if not x.endswith('.bak')]
return files
def editfile(path, file, vars={}, app=None):
args = (path, file) if 'app' in vars else (app, path, file)
url = URL('edit', args=args, vars=vars)
return A(file, _class='editor_filelink', _href=url, _style='word-wrap: nowrap;')
def editfile(path,file,vars={}, app = None):
args=(path,file) if 'app' in vars else (app,path,file)
url = URL('edit', args=args, vars=vars)
return A(file, _class='editor_filelink', _href=url, _style='word-wrap: nowrap;')
def files_menu():
app = request.vars.app or 'welcome'
dirs=[{'name':'models', 'reg':'.*\.py$'},
{'name':'controllers', 'reg':'.*\.py$'},
{'name':'views', 'reg':'[\w/\-]+(\.\w+)+$'},
{'name':'modules', 'reg':'.*\.py$'},
{'name':'static', 'reg': '[^\.#].*'},
{'name':'private', 'reg':'.*\.py$'}]
result_files = []
for dir in dirs:
result_files.append(TAG[''](LI(dir['name'], _class="nav-header component", _onclick="collapse('" + dir['name'] + "_files');"),
LI(UL(*[LI(editfile(dir['name'], f, dict(id=dir['name'] + f.replace('.','__')), app), _style="overflow:hidden", _id=dir['name']+"__"+f.replace('.','__'))
for f in listfiles(app, dir['name'], regexp=dir['reg'])],
_class="nav nav-list small-font"),
_id=dir['name'] + '_files', _style="display: none;")))
return dict(result_files = result_files)
app = request.vars.app or 'welcome'
dirs = [{'name': 'models', 'reg': '.*\.py$'},
{'name': 'controllers', 'reg': '.*\.py$'},
{'name': 'views', 'reg': '[\w/\-]+(\.\w+)+$'},
{'name': 'modules', 'reg': '.*\.py$'},
{'name': 'static', 'reg': '[^\.#].*'},
{'name': 'private', 'reg': '.*\.py$'}]
result_files = []
for dir in dirs:
result_files.append(TAG[''](LI(dir['name'], _class="nav-header component", _onclick="collapse('" + dir['name'] + "_files');"),
LI(UL(*[LI(editfile(dir['name'], f, dict(id=dir['name'] + f.replace('.', '__')), app), _style="overflow:hidden", _id=dir['name'] + "__" + f.replace('.', '__'))
for f in listfiles(app, dir['name'], regexp=dir['reg'])],
_class="nav nav-list small-font"),
_id=dir['name'] + '_files', _style="display: none;")))
return dict(result_files=result_files)
def upload_file():
""" File uploading handler """
@@ -1509,7 +1560,7 @@ def upload_file():
if filename:
d = dict(filename=filename[len(path):])
else:
d = dict(filename='unkown')
d = dict(filename='unknown')
session.flash = T('cannot upload file "%(filename)s"', d)
redirect(request.vars.sender)
@@ -1525,7 +1576,7 @@ def errors():
app = get_app()
if is_gae:
method = 'dbold' if ('old' in
(request.args(1) or '')) else 'dbnew'
(request.args(1) or '')) else 'dbnew'
else:
method = request.args(1) or 'new'
db_ready = {}
@@ -1568,7 +1619,7 @@ def errors():
hash2error[hash]['count'] += 1
except KeyError:
error_lines = error['traceback'].split("\n")
last_line = error_lines[-2] if len(error_lines)>1 else 'unknown'
last_line = error_lines[-2] if len(error_lines) > 1 else 'unknown'
error_causer = os.path.split(error['layer'])[1]
hash2error[hash] = dict(count=1, pickel=error,
causer=error_causer,
@@ -1607,9 +1658,9 @@ def errors():
last_line = error_lines[-2]
error_causer = os.path.split(error['layer'])[1]
hash2error[hash] = dict(count=1,
pickel=error, causer=error_causer,
last_line=last_line, hash=hash,
ticket=fn.ticket_id)
pickel=error, causer=error_causer,
last_line=last_line, hash=hash,
ticket=fn.ticket_id)
except AttributeError, e:
tk_db(tk_table.id == fn.id).delete()
tk_db.commit()
@@ -1626,11 +1677,11 @@ def errors():
tk_db(tk_table.ticket_id == item[7:]).delete()
tk_db.commit()
tickets_ = tk_db(tk_table.id > 0).select(tk_table.ticket_id,
tk_table.created_datetime,
orderby=~tk_table.created_datetime)
tk_table.created_datetime,
orderby=~tk_table.created_datetime)
tickets = [row.ticket_id for row in tickets_]
times = dict([(row.ticket_id, row.created_datetime) for
row in tickets_])
row in tickets_])
return dict(app=app, tickets=tickets, method=method,
times=times, db_ready=db_ready)
@@ -1690,7 +1741,7 @@ def make_link(path):
if ext.lower() == editable[key] and check_extension:
return A('"' + tryFile + '"',
_href=URL(r=request,
f='edit/%s/%s/%s' % (app, key, filename))).xml()
f='edit/%s/%s/%s' % (app, key, filename))).xml()
return ''
@@ -1836,7 +1887,7 @@ def bulk_register():
redirect(URL('site'))
return locals()
### Begin experimental stuff need fixes:
# Begin experimental stuff need fixes:
# 1) should run in its own process - cannot os.chdir
# 2) should not prompt user at console
# 3) should give option to force commit and not reuqire manual merge
@@ -1903,6 +1954,7 @@ def git_push():
redirect(URL('site'))
return dict(app=app, form=form)
def plugins():
app = request.args(0)
from serializers import loads_json
@@ -1917,12 +1969,16 @@ def plugins():
session.plugins = []
return dict(plugins=session.plugins["results"], app=request.args(0))
def install_plugin():
app = request.args(0)
source = request.vars.source
plugin = request.vars.plugin
if not (source and app):
raise HTTP(500, T("Invalid request"))
# make sure no XSS attacks in source
if not source.lower().split('://')[0] in ('http','https'):
raise HTTP(500, T("Invalid request"))
form = SQLFORM.factory()
result = None
if form.process().accepted:
@@ -1938,5 +1994,5 @@ def install_plugin():
else:
session.flash = \
T('unable to install plugin "%s"', filename)
redirect(URL(f="plugins", args=[app,]))
redirect(URL(f="plugins", args=[app, ]))
return dict(form=form, app=app, plugin=plugin, source=source)

View File

@@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
import base64
import os
import re
import gzip
import tarfile
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
from xmlrpclib import ProtocolError
from gluon.contrib.simplejsonrpc import ServerProxy
def deploy():
response.title = T('Deploy to pythonanywhere')
return {}
def create_account():
""" Create a PythonAnywhere account """
if not request.vars:
raise HTTP(400)
if request.vars.username and request.vars.web2py_admin_password:
# Check if web2py is already there otherwise we get an error 500 too.
client = ServerProxy('https://%(username)s:%(web2py_admin_password)s@%(username)s.pythonanywhere.com/admin/webservices/call/jsonrpc' % request.vars)
try:
if client.login() is True:
return response.json({'status': 'ok'})
except ProtocolError as error:
pass
import urllib, urllib2
url = 'https://www.pythonanywhere.com/api/web2py/create_account'
data = urllib.urlencode(request.vars)
req = urllib2.Request(url, data)
try:
reply = urllib2.urlopen(req)
except urllib2.HTTPError as error:
if error.code == 400:
reply = error
elif error.code == 500:
return response.json({'status':'error', 'errors':{'username': ['An App other than web2py is installed in the domain %(username)s.pythonanywhere.com' % request.vars]}})
else:
raise
response.headers['Content-Type'] = 'application/json'
return reply.read()
def list_apps():
""" Get a list of apps both remote and local """
if not request.vars.username or not request.vars.password:
raise HTTP(400)
client = ServerProxy('https://%(username)s:%(password)s@%(username)s.pythonanywhere.com/admin/webservices/call/jsonrpc' % request.vars)
regex = re.compile('^\w+$')
local = [f for f in os.listdir(apath(r=request)) if regex.match(f)]
try:
pythonanywhere = client.list_apps()
except ProtocolError as error:
raise HTTP(error.errcode)
return response.json({'local': local, 'pythonanywhere': pythonanywhere})
def bulk_install():
""" Install a list of apps """
def b64pack(app):
"""
Given an app's name, return the base64 representation of its packed version.
"""
folder = apath(app, r=request)
tmpfile = StringIO()
tar = tarfile.TarFile(fileobj=tmpfile, mode='w')
try:
filenames = listdir(folder, '^[\w\.\-]+$', add_dirs=True,
exclude_content_from=['cache', 'sessions', 'errors'])
for fname in filenames:
tar.add(os.path.join(folder, fname), fname, False)
finally:
tar.close()
tmpfile.seek(0)
gzfile = StringIO()
w2pfp = gzip.GzipFile(fileobj=gzfile, mode='wb')
w2pfp.write(tmpfile.read())
w2pfp.close()
gzfile.seek(0)
return base64.b64encode(gzfile.read())
request.vars.apps = request.vars['apps[]']
if not request.vars.apps or not request.vars.username or not request.vars.password:
raise HTTP(400)
if not isinstance(request.vars.apps, list):
request.vars.apps = [request.vars.apps] # Only one app selected
client = ServerProxy('https://%(username)s:%(password)s@%(username)s.pythonanywhere.com/admin/webservices/call/jsonrpc' % request.vars)
for app in request.vars.apps:
try:
client.install(app, app+'.w2p', b64pack(app))
except ProtocolError as error:
raise HTTP(error.errcode)
return response.json({'status': 'ok'})

View File

@@ -2,89 +2,131 @@
{
'!langcode!': 'cs-cz',
'!langname!': 'čeština',
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". Výsledky databázového JOINu nemůžete mazat ani upravovat.',
'"User Exception" debug mode. An error ticket could be issued!': '"User Exception" debug mode. An error ticket could be issued!',
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". (Avšak výsledky databázového JOINu nelze mazat ani upravovat.)',
'"User Exception" debug mode. ': '"Uživatelská výjimka", Debug mód.',
'"User Exception" debug mode. An error ticket could be issued!': '"Uživatelská výjimka", Debug mód. Může být vystaven chybový tiket.',
'%%{Row} in Table': '%%{řádek} v tabulce',
'%%{Row} selected': 'označených %%{řádek}',
'%s': '%s',
'%s %%{row} deleted': '%s smazaných %%{záznam}',
'%s %%{row} updated': '%s upravených %%{záznam}',
'%s selected': '%s označených',
'%s students registered': '%s studentů registrováno',
'%Y-%m-%d': '%d.%m.%Y',
'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S',
'(requires internet access)': '(vyžaduje připojení k internetu)',
'(requires internet access, experimental)': '(requires internet access, experimental)',
'(requires internet access, experimental)': '(vyžaduje internetové připojení, experimentální)',
'(something like "it-it")': '(například "cs-cs")',
'(version %s)': '(verze %s)',
'?': '?',
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)',
'@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page',
'@markmin\x01Searching: **%s** %%{file}': 'Hledání: **%s** %%{soubor}',
'Abort': 'Ukončit',
'About': 'O programu',
'About application': 'O aplikaci',
'Accept Terms': 'Souhlasit s podmínkami',
'Access Control': 'Řízení přístupu',
'Add breakpoint': 'Přidat bod přerušení',
'Additional code for your application': 'Další kód pro Vaši aplikaci',
'Admin design page': 'Admin design page',
'Additional code for your application': 'Další kód pro Vaši aplikaci (pro příkaz import). Neběží ve specifickém režimu ani ve vláknech jako model/kontrolér/šablona, ale jako standardní python moduly. Ty tedy můžete umístit sem (pouze pro tuto aplikaci) nebo používat systémově dostupné.',
'Admin design page': 'Admin design stránka',
'admin disabled because no admin password': 'admin je zakázán, protože chybí heslo administrátora',
'admin disabled because not supported on google app engine': 'admin je zakázán kvůli chybějící podpoře na Google App Engine',
'admin disabled because too many invalid login attempts': 'Admin je zakázán po příliš mnoha nesprávných pokusech o přihlášení',
'admin disabled because unable to access password file': 'Admin je zakázán, protože nelze číst soubor s heslem',
'Admin is disabled because insecure channel': 'Admin je zakázán na nezabezpečeném připojení',
'Admin language': 'jazyk rozhraní',
'Admin versioning page': 'Admin verzovací stránka',
'Administrative interface': 'pro administrátorské rozhraní klikněte sem',
'Administrative Interface': 'Administrátorské rozhraní',
'administrative interface': 'rozhraní pro správu',
'Administrator Password:': 'Administrátorské heslo:',
'Ajax Recipes': 'Recepty s ajaxem',
'An error occured, please %s the page': 'An error occured, please %s the page',
'An error occured, please %s the page': 'Došlo k chybě, prosím %s stránku',
'and rename it:': 'a přejmenovat na:',
'App does not exist or you are not authorized': 'Aplikace neexistuje nebo vám chybí oprávnění',
'appadmin': 'appadmin',
'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení',
'Application': 'Application',
'Application': 'Aplikace',
'application "%s" uninstalled': 'application "%s" odinstalována',
'Application cannot be generated in demo mode': 'Aplikace nemůže být vytvořena v demo módu',
'application compiled': 'aplikace zkompilována',
'Application exists already': 'Aplikace již existuje',
'application is compiled and cannot be designed': 'aplikace je přeložena a nelze ji editovat',
'Application name:': 'Název aplikace:',
'Application updated via git pull': 'Aplikace byla aktualizována pomocí git pull',
'are not used': 'nepoužita',
'are not used yet': 'ještě nepoužita',
'Are you sure you want to delete file "%s"?': 'Skutečně chcete smazat soubor "%s"?',
'Are you sure you want to delete plugin "%s"?': 'Skutečně chcete smazat plugin "%s"?',
'Are you sure you want to delete this object?': 'Opravdu chcete odstranit tento objekt?',
'Are you sure you want to uninstall application "%s"?': 'Opravdu chcete odinstalovat aplikaci "%s"?',
'arguments': 'arguments',
'at char %s': 'at char %s',
'at line %s': 'at line %s',
'ATTENTION:': 'ATTENTION:',
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.',
'Are you sure?': 'Jste si jist(a)?',
'arguments': 'argumenty',
'at char %s': 'na pozici znaku %s',
'at line %s': 'na řádku %s',
'ATTENTION:': 'POZOR:',
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'POZOR: Přihlášení vyžaduje zabezpečené (HTTPS) připojení nebo spouštění na localhost.',
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'POZOR: TESTOVÁNÍ NENÍ BEZPEČNÉ PŘI SOUBĚŽNÝCH VLÁKNECH. NESPOUŠTĚJ VÍCE TESTŮ SOUBĚŽNĚ.',
'ATTENTION: you cannot edit the running application!': 'POZOR: Nelze editovat spuštěnou aplikaci.',
'Autocomplete Python Code': 'Autocomplete Python kód',
'Available Databases and Tables': 'Dostupné databáze a tabulky',
'back': 'zpět',
'Back to wizard': 'Back to wizard',
'Basics': 'Basics',
'Back to the plugins list': 'Zpět do seznamu pluginů',
'Back to wizard': 'Zpátky do průvodce',
'Basics': 'Základy',
'Begin': 'Začít',
'breakpoint': 'bod přerušení',
'Breakpoints': 'Body přerušení',
'breakpoints': 'body přerušení',
'Bulk Register': 'Hromadná registrace',
'Bulk Student Registration': 'Hromadná registrace studentů',
'Buy this book': 'Koupit web2py knihu',
'Cache': 'Cache',
'cache': 'cache',
'Cache Cleared': 'Cache byla vymazána',
'Cache Keys': 'Klíče cache',
'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny',
'can be a git repo': 'může to být git repo',
'Cancel': 'Storno',
'Cannot be empty': 'Nemůže být prázdné',
'Cannot compile: there are errors in your app:': 'Nelze zkompilovat: ve vaší aplikaci jsou chyby:',
'cannot create file': 'nelze vytvořit soubor',
'cannot upload file "%(filename)s"': 'nelze nahrát soubor "%(filename)s"',
'Change Admin Password': 'Změnit heslo pro správu',
'Change admin password': 'Změnit heslo pro správu aplikací',
'change editor settings': 'změnit nastavení editoru',
'Change password': 'Změna hesla',
'Changelog': 'Žurnál změn',
'check all': 'vše označit',
'Check for upgrades': 'Zkusit aktualizovat',
'Check to delete': 'Označit ke smazání',
'Check to delete:': 'Označit ke smazání:',
'Checking for upgrades...': 'Zjišťuji, zda jsou k dispozici aktualizace...',
'Clean': 'Pročistit',
'Clear': 'Inicializovat',
'Clear CACHE?': 'Vymazat CACHE?',
'Clear DISK': 'Vymazat DISK',
'Clear RAM': 'Vymazat RAM',
'Click row to expand traceback': 'Pro rozbalení stopy, klikněte na řádek',
'Click row to view a ticket': 'Pro zobrazení chyby (ticketu), klikněte na řádku...',
'Client IP': 'IP adresa klienta',
'code': 'code',
'Code listing': 'Code listing',
'code': 'kód',
'Code listing': 'Výpis kódu',
'collapse/expand all': 'vše sbalit/rozbalit',
'Command': 'Příkaz',
'Comment:': 'Komentář:',
'Commit': 'Potvrdit',
'Commit form': 'Potvrdit formulář',
'Committed files': 'Potvrzené soubory',
'Community': 'Komunita',
'Compile': 'Zkompilovat',
'Compile (all or nothing)': 'Přeložit (vše nebo nic)',
'Compile (skip failed views)': 'Přeložit (přeskočit chybné šablony)',
'compiled application removed': 'zkompilovaná aplikace smazána',
'Components and Plugins': 'Komponenty a zásuvné moduly',
'Condition': 'Podmínka',
'continue': 'continue',
'continue': 'pokračovat',
'Controller': 'Kontrolér (Controller)',
'Controllers': 'Kontroléry',
'controllers': 'kontroléry',
@@ -92,9 +134,12 @@
'Count': 'Počet',
'Create': 'Vytvořit',
'create file with filename:': 'vytvořit soubor s názvem:',
'Create/Upload': 'Vytvořit/Nahrát',
'created by': 'vytvořil',
'Created By': 'Vytvořeno - kým',
'Created by:': 'Vytvořil:',
'Created On': 'Vytvořeno - kdy',
'Created on:': 'Vytvořeno:',
'crontab': 'crontab',
'Current request': 'Aktuální požadavek',
'Current response': 'Aktuální odpověď',
@@ -105,18 +150,19 @@
'data uploaded': 'data nahrána',
'Database': 'Rozhraní databáze',
'Database %s select': 'databáze %s výběr',
'Database administration': 'Database administration',
'Database administration': 'Administrace databáze',
'database administration': 'správa databáze',
'Database Administration (appadmin)': 'Administrace databáze (appadmin)',
'Date and Time': 'Datum a čas',
'day': 'den',
'db': 'db',
'DB Model': 'Databázový model',
'Debug': 'Ladění',
'defines tables': 'defines tables',
'defines tables': 'definuje tabulky',
'Delete': 'Smazat',
'delete': 'smazat',
'delete all checked': 'smazat vše označené',
'delete plugin': 'delete plugin',
'delete plugin': 'zrušit plugin',
'Delete this file (you will be asked to confirm deletion)': 'Smazat tento soubor (budete požádán o potvrzení mazání)',
'Delete:': 'Smazat:',
'deleted after first hit': 'smazat po prvním dosažení',
@@ -124,166 +170,265 @@
'Deploy': 'Nahrát',
'Deploy on Google App Engine': 'Nahrát na Google App Engine',
'Deploy to OpenShift': 'Nahrát na OpenShift',
'Deploy to pythonanywhere': 'Nahrát na PythonAnywhere',
'Deploy to PythonAnywhere': 'Nahrát na PythonAnywhere',
'Deployment form': 'Forumlář pro deployment (nasazení)',
'Deployment Interface': 'Rozhraní pro deployment (nasazení)',
'Deployment Recipes': 'Postupy pro deployment',
'Description': 'Popis',
'Description:': 'Popis:',
'design': 'návrh',
'Detailed traceback description': 'Podrobný výpis prostředí',
'details': 'podrobnosti',
'direction: ltr': 'směr: ltr',
'directory not found': 'adresář nebyl nalezen',
'Disable': 'Zablokovat',
'Disabled': 'Blokováno',
'disabled in demo mode': 'zakázáno v demo módu',
'disabled in GAE mode': 'zakázáno v GAE módu',
'disabled in multi user mode': 'zakázáno ve víceuživatelském módu',
'DISK': 'DISK',
'Disk Cache Keys': 'Klíče diskové cache',
'Disk Cleared': 'Disk smazán',
'Display line numbers': 'Zobrazit čísla řádků',
'DO NOT use the "Pack compiled" feature.': 'NEPOUŽÍVEJ vlastnost "Zabalit zkompilované".',
'docs': 'dokumentace',
'Docs': 'Dokumentace',
'Documentation': 'Dokumentace',
"Don't know what to do?": 'Nevíte kudy kam?',
'done!': 'hotovo!',
'Downgrade': 'Downgrade (vrácení verze)',
'Download': 'Stáhnout',
'Download .w2p': 'Stažení .w2p',
'Download as .exe': 'Stáhnout jako .exe',
'download layouts': 'stáhnout moduly rozvržení stránky',
'Download layouts from repository': 'Stáhnout moduly rozvržení z repozitáře',
'download plugins': 'stáhnout zásuvné moduly',
'Download plugins from repository': 'Stáhnout pluginy z repozitáře',
'E-mail': 'E-mail',
'Edit': 'Upravit',
'edit all': 'edit all',
'edit all': 'editovat vše',
'Edit application': 'Správa aplikace',
'edit controller': 'edit controller',
'edit controller': 'editovat controller',
'edit controller:': 'editovat kontrolér:',
'Edit current record': 'Upravit aktuální záznam',
'Edit Profile': 'Upravit profil',
'edit views:': 'upravit pohled:',
'edit views:': 'upravit šablonu (view):',
'Editing %s': 'Editace %s',
'Editing file "%s"': 'Úprava souboru "%s"',
'Editing Language file': 'Úprava jazykového souboru',
'Editing Plural Forms File': 'Editing Plural Forms File',
'Editing Plural Forms File': 'Editování souboru množných čísel',
'Editor': 'Editor',
'Email Address': 'Emailová adresa',
'Email and SMS': 'Email a SMS',
'Enable': 'Odblokovat',
'Enable Close-Tag': 'Povolit Close-Tag',
'Enable Code Folding': 'Povolit sdružování kódu',
'enter a number between %(min)g and %(max)g': 'zadejte číslo mezi %(min)g a %(max)g',
'enter an integer between %(min)g and %(max)g': 'zadejte celé číslo mezi %(min)g a %(max)g',
'Error': 'Chyba',
'Error logs for "%(app)s"': 'Seznam výskytu chyb pro aplikaci "%(app)s"',
'Error snapshot': 'Snapshot chyby',
'Error ticket': 'Ticket chyby',
'Error ticket': 'Tiket chyby',
'Errors': 'Chyby',
'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s',
'Exception %s': 'Exception %s',
'Exception %(extype)s: %(exvalue)s': 'Výjimka %(extype)s: %(exvalue)s',
'Exception %s': 'Výjimka %s',
'Exception instance attributes': 'Prvky instance výjimky',
'Expand Abbreviation': 'Expand Abbreviation',
'Exit Fullscreen': 'Ukončit režim celé obrazovky',
'Expand Abbreviation': 'Rozvinout zkratku',
'Expand Abbreviation (html files only)': 'Rozvinout zkratku (pouze html soubory)',
'export as csv file': 'exportovat do .csv souboru',
'Exports:': 'Exporty:',
'exposes': 'vystavuje',
'exposes:': 'vystavuje funkce:',
'extends': 'rozšiřuje',
'failed to compile file because:': 'soubor se nepodařilo zkompilovat, protože:',
'failed to reload module because:': 'nepodařilo se restartovat modul, protože:',
'FAQ': 'Často kladené dotazy',
'File': 'Soubor',
'file': 'soubor',
'file "%(filename)s" created': 'file "%(filename)s" created',
'file "%(filename)s" created': 'soubor "%(filename)s" byl vytvořen',
'file "%(filename)s" deleted': 'soubor "%(filename)s" byl zrušen',
'file "%(filename)s" uploaded': 'soubor "%(filename)s" byl nahrán',
'file "%s" of %s restored': 'soubor "%s" z %s byl obnoven',
'file changed on disk': 'soubor se na disku změnil',
'file does not exist': 'soubor neexistuje',
'file not found': 'soubor nebyl nalezen',
'file saved on %(time)s': 'soubor uložen %(time)s',
'file saved on %s': 'soubor uložen %s',
'filename': 'jméno souboru',
'Filename': 'Název souboru',
'Files added': 'Soubory byly přidány',
'filter': 'filtr',
'Find Next': 'Najít další',
'Find Previous': 'Najít předchozí',
'First name': 'Křestní jméno',
'Forgot username?': 'Zapomněl jste svoje přihlašovací jméno?',
'forgot username?': 'zapomněl jste svoje přihlašovací jméno?',
'Form has errors': 'Ve formuláři jsou chyby',
'Forms and Validators': 'Formuláře a validátory',
'Frames': 'Frames',
'Frames': 'Framy',
'Free Applications': 'Aplikace zdarma',
'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.',
'Functions with no doctests will result in [passed] tests.': 'Funkce bez doctestů se projeví jako [úspěšný] test.',
'GAE Email': 'GAE e-mail',
'GAE Output': 'GAE výstup',
'GAE Password': 'GAE heslo',
'Generate': 'Vytvořit',
'Get from URL:': 'Stáhnout z internetu:',
'Git Pull': 'Git Pull',
'Git Push': 'Git Push',
'Globals##debug': 'Globální proměnné',
'go!': 'OK!',
'Goto': 'Goto',
'graph model': 'graph model',
'Google App Engine Deployment Interface': 'Google App Engine - rozhraní pro nasazení',
'Google Application Id': 'ID Google Aplikace',
'Goto': 'Přejít na',
'graph model': 'grafický model',
'Graph Model': 'Grafický model',
'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena',
'Group ID': 'ID skupiny',
'Groups': 'Skupiny',
'Hello World': 'Ahoj světe',
'Help': 'Nápověda',
'here': 'zde',
'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty',
'Highlight current line': 'Zvýraznit aktuální řádek',
'Hits': 'Kolikrát dosaženo',
'Home': 'Domovská stránka',
'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně',
'How did you get here?': 'Jak jste se sem vlastně dostal?',
'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download',
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.',
'If start the downgrade, be patient, it may take a while to rollback': 'Spustíte-li downgrade verze, vyčkejte, protože vrácení změn může trvat dlouho',
'If start the upgrade, be patient, it may take a while to download': 'Spustíte-li upgrade, vyčkejte, protože stahování může trvat dlouho',
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Jestliže přehled výše obsahuje číslo chybového tiketu, znamená to chybu v kontroléru, ještě před pokusem vykonat doctesty. (Často je to způsobeno chybou odsazení nebo chybou mimo kód funkce.) Zelený nadpis označuje, že žádný test nehavaroval. (V tom případě dílčí výsledky nejsou uvedeny.)',
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Jestliže přehled výše obsahuje číslo chybového tiketu, znamená to chybu v kontroléru, ještě před pokusem vykonat doctesty. (Často je to způsobeno chybou odsazení nebo chybou mimo kód funkce.) Zelený nadpis označuje, že žádný test nehavaroval. (V tom případě dílčí výsledky nejsou uvedeny.)',
'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'Jestliže vaše aplikace používá jinou databázi než SQLite, budete muset na PythonAnywhere konfigurovat její DAL() připojení.',
'import': 'import',
'Import/Export': 'Import/Export',
'In development, use the default Rocket webserver that is currently supported by this debugger.': 'Při vývoji je doporučeno použít předvolený webserver Rocket, se kterým tento debugger spolupracuje.',
'includes': 'zahrnuje',
'Indent with tabs': 'Odsazení tabelátory',
'Index': 'Index',
'insert new': 'vložit nový záznam ',
'insert new %s': 'vložit nový záznam %s',
'inspect attributes': 'inspect attributes',
'inspect attributes': 'prohlédnout atributy',
'Install': 'Instalovat',
'Installation of %(plugin)s for %(app)s': 'Instalace %(plugin)s pro %(app)s',
'Installed applications': 'Nainstalované aplikace',
'Interaction at %s line %s': 'Interakce v %s, na řádce %s',
'Interactive console': 'Interaktivní příkazová řádka',
'internal error': 'vnitřní chyba',
'internal error: %s': 'vnitřní chyba: %s',
'Internal State': 'Vnitřní stav',
'Introduction': 'Úvod',
'Invalid action': 'Chybná akce',
'Invalid application name': 'Nesprávné jméno aplikace',
'invalid circular reference': 'nepovolený kruhový odkaz',
'Invalid email': 'Neplatný email',
'Invalid git repository specified.': 'Byl zadán nesprávný git repozitář.',
'Invalid password': 'Nesprávné heslo',
'invalid password': 'nesprávné heslo',
'invalid password.': 'neplatné heslo',
'Invalid Query': 'Neplatný dotaz',
'invalid request': 'Neplatný požadavek',
'Invalid request': 'Nesprávný požadavek (request)',
'invalid table names (auth_* tables already defined)': 'chybná jména tabulek (auth_* tabulky už byly definovány)',
'invalid ticket': 'chybný tiket',
'Is Active': 'Je aktivní',
'It is %s %%{day} today.': 'Dnes je to %s %%{den}.',
'Key': 'Klíč',
'Key bindings': 'Vazby klíčů',
'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin',
'Key bindings': 'Vazby kláves',
'Key bindings for ZenCoding Plugin': 'Vazby kláves pro ZenCoding Plugin',
'Keyboard shortcuts': 'Klávesové zkratky',
'kill process': 'likvidovat proces',
'language file "%(filename)s" created/updated': 'jazykový soubor "%(filename)s" byl vytvořen/aktualizován',
'Language files (static strings) updated': 'Jazykové soubory (statické řetězce) byly aktualizovány',
'languages': 'jazyky',
'Languages': 'Jazyky',
'Last name': 'Příjmení',
'Last Revision': 'Minulá verze',
'Last saved on:': 'Naposledy uloženo:',
'Layout': 'Rozvržení stránky (layout)',
'Layout Plugins': 'Moduly rozvržení stránky (Layout Plugins)',
'Layouts': 'Rozvržení stránek',
'License for': 'Licence pro',
'License:': 'Licence:',
'Line Nr': 'Č.řádku',
'Line number': 'Číslo řádku',
'LineNo': 'Č.řádku',
'Live Chat': 'Online pokec',
'lists by exception': 'výpis podle výjimky',
'lists by ticket': 'výpis podle tiketu',
'Live Chat': 'Online chat',
'Loading...': 'Nahrávám...',
'loading...': 'nahrávám...',
'locals': 'locals',
'Local Apps': 'Lokální aplikace',
'locals': 'lokální proměnné',
'Locals##debug': 'Lokální proměnné',
'Logged in': 'Přihlášení proběhlo úspěšně',
'Logged out': 'Odhlášení proběhlo úspěšně',
'Login': 'Přihlásit se',
'login': 'přihlásit se',
'Login': 'Přihlásit se',
'Login successful': 'Přihlášení bylo úspěšné',
'Login to the Administrative Interface': 'Přihlásit se do Správce aplikací',
'Login/Register': 'Přihlásit se / Registrovat',
'logout': 'odhlásit se',
'Logout': 'Odhlásit se',
'lost password': 'ztracené heslo',
'Lost Password': 'Zapomněl jste heslo',
'Lost password?': 'Zapomněl jste heslo?',
'lost password?': 'zapomněl jste heslo?',
'Manage': 'Manage',
'Manage Cache': 'Manage Cache',
'Main Menu': 'Hlavní nabídka',
'Manage': 'Spravovat',
'Manage %(action)s': 'Spravovat %(action)s',
'Manage Access Control': 'Spravovat řízení přístupu',
'Manage Admin Users/Students': 'Spravovat Admin uživatele / Studenty',
'Manage Cache': 'Spravovat cache',
'Manage Students': 'Spravovat studenty',
'Memberships': 'Členství ve skupinách',
'Menu Model': 'Model rozbalovací nabídky',
'merge': 'sloučit',
'Models': 'Modely',
'models': 'modely',
'Modified By': 'Změněno - kým',
'Modified On': 'Změněno - kdy',
'Modules': 'Moduly',
'modules': 'moduly',
'Multi User Mode': 'Víceuživatelský mód',
'My Sites': 'Správa aplikací',
'Name': 'Jméno',
'new application "%s" created': 'nová aplikace "%s" vytvořena',
'new application "%s" imported': 'nová aplikace "%s" byla importována',
'New Application Wizard': 'Nový průvodce aplikací',
'New application wizard': 'Nový průvodce aplikací',
'New password': 'Nové heslo',
'new plugin installed': 'nový plugin byl instalován',
'New plugin installed: %s': 'Nový plugin byl instalován: %s',
'New Record': 'Nový záznam',
'new record inserted': 'nový záznam byl založen',
'New simple application': 'Vytvořit primitivní aplikaci',
'next': 'next',
'New simple application': 'Vytvořit novou aplikaci',
'next': 'další',
'next %s rows': 'dalších %s řádků',
'next 100 rows': 'dalších 100 řádků',
'NO': 'NE',
'no changes': 'beze změn',
'No databases in this application': 'V této aplikaci nejsou žádné databáze',
'No Interaction yet': 'Ještě žádná interakce nenastala',
'no match': 'nenalezena shoda',
'no package selected': 'nebyla vybrána žádná package',
'no permission to uninstall "%s"': 'chybí oprávnění odinstalovat "%s"',
'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen',
'Node:': 'Uzel (node):',
'Not Authorized': 'Chybí autorizace',
'Not supported': 'Není podporováno',
'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Poznámka: Dostanete-li chybu s github status code = 128, ujistěte se, že systém a účet z něhož provádíte nasazení má odpovídající ssh klíč, konfigurovaný v OpenShift účtu.',
'Object or table name': 'Objekt či tabulka',
'Old password': 'Původní heslo',
"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": 'Pro použití tohoto debuggeru na produkci je potřeba konfigurovat webserver, aby používal jeden proces a více vláken.',
'online designer': 'online návrhář',
'Online examples': 'Příklady online',
'Open new app in new window': 'Open new app in new window',
'or alternatively': 'or alternatively',
'Or Get from URL:': 'Or Get from URL:',
'Open new app in new window': 'Otevřít novou aplikaci v novém okně',
'OpenShift Deployment Interface': 'OpenShift rozhraní pro nasazení aplikace',
'OpenShift Output': 'OpenShift výstup',
'or alternatively': 'nebo případně',
'Or Get from URL:': 'Nebo získat z URL adresy:',
'or import from csv file': 'nebo importovat z .csv souboru',
'Origin': 'Původ',
'Original/Translation': 'Originál/Překlad',
@@ -293,30 +438,53 @@
'Overwrite installed app': 'Přepsat instalovanou aplikaci',
'Pack all': 'Zabalit',
'Pack compiled': 'Zabalit zkompilované',
'pack plugin': 'pack plugin',
'password': 'heslo',
'Pack custom': 'Zabalit volitelně (custom)',
'pack plugin': 'zabalit plugin',
'Password': 'Heslo',
'password': 'heslo',
'password changed': 'heslo bylo změněno',
"Password fields don't match": 'Hesla se neshodují',
'Peeking at file': 'Peeking at file',
'Past revisions': 'Minulá verze',
'Path to appcfg.py': 'Cesta ke appcfg.py',
'Path to local openshift repo root.': 'Cesta ke kořenu (rootu) lokálního OpenShift repozitáře.',
'Peeking at file': 'Sledování souboru',
'Permission': 'Oprávnění',
'Permissions': 'Oprávnění',
'Please': 'Prosím',
'Plugin "%s" in application': 'Plugin "%s" in application',
'Please wait, giving pythonanywhere a moment...': 'Prosím, čekejte na dokončení činnosti PythonAnywhere...',
'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" byl odstraněn',
'Plugin "%s" in application': 'Plugin "%s" v aplikaci',
'plugin not specified': 'plugin nebyl určen',
'Plugin page': 'Stránka pluginů',
'plugins': 'zásuvné moduly',
'Plugins': 'Zásuvné moduly',
'Plural Form #%s': 'Plural Form #%s',
'Plural Form #%s': 'Množné číslo #%s',
'Plural-Forms:': 'Množná čísla:',
'Powered by': 'Poháněno',
'Powered by': 'používá technologii',
'Preface': 'Předmluva',
'Preferences saved correctly': 'Nastavení byla úspěšně uložena',
'Preferences saved on session only': 'Nastavení byla uložena pouze pro toto sezení',
'previous %s rows': 'předchozích %s řádků',
'previous 100 rows': 'předchozích 100 řádků',
'Private files': 'Soukromé soubory',
'private files': 'soukromé soubory',
'profile': 'profil',
'Project Progress': 'Vývoj projektu',
'Pull': 'Pull',
'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull selhal, některé soubory nelze zkopírovat. Pro podrobnosti zkontrolujte logy.',
'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull nelze provést, protože máte nesloučené soubory. Vyřešte tyto konflikty a pak akci opakujte.',
'Push': 'Push',
'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push selhal, protože máte nesloučené soubory. Vyřešte tyto konflikty a pak akci opakujte.',
'pygraphviz library not found': 'pygraphviz knihovna nebyla nalezena',
'Python': 'Python',
'PythonAnywhere Apps': 'PythonAnywhere aplikace',
'PythonAnywhere Password': 'PythonAnywhere heslo',
'Query:': 'Dotaz:',
'Quick Examples': 'Krátké příklady',
'RAM': 'RAM',
'RAM Cache Keys': 'Klíče RAM Cache',
'Ram Cleared': 'RAM smazána',
'Rapid Search': 'Rychlé hledání',
'Readme': 'Nápověda',
'Recipes': 'Postupy jak na to',
'Record': 'Záznam',
@@ -335,114 +503,167 @@
'Removed Breakpoint on %s at line %s': 'Bod přerušení smazán - soubor %s na řádce %s',
'Replace': 'Zaměnit',
'Replace All': 'Zaměnit vše',
'request': 'request',
'Repository (%s)': 'Repozitář (%s)',
'request': 'požadavek (request)',
'requires distutils, but not installed': 'vyžaduje distutils, jenže ty nejsou instalovány',
'requires python-git, but not installed': 'vyžaduje python-git, který ale není nainstalován',
'Reset Password key': 'Reset registračního klíče',
'response': 'response',
'Resolve Conflict file': 'Vyřešit konflikty',
'response': 'odpověď (response)',
'restart': 'restart',
'restore': 'obnovit',
'Retrieve username': 'Získat přihlašovací jméno',
'return': 'return',
'Revert': 'Vrátit se k původnímu',
'revert': 'vrátit se k původnímu',
'reverted to revision %s': 'vráceno k verzi %s',
'Revision %s': 'Verze %s',
'Revision:': 'Verze:',
'Role': 'Role',
'Roles': 'Role',
'Rows in Table': 'Záznamy v tabulce',
'Rows selected': 'Záznamů zobrazeno',
'rules are not defined': 'pravidla nejsou definována',
'Run tests': 'Spustit testy',
'Run tests in this file': 'Spustit testy v souboru',
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Spustí testy v tomto souboru (ke spuštění všech testů, použijte tlačítko 'test')",
'Running on %s': 'Běží na %s',
'Save': 'Uložit',
'Save file:': 'Save file:',
'Save file:': 'Uložit soubor:',
'Save file: %s': 'Uložit soubor: %s',
'Save model as...': 'Uložit model jako...',
'Save via Ajax': 'Uložit pomocí Ajaxu',
'Saved file hash:': 'hash uloženého souboru:',
'Screenshot %s': 'Screenshot %s',
'Search': 'Hledání',
'Select Files to Package': 'Vybrat soubory pro package',
'Semantic': 'Modul semantic',
'Services': 'Služby',
'session': 'session',
'session expired': 'session expired',
'session': 'session (sezení)',
'session expired': 'vypršela session',
'Session saved correctly': 'Session byla úspěšně uložena',
'Session saved on session only': 'Session byla uložena jen pro toto sezení',
'Set Breakpoint on %s at line %s: %s': 'Bod přerušení nastaven v souboru %s na řádce %s: %s',
'shell': 'příkazová řádka',
'Singular Form': 'Singular Form',
'Showing %s to %s of %s %s found': 'Zobrazuji %s%s z %s %s nalezených',
'Singular Form': 'Jednotné číslo',
'Site': 'Správa aplikací',
'Size of cache:': 'Velikost cache:',
'skip to generate': 'skip to generate',
'skip to generate': 'přeskočit pro vytvoření',
'some files could not be removed': 'některé soubory nelze odstranit',
'Something went wrong please wait a few minutes before retrying': 'Něco se nepodařilo. Vyčkejte několik minut a pak zkuste znova',
'Sorry, could not find mercurial installed': 'Bohužel mercurial není nainstalován.',
'source : db': 'zdroj : db',
'source : filesystem': 'zdroj : souborový systém',
'Start a new app': 'Vytvořit novou aplikaci',
'Start searching': 'Začít hledání',
'Start wizard': 'Spustit průvodce',
'state': 'stav',
'Static': 'Static',
'Static': 'Statické soubory',
'static': 'statické soubory',
'Static files': 'Statické soubory',
'Statistics': 'Statistika',
'Step': 'Step',
'step': 'step',
'stop': 'stop',
'Step': 'Krok',
'step': 'krok',
'stop': 'zastavit',
'Stylesheet': 'CSS styly',
'submit': 'odeslat',
'Submit': 'Odeslat',
'successful': 'úspěšně',
'Support': 'Podpora',
'Sure you want to delete this object?': 'Opravdu chcete smazat tento objekt?',
'switch to : db': 'přepnout na : db',
'switch to : filesystem': 'přepnout na : souborový systém',
'Tab width (# characters)': 'Šířka tabelátoru (# znaků)',
'Table': 'tabulka',
'Table name': 'Název tabulky',
'Temporary': 'Dočasný',
'test': 'test',
'Testing application': 'Testing application',
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je podmínka, například "db.tabulka1.pole1==\'hodnota\'". Podmínka "db.tabulka1.pole1==db.tabulka2.pole2" pak vytvoří SQL JOIN.',
'Testing application': 'Zkušební aplikace',
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je například "db.tabulka1.pole1==\'hodnota\'". Dotaz se dvěma tabulkami "db.tabulka1.pole1==db.tabulka2.pole2" vytvoří SQL JOIN.',
'The app exists, was created by wizard, continue to overwrite!': 'Aplikace existuje, byla vytvořena průvodcem. Pokračováním ji přepíšete !',
'The app exists, was NOT created by wizard, continue to overwrite!': 'Aplikace existuje, a NEBYLA vytvořena průvodcem. Pokračováním ji přepíšete !',
'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikace: každá URL je mapována na funkci vystavovanou kontrolérem.',
'The Core': 'Jádro (The Core)',
'The data representation, define database tables and sets': 'Reprezentace dat: definovat tabulky databáze a záznamy',
'The output of the file is a dictionary that was rendered by the view %s': 'Výstup ze souboru je slovník, který se zobrazil v pohledu %s.',
'The presentations layer, views are also known as templates': 'Prezentační vrstva: pohledy či templaty (šablony)',
'The data representation, define database tables and sets': 'Modely se vykonají při každém přístupu. Zde se obvykle definuje především reprezentace dat: Připojení k databázi a struktura tabulek databáze',
'The output of the file is a dictionary that was rendered by the view %s': 'Výstup ze souboru je dictionary (slovník), který se zobrazil pomocí šablony (view) %s.',
'The presentations layer, views are also known as templates': 'Prezentační vrstva: šablony (neboli pohledy, templaty, view). Mixuje Html, Python kód a Python data.',
'The Views': 'Pohledy (The Views)',
'There are no controllers': 'There are no controllers',
'There are no modules': 'There are no modules',
'Theme': 'Téma',
'There are no controllers': 'Nejsou vytvořeny žádné controllery',
'There are no models': 'Není vytvořen žádný model',
'There are no modules': 'Nejsou přidány žádné moduly',
'There are no plugins': 'Žádné moduly nejsou instalovány.',
'There are no private files': 'Žádné soukromé soubory neexistují.',
'There are no static files': 'There are no static files',
'There are no translators, only default language is supported': 'There are no translators, only default language is supported',
'There are no views': 'There are no views',
'These files are not served, they are only available from within your app': 'Tyto soubory jsou klientům nepřístupné. K dispozici jsou pouze v rámci aplikace.',
'These files are served without processing, your images go here': 'Tyto soubory jsou servírovány bez přídavné logiky, sem patří např. obrázky.',
'There are no static files': 'Nejsou přidány žádné statické soubory',
'There are no translators': 'Není vytvořen žádný překlad',
'There are no translators, only default language is supported': 'Není vytvořen žádný překlad, je podporován jen defaultní jazyk',
'There are no views': 'Nejsou vytvořeny žádné šablony (views)',
'These files are not served, they are only available from within your app': 'Tyto soubory jsou přístupné jen běžící aplikaci. Nejsou dostupné uživatelům, ani se nekopírují do případného vývojového repozitáře. Hesla a citlivá nastavení nedávejte nikam jinam.',
'These files are served without processing, your images go here': 'Tyto soubory jsou stahovány přímo, bez jakékoli přídavné logiky, sem patří např. obrázky.',
'This App': 'Tato aplikace',
'This is a copy of the scaffolding application': 'Toto je kopie aplikace skelet.',
'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk',
'This is the %(filename)s template': 'This is the %(filename)s template',
"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": 'Tento debugger nebude pracovat správně, jestliže váš webový server nepracuje pomocí vláken nebo když používáte více procesů démonů.',
'This is a copy of the scaffolding application': 'Toto je kopie vzorové aplikace.',
'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'Toto je experimentální vlastnost, která vyžaduje další testování. Návrat verze jen na vlastní riziko.',
'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'Toto je experimentální vlastnost, která vyžaduje další testování. Upgrade verze jen na vlastní riziko.',
'This is the %(filename)s template': 'Toto je šablona %(filename)s',
"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": 'Tato stránka umožňuje potvrdit vaše změny do OpenShift aplikačního repozitáře a odeslat je do vaší cloud instance. Předpokladem je, že jste už vytvořili aplikační instanci pomocí Web2py předlohy a že tento repozitář máte někde na disku tak, aby k němu Web2py mělo přístup. Tato funkcionalita vyžaduje, aby byl instalován GitPython a aby mohl být nalezen pomocí cesty, se kterou Web2py pracuje.',
'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'Tato stránka umožňuje zkopírovat vaši aplikaci do Google App Engine cloudu. Pamatujte, že nejprve je třeba vytvořit indexy lokálně, čehož dosáhnete instalací Google appserver a jedním lokálním spuštěním aplikace. V opačném případě bude docházet k chybám vyhledávání. Pozor: v závislosti na rychlosti sítě může nasazení trvat dlouhou dobu. Pozor: bude přepsán váš soubor app.yaml. BĚHEM SPUŠTĚNÍ NESPOUŠTĚJTE PODRUHÉ.',
'this page to see if a breakpoint was hit and debug interaction is required.': 'tuto stránku, abyste uviděli, zda se dosáhlo bodu přerušení.',
'Ticket': 'Ticket',
'Ticket ID': 'Ticket ID',
'This will pull changes from the remote repo for application "%s"?': 'Toto stáhne (pull) změny ze vzdáleného repozitáře pro aplikaci "%s"?',
'This will push changes to the remote repo for application "%s".': 'Toto nahraje (push) změny do vzdáleného repozitáře pro aplikaci "%s".',
'Ticket': 'Tiket',
'Ticket ID': 'ID tiketu',
'Ticket Missing': 'Chybový tiket chybí',
'Time in Cache (h:m:s)': 'Čas v Cache (h:m:s)',
'Timestamp': 'Časové razítko',
'to previous version.': 'k předchozí verzi.',
'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete soubor/adresář plugin_[jméno modulu]',
'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete skupinu souborů nebo adresář(e) plugin_[jméno modulu]',
'To emulate a breakpoint programatically, write:': 'K nastavení bodu přerušení v kódu programu, napište:',
'to use the debugger!': ', abyste mohli ladící program používat!',
'toggle breakpoint': 'vyp./zap. bod přerušení',
'Toggle comment': 'Přepnout komentář',
'Toggle Fullscreen': 'Na celou obrazovku a zpět',
'too short': 'Příliš krátké',
'Traceback': 'Traceback',
'Traceback': 'Hierarchie volání',
'Translation strings for the application': 'Překlad textů pro aplikaci',
'try something like': 'try something like',
'try something like': 'zkuste něco jako',
'Try the mobile interface': 'Zkuste rozhraní pro mobilní zařízení',
'try view': 'try view',
'try view': 'vyzkoušet šablonu (view)',
'Twitter': 'Twitter',
'Type python statement in here and hit Return (Enter) to execute it.': 'Type python statement in here and hit Return (Enter) to execute it.',
'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.',
'Unable to check for upgrades': 'Unable to check for upgrades',
'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Zapište příkaz PDB debuggeru a stiskněte Return (Enter) pro jeho provedení.',
'Type python statement in here and hit Return (Enter) to execute it.': 'Zapište příkaz pythonu a stiskněte Return (Enter) pro jeho provedení.',
'Type some Python code in here and hit Return (Enter) to execute it.': 'Zapište kód v jazyce python a stiskněte Return (Enter) pro jeho provedení.',
'Unable to check for upgrades': 'Nelze zjistit informaci o aktualizacích',
'unable to create application "%s"': 'nelze vytvořit aplikaci "%s"',
'unable to delete file "%(filename)s"': 'nelze zrušit soubor "%(filename)s"',
'unable to delete file plugin "%(plugin)s"': 'nelze zrušit plugin "%(plugin)s"',
'Unable to determine the line number!': 'Nelze určit číslo řádky!',
'Unable to download app because:': 'Nelze stáhnout aplikaci, protože:',
'unable to download layout': 'nelze stáhnout šablonu (layout)',
'unable to download plugin: %s': 'nelze stáhnout plugin: %s',
'Unable to download the list of plugins': 'Nelze stáhnout seznam pluginů',
'unable to install plugin "%s"': 'nelze instalovat plugin "%s"',
'unable to parse csv file': 'csv soubor nedá sa zpracovat',
'unable to uninstall "%s"': 'nelze instalovat "%s"',
'unable to upgrade because "%s"': 'nelze upgradovat, protože "%s"',
'uncheck all': 'vše odznačit',
'Uninstall': 'Odinstalovat',
'Unsupported webserver working mode: %s': 'Nepodporovaný mód webového serveru: %s',
'update': 'aktualizovat',
'update all languages': 'aktualizovat všechny jazyky',
'update all languages': 'aktualizovat všechny jazyky o nové texty ze zdrojových souborů',
'Update:': 'Upravit:',
'Upgrade': 'Upgrade',
'upgrade now': 'upgrade now',
'upgrade now to %s': 'upgrade now to %s',
'upgrade now': 'upgradovat nyní',
'upgrade now to %s': 'upgradovat nyní na %s',
'upload': 'nahrát',
'Upload': 'Upload',
'Upload': 'Upload (nahrát)',
'Upload a package:': 'Nahrát balík:',
'Upload and install packed application': 'Nahrát a instalovat zabalenou aplikaci',
'upload file:': 'nahrát soubor:',
'upload plugin file:': 'nahrát soubor modulu:',
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT pro sestavení složitějších dotazů.',
'User': 'Uživatel',
'User %(id)s Logged-in': 'Uživatel %(id)s přihlášen',
'User %(id)s Logged-out': 'Uživatel %(id)s odhlášen',
'User %(id)s Password changed': 'Uživatel %(id)s změnil heslo',
@@ -451,30 +672,45 @@
'User %(id)s Username retrieved': 'Uživatel %(id)s si nachal zaslat přihlašovací jméno',
'User ID': 'ID uživatele',
'Username': 'Přihlašovací jméno',
'variables': 'variables',
'Users': 'Uživatelé',
'Using the shell may lock the database to other users of this app.': 'Použití příkazového shellu může uzamknout databázi ostatním uživatelům této aplikace.',
'variables': 'proměnné',
'Verify Password': 'Zopakujte heslo',
'Version': 'Verze',
'Version %s.%s.%s (%s) %s': 'Verze %s.%s.%s (%s) %s',
'Versioning': 'Verzování',
'Videos': 'Videa',
'View': 'Pohled (View)',
'Views': 'Pohledy',
'views': 'pohledy',
'Web Framework': 'Web Framework',
'View': 'Šablona (View)',
'Views': 'Šablony (Views)',
'views': 'šablony (views)',
'Warning!': 'Pozor!',
'WARNING:': 'POZOR:',
'WARNING: The following views could not be compiled:': 'POZOR: Následující šablony se nepodařilo zkompilovat:',
'Web Framework': 'Webový framework',
'web2py Admin Password': 'web2py Heslo administrátora',
'web2py apps to deploy': 'web2py aplikace k nasazení',
'web2py Debugger': 'web2py Debugger',
'web2py downgrade': 'web2py downgrade',
'web2py is up to date': 'Máte aktuální verzi web2py.',
'web2py online debugger': 'Ladící online web2py program',
'web2py Recent Tweets': 'Štěbetání na Twitteru o web2py',
'web2py upgrade': 'web2py upgrade',
'web2py upgraded; please restart it': 'web2py upgraded; please restart it',
'web2py Recent Tweets': 'Nedávné tweety na Twitteru o web2py',
'web2py upgrade': 'aktualizace Web2py',
'web2py upgraded; please restart it': 'Web2py bylo aktualizováno; prosím restarujte jej',
'Welcome': 'Vítejte',
'Welcome to web2py': 'Vitejte ve web2py',
'Welcome to web2py!': 'Vítejte ve web2py!',
'Welcome to web2py': 'Vitejte ve Web2py aplikaci.',
'Welcome to web2py!': 'Vítejte ve Web2py aplikaci.',
'Which called the function %s located in the file %s': 'která zavolala funkci %s v souboru (kontroléru) %s.',
'WSGI reference name': 'jméno WSGI reference',
'YES': 'ANO',
'Yes': 'Ano',
'You are successfully running web2py': 'Úspěšně jste spustili web2py.',
'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Nastavovat a mazat body přerušení je též možno v rámci editování zdrojového souboru přes tlačítko Vyp./Zap. bod přerušení',
'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné',
'You can inspect variables using the console below': 'You can inspect variables using the console below',
'You can modify this application and adapt it to your needs': 'Tuto aplikaci si můžete upravit a přizpůsobit ji svým potřebám.',
'You have one more login attempt before you are locked out': 'Máte jen jeden další pokus k přihlášení před zablokováním',
'You need to set up and reach a': 'Je třeba nejprve nastavit a dojít až na',
'You only need these if you have already registered': 'Toto potřebujete jen tehdy, jestliže jste se už registroval(a)',
'You visited the url %s': 'Navštívili jste stránku %s,',
'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Aplikace bude blokována než se klikne na jedno z tlačítek (další, krok, pokračovat, atd.)',
'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné',
}

View File

@@ -1,377 +1,408 @@
# -*- coding: utf-8 -*-
{
'!langcode!': 'pt',
'!langname!': 'Português',
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" é uma expressão opcional como "campo1=\'novo_valor\'". Não é permitido atualizar ou apagar resultados de um JOIN',
'%s %%{row} deleted': '%s registros apagados',
'%s %%{row} updated': '%s registros atualizados',
'%Y-%m-%d': '%d/%m/%Y',
'%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S',
'(requires internet access)': '(requer acesso à internet)',
'(requires internet access, experimental)': '(requer acesso à internet, experimental)',
'(something like "it-it")': '(algo como "it-it")',
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(file **gluon/contrib/plural_rules/%s.py** is not found)',
'@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page',
'@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files',
'A new version of web2py is available': 'Está disponível uma nova versão do web2py',
'A new version of web2py is available: %s': 'Está disponível uma nova versão do web2py: %s',
'About': 'sobre',
'About application': 'Sobre a aplicação',
'additional code for your application': 'código adicional para sua aplicação',
'Additional code for your application': 'Código adicional para a sua aplicação',
'admin disabled because no admin password': ' admin desabilitado por falta de senha definida',
'admin disabled because not supported on google app engine': 'admin dehabilitado, não é soportado no GAE',
'admin disabled because unable to access password file': 'admin desabilitado, não foi possível ler o arquivo de senha',
'Admin is disabled because insecure channel': 'Admin desabilitado pois o canal não é seguro',
'Admin is disabled because unsecure channel': 'Admin desabilitado pois o canal não é seguro',
'Admin language': 'Linguagem do Admin',
'administrative interface': 'interface administrativa',
'Administrator Password:': 'Senha de administrador:',
'and rename it (required):': 'e renomeie (requerido):',
'and rename it:': ' e renomeie:',
'appadmin': 'appadmin',
'appadmin is disabled because insecure channel': 'admin desabilitado, canal inseguro',
'application "%s" uninstalled': 'aplicação "%s" desinstalada',
'application compiled': 'aplicação compilada',
'application is compiled and cannot be designed': 'A aplicação está compilada e não pode ser modificada',
'Application name:': 'Nome da aplicação:',
'are not used': 'não usadas',
'are not used yet': 'ainda não usadas',
'Are you sure you want to delete file "%s"?': 'Tem certeza que deseja apagar o arquivo "%s"?',
'Are you sure you want to delete plugin "%s"?': 'Tem certeza que deseja apagar o plugin "%s"?',
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
'Are you sure you want to uninstall application "%s"': 'Tem certeza que deseja apagar a aplicação "%s"?',
'Are you sure you want to uninstall application "%s"?': 'Tem certeza que deseja apagar a aplicação "%s"?',
'Are you sure you want to upgrade web2py now?': 'Tem certeza que deseja atualizar o web2py agora?',
'arguments': 'argumentos',
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENÇÃO o login requer uma conexão segura (HTTPS) ou executar de localhost.',
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENÇÃO OS TESTES NÃO THREAD SAFE, NÃO EFETUE MÚLTIPLOS TESTES AO MESMO TEMPO.',
'ATTENTION: you cannot edit the running application!': 'ATENÇÃO: Não pode modificar a aplicação em execução!',
'Autocomplete Python Code': 'Autocompletar Código Python',
'Available databases and tables': 'Bancos de dados e tabelas disponíveis',
'back': 'voltar',
'browse': 'buscar',
'cache': 'cache',
'cache, errors and sessions cleaned': 'cache, erros e sessões eliminadas',
'can be a git repo': 'can be a git repo',
'Cannot be empty': 'Não pode ser vazio',
'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Não é possível compilar: Existem erros em sua aplicação. Depure, corrija os errros e tente novamente',
'Cannot compile: there are errors in your app:': 'Não é possível compilar: Existem erros em sua aplicação',
'cannot create file': 'Não é possível criar o arquivo',
'cannot upload file "%(filename)s"': 'não é possível fazer upload do arquivo "%(filename)s"',
'Change admin password': 'mudar senha de administrador',
'change editor settings': 'mudar definições do editor',
'Change Password': 'Trocar Senha',
'check all': 'marcar todos',
'Check for upgrades': 'checar por atualizações',
'Check to delete': 'Marque para apagar',
'Checking for upgrades...': 'Buscando atualizações...',
'Clean': 'limpar',
'click here for online examples': 'clique para ver exemplos online',
'click here for the administrative interface': 'Clique aqui para acessar a interface administrativa',
'Click row to expand traceback': 'Clique em uma coluna para expandir o log do erro',
'click to check for upgrades': 'clique aqui para checar por atualizações',
'click to open': 'clique para abrir',
'Client IP': 'IP do cliente',
'code': 'código',
'collapse/expand all': 'colapsar/expandir tudo',
'commit (mercurial)': 'commit (mercurial)',
'Compile': 'compilar',
'compiled application removed': 'aplicação compilada removida',
'Controllers': 'Controladores',
'controllers': 'controladores',
'Count': 'Contagem',
'Create': 'criar',
'create file with filename:': 'criar um arquivo com o nome:',
'Create new application using the Wizard': 'Criar nova aplicação utilizando o assistente',
'create new application:': 'nome da nova aplicação:',
'Create new simple application': 'Crie uma nova aplicação',
'Create/Upload': 'Create/Upload',
'created by': 'criado por',
'crontab': 'crontab',
'Current request': 'Requisição atual',
'Current response': 'Resposta atual',
'Current session': 'Sessão atual',
'currently running': 'Executando',
'currently saved or': 'Atualmente salvo ou',
'customize me!': 'Modifique-me',
'data uploaded': 'Dados enviados',
'database': 'banco de dados',
'database %s select': 'Seleção no banco de dados %s',
'database administration': 'administração de banco de dados',
'Date and Time': 'Data e Hora',
'db': 'db',
'Debug': 'Debug',
'defines tables': 'define as tabelas',
'Delete': 'Apague',
'delete': 'apagar',
'delete all checked': 'apagar marcados',
'delete plugin': 'apagar plugin',
'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)',
'Delete:': 'Apague:',
'Deploy': 'publicar',
'Deploy on Google App Engine': 'Publicar no Google App Engine',
'Deploy to OpenShift': 'Deploy to OpenShift',
'Description': 'Descrição',
'design': 'modificar',
'DESIGN': 'Projeto',
'Design for': 'Projeto de',
'Detailed traceback description': 'Detailed traceback description',
'direction: ltr': 'direção: ltr',
'Disable': 'Disable',
'docs': 'docs',
'done!': 'feito!',
'download layouts': 'download layouts',
'Download layouts from repository': 'Download layouts from repository',
'download plugins': 'download plugins',
'Download plugins from repository': 'Download plugins from repository',
'E-mail': 'E-mail',
'EDIT': 'EDITAR',
'Edit': 'editar',
'Edit application': 'Editar aplicação',
'edit controller': 'editar controlador',
'Edit current record': 'Editar o registro atual',
'Edit Profile': 'Editar Perfil',
'edit views:': 'editar visões:',
'Editing %s': 'A Editar %s',
'Editing file': 'Editando arquivo',
'Editing file "%s"': 'Editando arquivo "%s"',
'Editing Language file': 'Editando arquivo de linguagem',
'Enterprise Web Framework': 'Framework web empresarial',
'Error': 'Erro',
'Error logs for "%(app)s"': 'Logs de erro para "%(app)s"',
'Error snapshot': 'Error snapshot',
'Error ticket': 'Error ticket',
'Errors': 'erros',
'Exception instance attributes': 'Atributos da instancia de excessão',
'Exit Fullscreen': 'Sair de Ecrã Inteiro',
'Expand Abbreviation (html files only)': 'Expandir Abreviação (só para ficheiros html)',
'export as csv file': 'exportar como arquivo CSV',
'exposes': 'expõe',
'extends': 'estende',
'failed to reload module': 'Falha ao recarregar o módulo',
'failed to reload module because:': 'falha ao recarregar o módulo por:',
'File': 'Arquivo',
'file "%(filename)s" created': 'arquivo "%(filename)s" criado',
'file "%(filename)s" deleted': 'arquivo "%(filename)s" apagado',
'file "%(filename)s" uploaded': 'arquivo "%(filename)s" enviado',
'file "%(filename)s" was not deleted': 'arquivo "%(filename)s" não foi apagado',
'file "%s" of %s restored': 'arquivo "%s" de %s restaurado',
'file changed on disk': 'arquivo modificado no disco',
'file does not exist': 'arquivo não existe',
'file saved on %(time)s': 'arquivo salvo em %(time)s',
'file saved on %s': 'arquivo salvo em %s',
'filter': 'filtro',
'Find Next': 'Localizar Seguinte',
'Find Previous': 'Localizar Anterior',
'First name': 'Nome',
'Frames': 'Frames',
'Functions with no doctests will result in [passed] tests.': 'Funções sem doctests resultarão em testes [aceitos].',
'graph model': 'graph model',
'Group ID': 'ID do Grupo',
'Hello World': 'Olá Mundo',
'Help': 'ajuda',
'Hide/Show Translated strings': '',
'htmledit': 'htmledit',
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Se o relatório acima contém um número de ticket, isso indica uma falha no controlador em execução, antes de tantar executar os doctests. Isto acontece geralmente por erro de endentação ou erro fora do código da função.\r\nO titulo em verde indica que os testes (se definidos) passaram. Neste caso os testes não são mostrados.',
'Import/Export': 'Importar/Exportar',
'includes': 'inclui',
'insert new': 'inserir novo',
'insert new %s': 'inserir novo %s',
'inspect attributes': 'inspecionar atributos',
'Install': 'instalar',
'Installed applications': 'Aplicações instaladas',
'internal error': 'erro interno',
'Internal State': 'Estado Interno',
'Invalid action': 'Ação inválida',
'Invalid email': 'E-mail inválido',
'invalid password': 'senha inválida',
'Invalid Query': 'Consulta inválida',
'invalid request': 'solicitação inválida',
'invalid ticket': 'ticket inválido',
'Keyboard shortcuts': 'Atalhos de teclado',
'language file "%(filename)s" created/updated': 'arquivo de linguagem "%(filename)s" criado/atualizado',
'Language files (static strings) updated': 'Arquivos de linguagem (textos estáticos) atualizados',
'languages': 'linguagens',
'Languages': 'Linguagens',
'languages updated': 'linguagens atualizadas',
'Last name': 'Sobrenome',
'Last saved on:': 'Salvo em:',
'License for': 'Licença para',
'loading...': 'carregando...',
'locals': 'locals',
'Login': 'Entrar',
'login': 'inicio de sessão',
'Login to the Administrative Interface': 'Entrar na interface adminitrativa',
'Logout': 'finalizar sessão',
'Lost Password': 'Senha perdida',
'Manage': 'Manage',
'manage': 'gerenciar',
'merge': 'juntar',
'Models': 'Modelos',
'models': 'modelos',
'Modules': 'Módulos',
'modules': 'módulos',
'Name': 'Nome',
'new application "%s" created': 'nova aplicação "%s" criada',
'New application wizard': 'Assistente para novas aplicações ',
'new plugin installed': 'novo plugin instalado',
'New Record': 'Novo registro',
'new record inserted': 'novo registro inserido',
'New simple application': 'Nova aplicação básica',
'next 100 rows': 'próximos 100 registros',
'NO': 'NÃO',
'No databases in this application': 'Não existem bancos de dados nesta aplicação',
'no match': 'não encontrado',
'no package selected': 'nenhum pacote selecionado',
'online designer': 'online designer',
'or alternatively': 'or alternatively',
'Or Get from URL:': 'Ou Obtenha do URL:',
'or import from csv file': 'ou importar de um arquivo CSV',
'or provide app url:': 'ou forneça a url de uma aplicação:',
'or provide application url:': 'ou forneça a url de uma aplicação:',
'Origin': 'Origem',
'Original/Translation': 'Original/Tradução',
'Overwrite installed app': 'sobrescrever aplicação instalada',
'Pack all': 'criar pacote',
'Pack compiled': 'criar pacote compilado',
'Pack custom': 'Pack custom',
'pack plugin': 'empacotar plugin',
'PAM authenticated user, cannot change password here': 'usuario autenticado por PAM, não pode alterar a senha por aqui',
'Password': 'Senha',
'password changed': 'senha alterada',
'Peeking at file': 'Visualizando arquivo',
'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" eliminado',
'Plugin "%s" in application': 'Plugin "%s" na aplicação',
'plugins': 'plugins',
'Plugins': 'Plugins',
'Plural-Forms:': 'Plural-Forms:',
'Powered by': 'Este site utiliza',
'previous 100 rows': '100 registros anteriores',
'Private files': 'Private files',
'private files': 'private files',
'Query:': 'Consulta:',
'Rapid Search': 'Rapid Search',
'record': 'registro',
'record does not exist': 'o registro não existe',
'record id': 'id do registro',
'Record ID': 'ID do Registro',
'Register': 'Registrar-se',
'Registration key': 'Chave de registro',
'Reload routes': 'Reload routes',
'Remove compiled': 'eliminar compilados',
'Replace': 'Substituir',
'Replace All': 'Substituir Tudo',
'request': 'request',
'Resolve Conflict file': 'Arquivo de resolução de conflito',
'response': 'response',
'restore': 'restaurar',
'revert': 'reverter',
'Role': 'Papel',
'Rows in table': 'Registros na tabela',
'Rows selected': 'Registros selecionados',
'rules are not defined': 'rules are not defined',
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')",
'Running on %s': 'A correr em %s',
'Save': 'Save',
'save': 'salvar',
'Save file:': 'Gravar ficheiro:',
'Save file: %s': 'Gravar ficheiro: %s',
'Save via Ajax': 'Gravar via Ajax',
'Saved file hash:': 'Hash do arquivo salvo:',
'selected': 'selecionado(s)',
'session': 'session',
'session expired': 'sessão expirada',
'shell': 'Terminal',
'Site': 'site',
'some files could not be removed': 'alguns arquicos não puderam ser removidos',
'Start searching': 'Start searching',
'Start wizard': 'iniciar assistente',
'state': 'estado',
'Static': 'Static',
'static': 'estáticos',
'Static files': 'Arquivos estáticos',
'Submit': 'Submit',
'submit': 'enviar',
'Sure you want to delete this object?': 'Tem certeza que deseja apaagr este objeto?',
'table': 'tabela',
'Table name': 'Nome da tabela',
'test': 'testar',
'Testing application': 'Testando a aplicação',
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'A "consulta" é uma condição como "db.tabela.campo1==\'valor\'". Algo como "db.tabela1.campo1==db.tabela2.campo2" resulta em um JOIN SQL.',
'the application logic, each URL path is mapped in one exposed function in the controller': 'A lógica da aplicação, cada URL é mapeada para uma função exposta pelo controlador',
'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller',
'the data representation, define database tables and sets': 'A representação dos dadps, define tabelas e estruturas de dados',
'The data representation, define database tables and sets': 'The data representation, define database tables and sets',
'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates',
'the presentations layer, views are also known as templates': 'A camada de apresentação, As visões também são chamadas de templates',
'There are no controllers': 'Não existem controllers',
'There are no models': 'Não existem modelos',
'There are no modules': 'Não existem módulos',
'There are no plugins': 'There are no plugins',
'There are no private files': '',
'There are no static files': 'Não existem arquicos estáticos',
'There are no translators, only default language is supported': 'Não há traduções, somente a linguagem padrão é suportada',
'There are no views': 'Não existem visões',
'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app',
'These files are served without processing, your images go here': 'These files are served without processing, your images go here',
'these files are served without processing, your images go here': 'Estes arquivos são servidos sem processamento, suas imagens ficam aqui',
'This is the %(filename)s template': 'Este é o template %(filename)s',
'Ticket': 'Ticket',
'Ticket ID': 'Ticket ID',
'Timestamp': 'Data Atual',
'TM': 'MR',
'to previous version.': 'para a versão anterior.',
'To create a plugin, name a file/folder plugin_[name]': 'Para criar um plugin, nomeio um arquivo/pasta como plugin_[nome]',
'toggle breakpoint': 'toggle breakpoint',
'Toggle comment': 'Toggle comment',
'Toggle Fullscreen': 'Toggle Fullscreen',
'Traceback': 'Traceback',
'translation strings for the application': 'textos traduzidos para a aplicação',
'Translation strings for the application': 'Translation strings for the application',
'try': 'tente',
'try something like': 'tente algo como',
'Try the mobile interface': 'Try the mobile interface',
'Unable to check for upgrades': 'Não é possível checar as atualizações',
'unable to create application "%s"': 'não é possível criar a aplicação "%s"',
'unable to delete file "%(filename)s"': 'não é possível criar o arquico "%(filename)s"',
'unable to delete file plugin "%(plugin)s"': 'não é possível criar o plugin "%(plugin)s"',
'Unable to download': 'Não é possível efetuar o download',
'Unable to download app': 'Não é possível baixar a aplicação',
'Unable to download app because:': 'Não é possível baixar a aplicação porque:',
'Unable to download because': 'Não é possível baixar porque',
'unable to parse csv file': 'não é possível analisar o arquivo CSV',
'unable to uninstall "%s"': 'não é possível instalar "%s"',
'unable to upgrade because "%s"': 'não é possível atualizar porque "%s"',
'uncheck all': 'desmarcar todos',
'Uninstall': 'desinstalar',
'update': 'atualizar',
'update all languages': 'atualizar todas as linguagens',
'Update:': 'Atualizar:',
'upgrade web2py now': 'atualize o web2py agora',
'upload': 'upload',
'Upload': 'Upload',
'Upload & install packed application': 'Faça upload e instale uma aplicação empacotada',
'Upload a package:': 'Faça upload de um pacote:',
'Upload and install packed application': 'Upload and install packed application',
'upload application:': 'Fazer upload de uma aplicação:',
'Upload existing application': 'Faça upload de uma aplicação existente',
'upload file:': 'Enviar arquivo:',
'upload plugin file:': 'Enviar arquivo de plugin:',
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) para AND, (...)|(...) para OR, y ~(...) para NOT, para criar consultas mais complexas.',
'Use an url:': 'Use uma url:',
'User ID': 'ID do Usuario',
'variables': 'variáveis',
'Version': 'Versão',
'versioning': 'versionamento',
'Versioning': 'Versioning',
'view': 'visão',
'Views': 'Visões',
'views': 'visões',
'Web Framework': 'Web Framework',
'web2py is up to date': 'web2py está atualizado',
'web2py Recent Tweets': 'Tweets Recentes de @web2py',
'web2py upgraded; please restart it': 'web2py atualizado; favor reiniciar',
'Welcome to web2py': 'Bem-vindo ao web2py',
'YES': 'SIM',
}
# -*- coding: utf-8 -*-
{
'!langcode!': 'pt',
'!langname!': 'Português',
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" é uma expressão opcional como "campo1=\'novo_valor\'". Não é permitido atualizar ou apagar resultados de um JOIN',
'%s %%{row} deleted': '%s registros apagados',
'%s %%{row} updated': '%s registros atualizados',
'%Y-%m-%d': '%d/%m/%Y',
'%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S',
'(requires internet access)': '(requer acesso à internet)',
'(requires internet access, experimental)': '(requer acesso à internet, experimental)',
'(something like "it-it")': '(algo como "it-it")',
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(file **gluon/contrib/plural_rules/%s.py** is not found)',
'@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page',
'@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files',
'A new version of web2py is available': 'Está disponível uma nova versão do web2py',
'A new version of web2py is available: %s': 'Está disponível uma nova versão do web2py: %s',
'About': 'sobre',
'About application': 'Sobre a aplicação',
'Accept Terms': 'Accept Terms',
'additional code for your application': 'código adicional para sua aplicação',
'Additional code for your application': 'Código adicional para a sua aplicação',
'admin disabled because no admin password': ' admin desabilitado por falta de senha definida',
'admin disabled because not supported on google app engine': 'admin dehabilitado, não é soportado no GAE',
'admin disabled because unable to access password file': 'admin desabilitado, não foi possível ler o arquivo de senha',
'Admin is disabled because insecure channel': 'Admin desabilitado pois o canal não é seguro',
'Admin is disabled because unsecure channel': 'Admin desabilitado pois o canal não é seguro',
'Admin language': 'Linguagem do Admin',
'administrative interface': 'interface administrativa',
'Administrator Password:': 'Senha de administrador:',
'and rename it (required):': 'e renomeie (requerido):',
'and rename it:': ' e renomeie:',
'appadmin': 'appadmin',
'appadmin is disabled because insecure channel': 'admin desabilitado, canal inseguro',
'application "%s" uninstalled': 'aplicação "%s" desinstalada',
'application compiled': 'aplicação compilada',
'application is compiled and cannot be designed': 'A aplicação está compilada e não pode ser modificada',
'Application name:': 'Nome da aplicação:',
'are not used': 'não usadas',
'are not used yet': 'ainda não usadas',
'Are you sure you want to delete file "%s"?': 'Tem certeza que deseja apagar o arquivo "%s"?',
'Are you sure you want to delete plugin "%s"?': 'Tem certeza que deseja apagar o plugin "%s"?',
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
'Are you sure you want to uninstall application "%s"': 'Tem certeza que deseja apagar a aplicação "%s"?',
'Are you sure you want to uninstall application "%s"?': 'Tem certeza que deseja apagar a aplicação "%s"?',
'Are you sure you want to upgrade web2py now?': 'Tem certeza que deseja atualizar o web2py agora?',
'arguments': 'argumentos',
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENÇÃO o login requer uma conexão segura (HTTPS) ou executar de localhost.',
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENÇÃO OS TESTES NÃO THREAD SAFE, NÃO EFETUE MÚLTIPLOS TESTES AO MESMO TEMPO.',
'ATTENTION: you cannot edit the running application!': 'ATENÇÃO: Não pode modificar a aplicação em execução!',
'Autocomplete Python Code': 'Autocompletar Código Python',
'Available databases and tables': 'Bancos de dados e tabelas disponíveis',
'back': 'voltar',
'Begin': 'Begin',
'browse': 'buscar',
'cache': 'cache',
'cache, errors and sessions cleaned': 'cache, erros e sessões eliminadas',
'can be a git repo': 'can be a git repo',
'Cannot be empty': 'Não pode ser vazio',
'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Não é possível compilar: Existem erros em sua aplicação. Depure, corrija os errros e tente novamente',
'Cannot compile: there are errors in your app:': 'Não é possível compilar: Existem erros em sua aplicação',
'cannot create file': 'Não é possível criar o arquivo',
'cannot upload file "%(filename)s"': 'não é possível fazer upload do arquivo "%(filename)s"',
'Change admin password': 'mudar senha de administrador',
'change editor settings': 'mudar definições do editor',
'Change Password': 'Trocar Senha',
'check all': 'marcar todos',
'Check for upgrades': 'checar por atualizações',
'Check to delete': 'Marque para apagar',
'Checking for upgrades...': 'Buscando atualizações...',
'Clean': 'limpar',
'click here for online examples': 'clique para ver exemplos online',
'click here for the administrative interface': 'Clique aqui para acessar a interface administrativa',
'Click row to expand traceback': 'Clique em uma coluna para expandir o log do erro',
'click to check for upgrades': 'clique aqui para checar por atualizações',
'click to open': 'clique para abrir',
'Client IP': 'IP do cliente',
'code': 'código',
'collapse/expand all': 'colapsar/expandir tudo',
'commit (mercurial)': 'commit (mercurial)',
'Compile': 'compilar',
'compiled application removed': 'aplicação compilada removida',
'Controllers': 'Controladores',
'controllers': 'controladores',
'Count': 'Contagem',
'Create': 'criar',
'create file with filename:': 'criar um arquivo com o nome:',
'Create new application using the Wizard': 'Criar nova aplicação utilizando o assistente',
'create new application:': 'nome da nova aplicação:',
'Create new simple application': 'Crie uma nova aplicação',
'Create/Upload': 'Create/Upload',
'created by': 'criado por',
'crontab': 'crontab',
'Current request': 'Requisição atual',
'Current response': 'Resposta atual',
'Current session': 'Sessão atual',
'currently running': 'Executando',
'currently saved or': 'Atualmente salvo ou',
'customize me!': 'Modifique-me',
'data uploaded': 'Dados enviados',
'database': 'banco de dados',
'database %s select': 'Seleção no banco de dados %s',
'database administration': 'administração de banco de dados',
'Date and Time': 'Data e Hora',
'db': 'db',
'Debug': 'Debug',
'defines tables': 'define as tabelas',
'Delete': 'Apague',
'delete': 'apagar',
'delete all checked': 'apagar marcados',
'delete plugin': 'apagar plugin',
'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)',
'Delete:': 'Apague:',
'Deploy': 'publicar',
'Deploy on Google App Engine': 'Publicar no Google App Engine',
'Deploy to OpenShift': 'Deploy to OpenShift',
'Deploy to pythonanywhere': 'Deploy to pythonanywhere',
'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere',
'Deployment Interface': 'Deployment Interface',
'Description': 'Descrição',
'design': 'modificar',
'DESIGN': 'Projeto',
'Design for': 'Projeto de',
'Detailed traceback description': 'Detailed traceback description',
'details': 'details',
'direction: ltr': 'direção: ltr',
'Disable': 'Disable',
'docs': 'docs',
'done!': 'feito!',
'download layouts': 'download layouts',
'Download layouts from repository': 'Download layouts from repository',
'download plugins': 'download plugins',
'Download plugins from repository': 'Download plugins from repository',
'E-mail': 'E-mail',
'EDIT': 'EDITAR',
'Edit': 'editar',
'Edit application': 'Editar aplicação',
'edit controller': 'editar controlador',
'Edit current record': 'Editar o registro atual',
'Edit Profile': 'Editar Perfil',
'edit views:': 'editar visões:',
'Editing %s': 'A Editar %s',
'Editing file': 'Editando arquivo',
'Editing file "%s"': 'Editando arquivo "%s"',
'Editing Language file': 'Editando arquivo de linguagem',
'Email Address': 'Email Address',
'Enterprise Web Framework': 'Framework web empresarial',
'Error': 'Erro',
'Error logs for "%(app)s"': 'Logs de erro para "%(app)s"',
'Error snapshot': 'Error snapshot',
'Error ticket': 'Error ticket',
'Errors': 'erros',
'Exception instance attributes': 'Atributos da instancia de excessão',
'Exit Fullscreen': 'Sair de Ecrã Inteiro',
'Expand Abbreviation (html files only)': 'Expandir Abreviação (só para ficheiros html)',
'export as csv file': 'exportar como arquivo CSV',
'exposes': 'expõe',
'exposes:': 'exposes:',
'extends': 'estende',
'failed to reload module': 'Falha ao recarregar o módulo',
'failed to reload module because:': 'falha ao recarregar o módulo por:',
'File': 'Arquivo',
'file "%(filename)s" created': 'arquivo "%(filename)s" criado',
'file "%(filename)s" deleted': 'arquivo "%(filename)s" apagado',
'file "%(filename)s" uploaded': 'arquivo "%(filename)s" enviado',
'file "%(filename)s" was not deleted': 'arquivo "%(filename)s" não foi apagado',
'file "%s" of %s restored': 'arquivo "%s" de %s restaurado',
'file changed on disk': 'arquivo modificado no disco',
'file does not exist': 'arquivo não existe',
'file saved on %(time)s': 'arquivo salvo em %(time)s',
'file saved on %s': 'arquivo salvo em %s',
'filter': 'filtro',
'Find Next': 'Localizar Seguinte',
'Find Previous': 'Localizar Anterior',
'First name': 'Nome',
'Form has errors': 'Form has errors',
'Frames': 'Frames',
'Functions with no doctests will result in [passed] tests.': 'Funções sem doctests resultarão em testes [aceitos].',
'graph model': 'graph model',
'Group ID': 'ID do Grupo',
'Hello World': 'Olá Mundo',
'Help': 'ajuda',
'Hide/Show Translated strings': '',
'htmledit': 'htmledit',
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Se o relatório acima contém um número de ticket, isso indica uma falha no controlador em execução, antes de tantar executar os doctests. Isto acontece geralmente por erro de endentação ou erro fora do código da função.\r\nO titulo em verde indica que os testes (se definidos) passaram. Neste caso os testes não são mostrados.',
'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.',
'Import/Export': 'Importar/Exportar',
'includes': 'inclui',
'insert new': 'inserir novo',
'insert new %s': 'inserir novo %s',
'inspect attributes': 'inspecionar atributos',
'Install': 'instalar',
'Installed applications': 'Aplicações instaladas',
'internal error': 'erro interno',
'Internal State': 'Estado Interno',
'Invalid action': 'Ação inválida',
'Invalid email': 'E-mail inválido',
'invalid password': 'senha inválida',
'Invalid Query': 'Consulta inválida',
'invalid request': 'solicitação inválida',
'invalid ticket': 'ticket inválido',
'Keyboard shortcuts': 'Atalhos de teclado',
'language file "%(filename)s" created/updated': 'arquivo de linguagem "%(filename)s" criado/atualizado',
'Language files (static strings) updated': 'Arquivos de linguagem (textos estáticos) atualizados',
'languages': 'linguagens',
'Languages': 'Linguagens',
'languages updated': 'linguagens atualizadas',
'Last name': 'Sobrenome',
'Last saved on:': 'Salvo em:',
'License for': 'Licença para',
'lists by ticket': 'lists by ticket',
'Loading...': 'Loading...',
'loading...': 'carregando...',
'Local Apps': 'Local Apps',
'locals': 'locals',
'Login': 'Entrar',
'login': 'inicio de sessão',
'Login successful': 'Login successful',
'Login to the Administrative Interface': 'Entrar na interface adminitrativa',
'Login/Register': 'Login/Register',
'Logout': 'finalizar sessão',
'Lost Password': 'Senha perdida',
'manage': 'gerenciar',
'Manage': 'Manage',
'merge': 'juntar',
'models': 'modelos',
'Models': 'Modelos',
'Modules': 'Módulos',
'modules': 'módulos',
'Name': 'Nome',
'new application "%s" created': 'nova aplicação "%s" criada',
'New Application Wizard': 'New Application Wizard',
'New application wizard': 'Assistente para novas aplicações ',
'new plugin installed': 'novo plugin instalado',
'New Record': 'Novo registro',
'new record inserted': 'novo registro inserido',
'New simple application': 'Nova aplicação básica',
'next 100 rows': 'próximos 100 registros',
'NO': 'NÃO',
'No databases in this application': 'Não existem bancos de dados nesta aplicação',
'no match': 'não encontrado',
'no package selected': 'nenhum pacote selecionado',
'No ticket_storage.txt found under /private folder': 'No ticket_storage.txt found under /private folder',
'online designer': 'online designer',
'or alternatively': 'or alternatively',
'Or Get from URL:': 'Ou Obtenha do URL:',
'or import from csv file': 'ou importar de um arquivo CSV',
'or provide app url:': 'ou forneça a url de uma aplicação:',
'or provide application url:': 'ou forneça a url de uma aplicação:',
'Origin': 'Origem',
'Original/Translation': 'Original/Tradução',
'Overwrite installed app': 'sobrescrever aplicação instalada',
'Pack all': 'criar pacote',
'Pack compiled': 'criar pacote compilado',
'Pack custom': 'Pack custom',
'pack plugin': 'empacotar plugin',
'PAM authenticated user, cannot change password here': 'usuario autenticado por PAM, não pode alterar a senha por aqui',
'Password': 'Senha',
'password changed': 'senha alterada',
'Peeking at file': 'Visualizando arquivo',
'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...',
'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" eliminado',
'Plugin "%s" in application': 'Plugin "%s" na aplicação',
'plugins': 'plugins',
'Plugins': 'Plugins',
'Plural-Forms:': 'Plural-Forms:',
'Powered by': 'Este site utiliza',
'previous 100 rows': '100 registros anteriores',
'Private files': 'Private files',
'private files': 'private files',
'PythonAnywhere Apps': 'PythonAnywhere Apps',
'PythonAnywhere Password': 'PythonAnywhere Password',
'Query:': 'Consulta:',
'Rapid Search': 'Rapid Search',
'Read': 'Read',
'record': 'registro',
'record does not exist': 'o registro não existe',
'record id': 'id do registro',
'Record ID': 'ID do Registro',
'Register': 'Registrar-se',
'Registration key': 'Chave de registro',
'Reload routes': 'Reload routes',
'Remove compiled': 'eliminar compilados',
'Replace': 'Substituir',
'Replace All': 'Substituir Tudo',
'request': 'request',
'requires python-git, but not installed': 'requires python-git, but not installed',
'Resolve Conflict file': 'Arquivo de resolução de conflito',
'response': 'response',
'restore': 'restaurar',
'revert': 'reverter',
'Role': 'Papel',
'Rows in table': 'Registros na tabela',
'Rows selected': 'Registros selecionados',
'rules are not defined': 'rules are not defined',
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')",
'Running on %s': 'A correr em %s',
'Save': 'Save',
'save': 'salvar',
'Save file:': 'Gravar ficheiro:',
'Save file: %s': 'Gravar ficheiro: %s',
'Save via Ajax': 'Gravar via Ajax',
'Saved file hash:': 'Hash do arquivo salvo:',
'selected': 'selecionado(s)',
'session': 'session',
'session expired': 'sessão expirada',
'shell': 'Terminal',
'Site': 'site',
'some files could not be removed': 'alguns arquicos não puderam ser removidos',
'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying',
'source : filesystem': 'source : filesystem',
'Start a new app': 'Start a new app',
'Start searching': 'Start searching',
'Start wizard': 'iniciar assistente',
'state': 'estado',
'Static': 'Static',
'static': 'estáticos',
'Static files': 'Arquivos estáticos',
'Submit': 'Submit',
'submit': 'enviar',
'Sure you want to delete this object?': 'Tem certeza que deseja apaagr este objeto?',
'switch to : db': 'switch to : db',
'table': 'tabela',
'Table name': 'Nome da tabela',
'test': 'testar',
'Testing application': 'Testando a aplicação',
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'A "consulta" é uma condição como "db.tabela.campo1==\'valor\'". Algo como "db.tabela1.campo1==db.tabela2.campo2" resulta em um JOIN SQL.',
'the application logic, each URL path is mapped in one exposed function in the controller': 'A lógica da aplicação, cada URL é mapeada para uma função exposta pelo controlador',
'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller',
'the data representation, define database tables and sets': 'A representação dos dadps, define tabelas e estruturas de dados',
'The data representation, define database tables and sets': 'The data representation, define database tables and sets',
'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates',
'the presentations layer, views are also known as templates': 'A camada de apresentação, As visões também são chamadas de templates',
'There are no controllers': 'Não existem controllers',
'There are no models': 'Não existem modelos',
'There are no modules': 'Não existem módulos',
'There are no plugins': 'There are no plugins',
'There are no private files': '',
'There are no static files': 'Não existem arquicos estáticos',
'There are no translators, only default language is supported': 'Não há traduções, somente a linguagem padrão é suportada',
'There are no views': 'Não existem visões',
'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app',
'These files are served without processing, your images go here': 'These files are served without processing, your images go here',
'these files are served without processing, your images go here': 'Estes arquivos são servidos sem processamento, suas imagens ficam aqui',
'This is the %(filename)s template': 'Este é o template %(filename)s',
'Ticket': 'Ticket',
'Ticket ID': 'Ticket ID',
'Timestamp': 'Data Atual',
'TM': 'MR',
'to previous version.': 'para a versão anterior.',
'To create a plugin, name a file/folder plugin_[name]': 'Para criar um plugin, nomeio um arquivo/pasta como plugin_[nome]',
'toggle breakpoint': 'toggle breakpoint',
'Toggle comment': 'Toggle comment',
'Toggle Fullscreen': 'Toggle Fullscreen',
'Traceback': 'Traceback',
'translation strings for the application': 'textos traduzidos para a aplicação',
'Translation strings for the application': 'Translation strings for the application',
'try': 'tente',
'try something like': 'tente algo como',
'Try the mobile interface': 'Try the mobile interface',
'Unable to check for upgrades': 'Não é possível checar as atualizações',
'unable to create application "%s"': 'não é possível criar a aplicação "%s"',
'unable to delete file "%(filename)s"': 'não é possível criar o arquico "%(filename)s"',
'unable to delete file plugin "%(plugin)s"': 'não é possível criar o plugin "%(plugin)s"',
'Unable to download': 'Não é possível efetuar o download',
'Unable to download app': 'Não é possível baixar a aplicação',
'Unable to download app because:': 'Não é possível baixar a aplicação porque:',
'Unable to download because': 'Não é possível baixar porque',
'unable to parse csv file': 'não é possível analisar o arquivo CSV',
'unable to uninstall "%s"': 'não é possível instalar "%s"',
'unable to upgrade because "%s"': 'não é possível atualizar porque "%s"',
'uncheck all': 'desmarcar todos',
'Uninstall': 'desinstalar',
'update': 'atualizar',
'update all languages': 'atualizar todas as linguagens',
'Update:': 'Atualizar:',
'upgrade now to %s': 'upgrade now to %s',
'upgrade web2py now': 'atualize o web2py agora',
'upload': 'upload',
'Upload': 'Upload',
'Upload & install packed application': 'Faça upload e instale uma aplicação empacotada',
'Upload a package:': 'Faça upload de um pacote:',
'Upload and install packed application': 'Upload and install packed application',
'upload application:': 'Fazer upload de uma aplicação:',
'Upload existing application': 'Faça upload de uma aplicação existente',
'upload file:': 'Enviar arquivo:',
'upload plugin file:': 'Enviar arquivo de plugin:',
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) para AND, (...)|(...) para OR, y ~(...) para NOT, para criar consultas mais complexas.',
'Use an url:': 'Use uma url:',
'User ID': 'ID do Usuario',
'Username': 'Username',
'variables': 'variáveis',
'Version': 'Versão',
'versioning': 'versionamento',
'Versioning': 'Versioning',
'view': 'visão',
'Views': 'Visões',
'views': 'visões',
'Warning!': 'Warning!',
'Web Framework': 'Web Framework',
'web2py Admin Password': 'web2py Admin Password',
'web2py is up to date': 'web2py está atualizado',
'web2py Recent Tweets': 'Tweets Recentes de @web2py',
'web2py upgraded; please restart it': 'web2py atualizado; favor reiniciar',
'Welcome to web2py': 'Bem-vindo ao web2py',
'YES': 'SIM',
'You only need these if you have already registered': 'You only need these if you have already registered',
}

View File

@@ -4,6 +4,7 @@ import time
from gluon import portalocker
from gluon.admin import apath
from gluon.fileutils import read_file
from gluon.utils import web2py_uuid
# ###########################################################
# ## make sure administrator is on localhost or https
# ###########################################################
@@ -49,15 +50,18 @@ except IOError:
def verify_password(password):
session.pam_user = None
if DEMO_MODE:
return True
ret = True
elif not _config.get('password'):
return False
ret - False
elif _config['password'].startswith('pam_user:'):
session.pam_user = _config['password'][9:].strip()
import gluon.contrib.pam
return gluon.contrib.pam.authenticate(session.pam_user, password)
ret = gluon.contrib.pam.authenticate(session.pam_user, password)
else:
return _config['password'] == CRYPT()(password)[0]
ret = _config['password'] == CRYPT()(password)[0]
if ret:
session.hmac_key = web2py_uuid()
return ret
# ###########################################################
@@ -100,13 +104,12 @@ def write_hosts_deny(denied_hosts):
portalocker.unlock(f)
f.close()
def login_record(success=True):
denied_hosts = read_hosts_deny()
val = (0, 0)
if success and request.client in denied_hosts:
del denied_hosts[request.client]
elif not success and not request.is_local:
elif not success:
val = denied_hosts.get(request.client, (0, 0))
if time.time() - val[1] < expiration_failed_logins \
and val[0] >= allowed_number_of_attempts:
@@ -117,6 +120,11 @@ def login_record(success=True):
write_hosts_deny(denied_hosts)
return val[0]
def failed_login_count():
denied_hosts = read_hosts_deny()
val = denied_hosts.get(request.client, (0, 0))
return val[0]
# ###########################################################
# ## session expiration

View File

@@ -1,579 +0,0 @@
/*=============================================================
GENERAL
==============================================================*/
html,body{height:auto;background:transparent;}
/*=============================================================
CONTROLS
==============================================================*/
label,
input,
button,
select,
textarea,
button.btn
{
font-size:13px;
font-weight:normal;
line-height:18px;
}
textarea,
select
{
margin-bottom:9px;
}
select,
/*textarea,*/
input[type="text"],
input[type="password"],
input[type="datetime"],
input[type="datetime-local"],
input[type="date"],
input[type="month"],
input[type="time"],
input[type="week"],
input[type="number"],
input[type="email"],
input[type="url"],
input[type="search"],
input[type="tel"],
input[type="color"],
.uneditable-input,
a.btn-lnk
{
height:18px;
padding:4px;
font-size:13px;
line-height:18px;
}
.design h3,
.plugin h3
{
background-position:0 2px;
}
select,
input[type="file"]
{
height:28px;
line-height:28px;
}
input[type="submit"],
input[type="button"]
{
font-size:13px;
height:28px;
line-height:18px;
padding:4px 10px;
}
input[type="radio"],
input[type="checkbox"]
{
margin-top:2px;
}
.button.btn
{
line-height:1.25em;
font-size:inherit;
border:none;
text-shadow:none;
margin-bottom:0px;
-webkit-border-radius:0px;
-moz-border-radius:0px;
border-radius:0px;
-webkit-box-shadow:none;
-moz-box-shadow:none;
box-shadow:none);
}
.button.btn:hover
{
background-color:transparent;
-webkit-transition: background-position 0s linear;
-moz-transition: background-position 0s linear;
-o-transition: background-position 0s linear;
transition: background-position 0s linear;
}
form label
{
font-weight:bold;
}
.help
{
border-color:transparent;
}
/* tree menu */
.folder
{
border:none;
}
.folder>i
{
display:none;
}
.celled
{
padding-top: 2px;
}
.celled-one
{
padding-top: 1px;
}
.test h3
{
border:0;
padding-left:18px;
}
/*=============================================================
FLASH MESSAGEBOX
==============================================================*/
.flash
{
position:fixed;
width:50%;
top:49px;
left:25%;
right:25%;
cursor:default;
text-align:center;
padding:8px 35px 8px 14px;
z-index:5620;
}
.flash>.close
{
color:inherit;
opacity:0.7;
}
.flash>.close:hover
{
opacity:0.9;
}
/*=============================================================
NAVBAR
==============================================================*/
.navbar-fixed-top .navbar-inner,
.navbar-static-top .navbar-inner
{
/* in place of shadow image */
-webkit-box-shadow:0px 10px 20px rgba(195,195,195,1.0);
-moz-box-shadow: 0px 10px 20px rgba(195,195,195,1.0);
box-shadow: 0px 10px 20px rgba(195,195,195,1.0);
//zoom:1; /* IE6-9 */
filter:progid:DXImageTransform.Microsoft.DropShadow(OffX=0, OffY=10, Color=#000000); /* IE6-9 */
padding:0;
}
.navbar-inverse .navbar-inner
{
min-height:33px; /* required - override */
height:33px;
filter:progid:DXImageTransform.Microsoft.gradient(enabled=false); /* IE6-9 */
background:#292929 url(../images/header_bg.png) repeat-x;
border:none;
}
#header
{
background:transparent;
}
#header.navbar
{
overflow:visible;
}
.navbar-inverse .nav > li > a
{
padding:0;
line-height:1.25;
text-shadow:none;
}
.navbar .btn-navbar
{
padding:4px;
margin:5px 5px 0 5px;
}
#menu{margin-right:-7px;}
/*=============================================================
FOOTER
==============================================================*/
#footer
{
padding-bottom:0;
}
/*=============================================================
MAIN
==============================================================*/
#main
{
position:static;
padding-top:0;
padding-bottom:0;
}
/*=============================================================
SIDEBAR
==============================================================*/
.sidebar_inner
{
background:transparent;
padding:0;
min-width:auto;
}
.sidebar .box {
border-top:1px solid #EEE;
}
/*=============================================================
WIZARD
==============================================================*/
.step div.help li
{
line-height:inherit;
}
.ms-container .ms-selectable li.ms-elem-selectable,
.ms-container .ms-selection li.ms-elem-selected
{
font-size:13px;
}
.input-append a.btn
{
padding:4px;
height:18px;
font-size:13px;
line-height:18px;
}
/*=============================================================
ERRORS TABLE
==============================================================*/
.errors .table th
{
filter:progid:DXImageTransform.Microsoft.gradient(enabled=false); /* IE6-9 */
}
.tablebar span.help
{
font-weight:normal;
line-height:1.25em;
text-shadow:none;
width:auto;
}
/*=============================================================
TOOLTIP
==============================================================*/
.tooltip.in
{
opacity:1;
filter:alpha(opacity=100);
}
.tooltip-inner
{
opacity:1;
text-align:left;
background:#9fb364;
color:#eef1d9;
border:1px solid #eef1d9;
font-style:italic;
padding:0.3em;
-moz-border-radius:0.5em;
border-radius:0.5em;
font-size:13px;
text-transform:none;
}
.tooltip.right .tooltip-arrow,
.tooltip.left .tooltip-arrow
{
border-color:transparent;
}
/*=============================================================
THE GRID
==============================================================*/
.w2p_grid_bottom_bar .w2p_export_menu
{
line-height:18px;
margin-left:0;
}
.w2p_export_menu .dropdown-toggle
{
cursor:pointer;
margin:0;
padding:0;
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(white), to(#E6E6E6));
background-image: -webkit-linear-gradient(top, white, #E6E6E6);
background-image: -o-linear-gradient(top, white, #E6E6E6);
background-image: linear-gradient(to bottom, white, #E6E6E6);
background-image: -moz-linear-gradient(top, white, #E6E6E6);
}
.w2p_export_menu ul
{
margin-top:2px;
display:none;
}
.w2p_export_menu li
{
display:list-item;
margin:0;
}
div.web2py_grid
{
font-size:13px;
line-height:18px;
}
.web2py_grid a.btn
{
font-size:13px;
line-height:18px;
padding:4px 10px;
margin-left:0;
margin-right:4px;
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
}
.web2py_grid .input-append .btn
{
padding:4px 10px;
margin-right:0;
font-family:inherit;
color:#333;
text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);
border:1px solid #c5c5c5;
}
.web2py_grid select:focus
{
border-color:rgba(232,149,60,0.8);
outline:0;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(232, 149, 60, 0.6);
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(232,149,60,0.6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(232, 149, 60, 0.6);
}
.web2py_console input[type="button"],
.web2py_grid .row_buttons a.btn
{
color:#333;
line-height:18px;
padding:4px 10px;
text-shadow:rgba(255, 255, 255, 0.74902) 0px 1px 1px;
border-color:rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.web2py_console input[type="button"]:hover,
.web2py_grid .row_buttons a.btn:hover
{
color:#333;
border-color:rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);
background:#E6E6E6;
background-position: 0 -15px !important;
-webkit-transition: background-position .1s linear;
-moz-transition: background-position .1s linear;
-o-transition: background-position .1s linear;
transition: background-position .1s linear;
}
.web2py_table
{
border:none;
}
.web2py_table table
{
/*table-layout:fixed;*/
margin-bottom:4px;
}
.web2py_table table td
{
/*word-wrap:break-word;*/ /*uncomment when "table-layout:fixed" is applied */
}
.web2py_grid thead th
{
background-color:transparent;
padding:4px 5px;
line-height:18px;
vertical-align:bottom;
border-right:0;
border-bottom:0;
word-wrap:break-word;
}
.web2py_grid .btn-group > .dropdown-menu
{
font-size:13px;
}
.web2py_grid .dropdown-menu li > a:hover,
.web2py_grid .dropdown-menu li > a:focus
{
filter:progid:DXImageTransform.Microsoft.gradient(enabled=false); /* IE6-9 */
background-image:none;
background-color:#E8953C;
}
.pagination
{
margin:0;
height:30px;
}
.pagination ul > li > a
{
line-height:28px;
}
#w2p_grid_addbtn:focus,
#w2p_search-form :focus,
.btn:focus
{
outline:none;
}
.web2py_console input[type="button"]:focus,
.web2py_grid .row_buttons a.btn:focus
{
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15) inset, 0 1px 2px rgba(0, 0, 0, 0.05);
}
div.web2py_counter.span6
{
min-height:20px;
}
.web2py_paginator
{
border:0;
margin:0;
padding:0;
background-color:transparent;
}
.web2py_paginator ul li a
{
margin-right:0;
padding:0 14px;
border:1px solid #DDD;
border-left-width:0;
color:#E8953C;
}
.web2py_paginator ul li a:hover
{
background: whiteSmoke;
border: 1px solid #DDD;
border-left-width:0;
color:#e2821b;
}
.web2py_paginator ul li:first-child a,
.web2py_paginator ul li:first-child a:hover
{
border-left-width:1px;
}
.web2py_paginator .current
{
font-weight:normal;
}
.web2py_paginator ul li.current a:hover
{
color:#999;
}
.editor-bar-column a[name="save"]
{
background-color: whiteSmoke;
background-image: -webkit-gradient(linear,0 0,0 100%,from(white),to(#E6E6E6));
background-image: -webkit-linear-gradient(top,white,#E6E6E6);
background-image: -o-linear-gradient(top,white,#E6E6E6);
background-image: linear-gradient(to bottom,white,#E6E6E6);
background-image: -moz-linear-gradient(top,white,#E6E6E6);
background-repeat: repeat-x;
padding:2px 6px;
font-size:11px;
line-height:17px;
margin:0;
}
.editor-bar-column a[name="save"]:hover
{
background-color: #E6E6E6;
background-position: 0 -15px;
-webkit-transition: background-position .1s linear;
-moz-transition: background-position .1s linear;
-o-transition: background-position .1s linear;
transition: background-position .1s linear;
}
.keybindings
{
padding:0 18px 10px;
}
.keybindings li
{
margin-bottom:0;
}
/*----- translate page ---*/
.languageform input
{
margin-bottom:0;
}
.languageform div
{
margin-bottom:9px;
}
.languageform input.untranslated
{
background-color:#FC0;
}
.step #wizard_nav .first-box
{
padding-top:0;
}
/*=============================================================
MEDIA QUERIES
==============================================================*/
@media (max-width: 979px)
{
/*-----------------------------------
Navbar
-------------------------------------*/
#header .navbar-inner
{
padding:0;
}
/*collapsed menu*/
.navbar .nav-collapse .nav
{
background:#222;
padding:8px 2px 8px 8px;
-webkit-border-bottom-right-radius:8px;
-webkit-border-bottom-left-radius:8px;
-moz-border-radius-bottomright:8px;
-moz-border-radius-bottomleft:8px;
border-bottom-right-radius:8px;
border-bottom-left-radius:8px;
}
#menu
{
margin-right:0;
}
#menu li
{
float:none;
}
#menu a.button,
#menu a.button span
{
background-image:url(../images/menu_responsive.png);
}
#menu a.button
{
padding:0 1em 0 0;
}
}
@media(max-width:632px)
{
/*-----------------------------------
footer
-------------------------------------*/
#footer
{
height:auto;
}
#footer select
{
margin-top:8px;
}
}

View File

@@ -476,7 +476,7 @@ h4.editableapp { background: #fff url(../images/folder.png) no-repeat; }
h4.currentapp { background: #fff url(../images/folder_locked.png) no-repeat; }
.flash { position:fixed; width:50%; top:49px; left:25%; right:25%; cursor:default; text-align:center; z-index:5620; }
.w2p_flash { position:fixed; width:50%; top:49px; left:25%; right:25%; cursor:default; text-align:center; z-index:5620; }
span#closeflash {position:absolute; top:1px; right:-1px; font-size:150%; border:1px solid black; border-color: transparent transparent #fbeed5 #fbeed5; border-radius: 0 0 0 4px; width:22px; }
span#closeflash:hover {font-weight:bold; cursor:pointer; }

View File

@@ -1,322 +0,0 @@
/** these MUST stay **/
a {text-decoration:none; white-space:nowrap}
a:hover {text-decoration:underline}
a.button {text-decoration:none}
h1,h2,h3,h4,h5,h6 {margin:0.5em 0 0.25em 0; display:block;
font-family:Helvetica}
h1 {font-size:4.00em}
h2 {font-size:3.00em}
h3 {font-size:2.00em}
h4 {font-size:1.50em}
h5 {font-size:1.25em}
h6 {font-size:1.12em}
th,label {font-weight:bold; white-space:nowrap;}
td,th {text-align:left; padding:2px 5px 2px 5px}
th {vertical-align:middle; border-right:1px solid white}
td {vertical-align:top}
form table tr td label {text-align:left}
p,table,ol,ul {padding:0; margin: 0.75em 0}
p {text-align:justify}
ol, ul {list-style-position:outside; margin-left:2em}
li {margin-bottom:0.5em}
span,input,select,textarea,button,label,a {display:inline}
img {border:0}
blockquote,blockquote p,p blockquote {
font-style:italic; margin:0.5em 30px 0.5em 30px; font-size:0.9em}
i,em {font-style:italic}
strong {font-weight:bold}
small {font-size:0.8em}
code {font-family:Courier}
textarea {width:100%}
video {width:400px}
audio {width:200px}
[type="text"], [type="password"], select {
margin-right: 5px; width: 300px;
}
.hidden {display:none;visibility:visible}
.right {float:right; text-align:right}
.left {float:left; text-align:left}
.center {width:100%; text-align:center; vertical-align:middle}
/** end **/
/* Sticky footer begin */
.main {
padding:20px 0 50px 0;
}
.footer,.push {
height:6em;
padding:1em 0;
clear:both;
}
.footer-content {position:relative; bottom:-4em; width:100%}
.auth_navbar {
white-space:nowrap;
}
/* Sticky footer end */
.footer {
border-top:1px #DEDEDE solid;
}
.header {
/* background:<fill here for header image>; */
}
fieldset {padding:16px; border-top:1px #DEDEDE solid}
fieldset legend {text-transform:uppercase; font-weight:bold; padding:4px 16px 4px 16px; background:#f1f1f1}
/* fix ie problem with menu */
td.w2p_fw {padding-bottom:1px}
td.w2p_fl,td.w2p_fw,td.w2p_fc {vertical-align:top}
td.w2p_fl {text-align:left}
td.w2p_fl, td.w2p_fw {padding-right:7px}
td.w2p_fl,td.w2p_fc {padding-top:4px}
div.w2p_export_menu {margin:5px 0}
div.w2p_export_menu a, div.w2p_wiki_tags a, div.w2p_cloud a {margin-left:5px; padding:2px 5px; background-color:#f1f1f1; border-radius:5px; -moz-border-radius:5px; -webkit-border-radius:5px;}
/* tr#submit_record__row {border-top:1px solid #E5E5E5} */
#submit_record__row td {padding-top:.5em}
/* Fix */
#auth_user_remember__row label {display:inline}
#web2py_user_form td {vertical-align:top}
/*********** web2py specific ***********/
div.flash {
font-weight:bold;
display:none;
position:fixed;
padding:10px;
top:48px;
right:250px;
min-width:280px;
opacity:0.95;
margin:0px 0px 10px 10px;
vertical-align:middle;
cursor:pointer;
color:#fff;
background-color:#000;
border:2px solid #fff;
border-radius:8px;
-o-border-radius: 8px;
-moz-border-radius:8px;
-webkit-border-radius:8px;
background-image: -webkit-linear-gradient(top,#222,#000);
background-image: -o-linear-gradient(top,#222,#000);
background-image: -moz-linear-gradient(90deg, #222, #000);
background-image: linear-gradient(top,#222,#000);
background-repeat: repeat-x;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
z-index:2000;
}
div.flash #closeflash{color:inherit; float:right; margin-left:15px;}
.ie-lte7 div.flash #closeflash
{color:expression(this.parentNode.currentStyle['color']);float:none;position:absolute;right:4px;}
div.flash:hover { opacity:0.25; }
div.error_wrapper {display:block}
div.error {
width: 298px;
background:red;
border: 2px solid #d00;
color:white;
padding:5px;
display:inline-block;
background-image: -webkit-linear-gradient(left,#f00,#fdd);
background-image: -o-linear-gradient(left,#f00,#fdd);
background-image: -moz-linear-gradient(0deg, #f00, #fdd);
background-image: linear-gradient(left,#f00,#fdd);
background-repeat: repeat-y;
}
.topbar {
padding:10px 0;
width:100%;
color:#959595;
vertical-align:middle;
padding:auto;
background-image:-khtml-gradient(linear,left top,left bottom,from(#333333),to(#222222));
background-image:-moz-linear-gradient(top,#333333,#222222);
background-image:-ms-linear-gradient(top,#333333,#222222);
background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#333333),color-stop(100%,#222222));
background-image:-webkit-linear-gradient(top,#333333,#222222);
background-image:-o-linear-gradient(top,#333333,#222222);
background-image:linear-gradient(top,#333333,#222222);
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333',endColorstr='#222222',GradientType=0);
-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.25),inset 0 -1px 0 rgba(0,0,0,0.1);
-moz-box-shadow:0 1px 3px rgba(0,0,0,0.25),inset 0 -1px 0 rgba(0,0,0,0.1);
box-shadow:0 1px 3px rgba(0,0,0,0.25),inset 0 -1px 0 rgba(0,0,0,0.1);
}
.topbar a {
color:#e1e1e1;
}
#navbar {float:right; padding:5px; /* same as superfish */}
.statusbar {
background-color:#F5F5F5;
margin-top:1em;
margin-bottom:1em;
padding:.5em 1em;
border:1px solid #ddd;
border-radius:5px;
-moz-border-radius:5px;
-webkit-border-radius:5px;
}
.breadcrumbs {float:left}
.copyright {float:left}
#poweredBy {float:right}
/* #MEDIA QUERIES SECTION */
/*
*Grid
*
* The default style for SQLFORM.grid even using jquery-iu or another ui framework
* will look better with the declarations below
* if needed to remove base.css consider keeping these following lines in some css file.
*/
/* .web2py_table {border:1px solid #ccc} */
.web2py_paginator {}
.web2py_grid {width:100%}
.web2py_grid table {width:100%}
.web2py_grid tbody td {padding:2px 5px 2px 5px; vertical-align: middle;}
.web2py_grid .web2py_form td {vertical-align: top;}
.web2py_grid thead th,.web2py_grid tfoot td {
background-color:#EAEAEA;
padding:10px 5px 10px 5px;
}
.web2py_grid tr.odd {background-color:#F9F9F9}
.web2py_grid tr:hover {background-color:#F5F5F5}
/*
.web2py_breadcrumbs a {
line-height:20px; margin-right:5px; display:inline-block;
padding:3px 5px 3px 5px;
font-family:'lucida grande',tahoma,verdana,arial,sans-serif;
color:#3C3C3D;
text-shadow:1px 1px 0 #FFFFFF;
white-space:nowrap; overflow:visible; cursor:pointer;
background:#ECECEC;
border:1px solid #CACACA;
-webkit-border-radius:2px; -moz-border-radius:2px;
-webkit-background-clip:padding-box; border-radius:2px;
outline:none; position:relative; zoom:1; *display:inline;
}
*/
.web2py_console form {
width: 100%;
display: inline;
vertical-align: middle;
margin: 0 0 0 5px;
}
.web2py_console form select {
margin:0;
}
.web2py_search_actions {
float:left;
text-align:left;
}
.web2py_grid .row_buttons {
min-height:25px;
vertical-align:middle;
}
.web2py_grid .row_buttons a {
margin:3px;
}
.web2py_search_actions {
width:100%;
}
.web2py_grid .row_buttons a,
.web2py_paginator ul li a,
.web2py_search_actions a,
.web2py_console input[type=submit],
.web2py_console input[type=button],
.web2py_console button {
line-height:20px;
margin-right:2px; display:inline-block;
padding:3px 5px 3px 5px;
}
.web2py_counter {
margin-top:5px;
margin-right:2px;
width:35%;
float:right;
text-align:right;
}
/*Fix firefox problem*/
.web2py_table {clear:both; display:block}
.web2py_paginator {
padding:5px;
text-align:right;
background-color:#f2f2f2;
}
.web2py_paginator ul {
list-style-type:none;
margin:0px;
padding:0px;
}
.web2py_paginator ul li {
display:inline;
}
.web2py_paginator .current {
font-weight:bold;
}
.web2py_breadcrumbs ul {
list-style:none;
margin-bottom:18px;
}
li.w2p_grid_breadcrumb_elem {
display:inline-block;
}
.web2py_console form { vertical-align: middle; }
.web2py_console input, .web2py_console select,
.web2py_console a { margin: 2px; }
.web2py_htmltable {
width: 100%;
overflow-x: auto;
-ms-overflow-x:scroll;
}
#wiki_page_body {
width: 600px;
height: auto;
min-height: 400px;
}
/* fix some IE problems */
.ie-lte7 .topbar .container {z-index:2}
.ie-lte8 div.flash{ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0 ); }
.ie-lte8 div.flash:hover {filter:alpha(opacity=25);}
.ie9 #w2p_query_panel {padding-bottom:2px}

View File

@@ -1,264 +0,0 @@
/*=============================================================
CUSTOM RULES
==============================================================*/
body{height:auto;} /* to avoid vertical scroll bar */
a{}
a:visited{}
a:hover{}
a:focus{}
a:active{}
h1{}
h2{}
h3{}
h4{}
h5{}
h6{}
div.flash.flash-center{left:25%;right:25%;}
div.flash.flash-top,div.flash.flash-top:hover{
position:relative;
display:block;
margin:0;
padding:1em;
top:0;
left:0;
width:100%;
text-align:center;
text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);
color:#865100;
background:#feea9a;
border:1px solid;
border-top:0px;
border-left:0px;
border-right:0px;
border-radius:0;
opacity:1;
}
#header{margin-top:60px;}
.mastheader h1 {
margin-bottom:9px;
font-size:81px;
font-weight:bold;
letter-spacing:-1px;
line-height:1;
font-size:54px;
}
.mastheader small {
font-size:20px;
font-weight:300;
}
/* auth navbar - primitive style */
.auth_navbar,.auth_navbar a{color:inherit;}
.navbar-inner {-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
.ie-lte7 .auth_navbar,.auth_navbar a{color:expression(this.parentNode.currentStyle['color']); /* ie7 doesn't support inherit */}
.auth_navbar a{white-space:nowrap;} /* to avoid the nav split on more lines */
.auth_navbar a:hover{color:white;text-decoration:none;}
ul#navbar>.auth_navbar{
display:inline-block;
padding:5px;
}
/* form errors message box customization */
div.error_wrapper{margin-bottom:9px;}
div.error_wrapper .error{
border-radius: 4px;
-o-border-radius: 4px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
}
/* below rules are only for formstyle = bootstrap
trying to make errors look like bootstrap ones */
div.controls .error_wrapper{
display:inline-block;
margin-bottom:0;
vertical-align:middle;
}
div.controls .error{
min-width:5px;
background:inherit;
color:#B94A48;
border:none;
padding:0;
margin:0;
/*display:inline;*/ /* uncommenting this, the animation effect is lost */
}
div.controls .help-inline{color:#3A87AD;}
div.controls .error_wrapper +.help-inline {margin-left:-99999px;}
div.controls select +.error_wrapper {margin-left:5px;}
.ie-lte7 div.error{color:#fff;}
/* beautify brand */
.navbar {margin-bottom:0}
.navbar-inverse .brand{color:#c6cecc;}
.navbar-inverse .brand b{display:inline-block;margin-top:-1px;}
.navbar-inverse .brand b>span{font-size:22px;color:white}
.navbar-inverse .brand:hover b>span{color:white}
/* beautify web2py link in navbar */
span.highlighted{color:#d8d800;}
.open span.highlighted{color:#ffff00;}
/*=============================================================
OVERRIDING WEB2PY.CSS RULES
==============================================================*/
/* reset to default */
a{white-space:normal;}
li{margin-bottom:0;}
textarea,button{display:block;}
/*reset ul padding */
ul#navbar{padding:0;}
/* label aligned to related input */
td.w2p_fl,td.w2p_fc {padding:0;}
#web2py_user_form td{vertical-align:middle;}
/*=============================================================
OVERRIDING BOOTSTRAP.CSS RULES
==============================================================*/
/* because web2py handles this via js */
textarea { width:90%}
.hidden{visibility:visible;}
/* right folder for bootstrap black images/icons */
[class^="icon-"],[class*=" icon-"]{
background-image:url("../images/glyphicons-halflings.png")
}
/* right folder for bootstrap white images/icons */
.icon-white,
.nav-tabs > .active > a > [class^="icon-"],
.nav-tabs > .active > a > [class*=" icon-"],
.nav-pills > .active > a > [class^="icon-"],
.nav-pills > .active > a > [class*=" icon-"],
.nav-list > .active > a > [class^="icon-"],
.nav-list > .active > a > [class*=" icon-"],
.navbar-inverse .nav > .active > a > [class^="icon-"],
.navbar-inverse .nav > .active > a > [class*=" icon-"],
.dropdown-menu > li > a:hover > [class^="icon-"],
.dropdown-menu > li > a:hover > [class*=" icon-"],
.dropdown-menu > .active > a > [class^="icon-"],
.dropdown-menu > .active > a > [class*=" icon-"] {
background-image:url("../images/glyphicons-halflings-white.png");
}
/* bootstrap has a label as input's wrapper while web2py has a div */
div>input[type="radio"],div>input[type="checkbox"]{margin:0;}
/* bootstrap has button instead of input */
input[type="button"], input[type="submit"]{margin-right:8px;}
/* web2py radio widget adjustment */
.generic-widget input[type='radio'] {margin:-1px 0 0 0; vertical-align: middle;}
.generic-widget input[type='radio'] + label {display:inline-block; margin:0 0 0 6px; vertical-align: middle;}
/*=============================================================
RULES FOR SOLVING CONFLICTS BETWEEN WEB2PY.CSS AND BOOTSTRAP.CSS
==============================================================*/
/*when formstyle=table3cols*/
tr#auth_user_remember__row>td.w2p_fw>div{padding-bottom:8px;}
td.w2p_fw div>label{vertical-align:middle;}
td.w2p_fc {padding-bottom:5px;}
/*when formstyle=divs*/
div#auth_user_remember__row{margin-top:4px;}
div#auth_user_remember__row>.w2p_fl{display:none;}
div#auth_user_remember__row>.w2p_fw{min-height:39px;}
div.w2p_fw,div.w2p_fc{
display:inline-block;
vertical-align:middle;
margin-bottom:0;
}
div.w2p_fc{
padding-left:5px;
margin-top:-8px;
}
/*when formstyle=ul*/
form>ul{
list-style:none;
margin:0;
}
li#auth_user_remember__row{margin-top:4px;}
li#auth_user_remember__row>.w2p_fl{display:none;}
li#auth_user_remember__row>.w2p_fw{min-height:39px;}
/*when formstyle=bootstrap*/
#auth_user_remember__row label.checkbox{display:block;}
span.inline-help{display:inline-block;}
input[type="text"].input-xlarge,input[type="password"].input-xlarge{width:270px;}
/*when recaptcha is used*/
#recaptcha{min-height:30px;display:inline-block;margin-bottom:0;line-height:30px;vertical-align:middle;}
td>#recaptcha{margin-bottom:6px;}
div>#recaptcha{margin-bottom:9px;}
div.control-group.error{
width:auto;
background:transparent;
border:0;
color:inherit;
padding:0;
background-repeat:repeat;
}
/*=============================================================
OTHER RULES
==============================================================*/
/* Massimo Di Pierro fixed alignment in forms with list:string */
form table tr{margin-bottom:9px;}
td.w2p_fw ul{margin-left:0px;}
/* web2py_console in grid and smartgrid */
.hidden{visibility:visible;}
.web2py_console input{
display: inline-block;
margin-bottom: 0;
vertical-align: middle;
}
.web2py_console input[type="submit"],
.web2py_console input[type="button"],
.web2py_console button{
padding-top:4px;
padding-bottom:4px;
margin:3px 0 0 2px;
}
.web2py_console a,
.web2py_console select,
.web2py_console input
{
margin:3px 0 0 2px;
}
.web2py_grid form table{width:auto;}
/* auth_user_remember checkbox extrapadding in IE fix */
.ie-lte9 input#auth_user_remember.checkbox {padding-left:0;}
div.controls .error {
width: auto;
}
/*=============================================================
MEDIA QUERIES
==============================================================*/
@media only screen and (max-width:979px){
body{padding-top:0px;}
#navbar{/*top:5px;*/}
div.flash{right:5px;}
.dropdown-menu ul{visibility:visible;}
}
@media only screen and (max-width:479px){
body{
padding-left:10px;
padding-right:10px;
}
.navbar-fixed-top,.navbar-fixed-bottom {
margin-left:-10px;
margin-right:-10px;
}
input[type="text"],input[type="password"],select{
width:95%;
}
}
@media (max-width: 767px) {
.navbar {
margin-right: -20px;
margin-left: -20px;
}
}

View File

@@ -1,122 +0,0 @@
/*=============================================================
BOOTSTRAP DROPDOWN MENU
==============================================================*/
.dropdown-menu ul{
left:100%;
position:absolute;
top:0;
visibility:hidden;
margin-top:-1px;
}
.dropdown-menu li:hover ul{visibility:visible;}
.navbar .dropdown-menu ul:before{
border-bottom:7px solid transparent;
border-left:none;
border-right:7px solid rgba(0, 0, 0, 0.2);
border-top:7px solid transparent;
left:-7px;
top:5px;
}
.nav > li.dropdown > a:after {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid #000000;
content: "";
display: inline-block;
height: 0;
opacity: 0.7;
vertical-align: top;
width: 0;
margin-left: 2px;
margin-top: 8px;
border-bottom-color: #FFFFFF;
border-top-color: #FFFFFF;
}
.dropdown-menu span{display:inline-block;}
ul.dropdown-menu li.dropdown > a:after {
border-left: 4px solid #000;
border-right: 4px solid transparent;
border-bottom: 4px solid transparent;
border-top: 4px solid transparent;
content: "";
display: inline-block;
height: 0;
opacity: 0.7;
vertical-align: top;
width: 0;
margin-left: 8px;
margin-top: 6px;
}
ul.nav li.dropdown:hover ul.dropdown-menu {
display: block;
}
.open >.dropdown-menu ul{display:block;} /* fix menu issue when BS2.0.4 is applied */
/*=============================================================
BOOTSTRAP SUBMIT BUTTON
==============================================================*/
input[type='submit']:not(.btn) {
display: inline-block;
padding: 4px 14px;
margin-bottom: 0;
font-size: 14px;
line-height: 20px;
color: #333;
text-align: center;
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
vertical-align: middle;
cursor: pointer;
background-color: whiteSmoke;
background-image: -webkit-gradient(linear,0 0,0 100%,from(white),to(#E6E6E6));
background-image: -webkit-linear-gradient(top,white,#E6E6E6);
background-image: -o-linear-gradient(top,white,#E6E6E6);
background-image: linear-gradient(to bottom,white,#E6E6E6);
background-image: -moz-linear-gradient(top,white,#E6E6E6);
background-repeat: repeat-x;
border: 1px solid #BBB;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
border-bottom-color: #A2A2A2;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);
filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
}
input[type='submit']:not(.btn):hover {
color: #333;
text-decoration: none;
background-color: #E6E6E6;
background-position: 0 -15px;
-webkit-transition: background-position .1s linear;
-moz-transition: background-position .1s linear;
-o-transition: background-position .1s linear;
transition: background-position .1s linear;
}
input[type='submit']:not(.btn).active, input[type='submit']:not(.btn):active {
background-color: #E6E6E6;
background-color: #D9D9D9 9;
background-image: none;
outline: 0;
-webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
-moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
}
/*=============================================================
OTHER
==============================================================*/
.ie-lte8 .navbar-fixed-top {position:static;}

View File

@@ -77,10 +77,10 @@ function doClickSave() {
t.attr('disabled', '');
var flash = xhr.getResponseHeader('web2py-component-flash');
if(flash) {
$('.flash').html(decodeURIComponent(flash))
$('.w2p_flash').html(decodeURIComponent(flash))
.append('<a href="#" class="close">&times;</a>')
.slideDown();
} else $('.flash').hide();
} else $('.w2p_flash').hide();
try {
if(json.error) {
window.location.href = json.redirect;
@@ -158,10 +158,10 @@ function doToggleBreakpoint(filename, url, sel) {
// show flash message (if any)
var flash = xhr.getResponseHeader('web2py-component-flash');
if(flash) {
$('.flash').html(decodeURIComponent(flash))
$('.w2p_flash').html(decodeURIComponent(flash))
.append('<a href="#" class="close">&times;</a>')
.slideDown();
} else $('.flash').hide();
} else $('.w2p_flash').hide();
try {
if(json.error) {
window.location.href = json.redirect;

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,7 @@
</ul>
<div class="tab-content">
<div class="tab-pane active" id="alltables">
<table>
<table class="table">
{{for db in sorted(databases):}}
{{for table in databases[db].tables:}}
{{qry='%s.%s.id>0'%(db,table)}}
@@ -40,7 +40,7 @@
{{=A("%s.%s" % (db,table),_href=URL('select',args=[db],vars=dict(query=qry)))}}
</th>
<td>
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn")}}
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn btn-default")}}
</td>
</tr>
{{pass}}
@@ -61,7 +61,7 @@
</pre>
{{pass}}
{{if table:}}
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/>
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn btn-default")}}<br/><br/>
<h3>{{=T("Rows in Table")}}</h3><br/>
{{else:}}
<h3>{{=T("Rows selected")}}</h3><br/>
@@ -72,8 +72,8 @@
{{=T('"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN')}}</p>
<br/><br/>
<h4>{{=T("%s selected", nrows)}}</h4>
{{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn")}}{{pass}}
{{if stop<nrows:}}{{=A(T('next %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start+step)),_class="btn")}}{{pass}}
{{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn btn-default")}}{{pass}}
{{if stop<nrows:}}{{=A(T('next %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start+step)),_class="btn btn-default")}}{{pass}}
{{if rows:}}
<div style="overflow:auto; width:80%;">
{{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}}
@@ -82,7 +82,7 @@
</div>
{{pass}}
<br/><br/><h3>{{=T("Import/Export")}}</h3><br/>
<a href="{{=URL('csv',args=request.args[0],vars=dict(query=query))}}" class="btn">{{=T("export as csv file")}}</a>
<a href="{{=URL('csv',args=request.args[0],vars=dict(query=query))}}" class="btn btn-default">{{=T("export as csv file")}}</a>
{{=formcsv or ''}}
{{elif request.function=='insert':}}
@@ -137,9 +137,9 @@
<h4>{{=T("Overview")}}</h4>
<p>{{=T.M("Number of entries: **%s**", total['entries'])}}</p>
{{if total['entries'] > 0:}}
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses})",
dict(ratio=total['ratio'], hits=total['hits'], misses=total['misses']))}}
</p>
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})",
dict( ratio=total['ratio'], hits=total['hits'], misses=total['misses']))}}
</p>
<p>
{{=T("Size of cache:")}}
{{if object_stats:}}
@@ -155,8 +155,8 @@
{{=T.M("Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
dict(hours=total['oldest'][0], min=total['oldest'][1], sec=total['oldest'][2]))}}
</p>
{{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle();')}}
<div class="hidden" id="all_keys">
{{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle().toggleClass( "w2p_hidden" );')}}
<div class="w2p_hidden" id="all_keys">
{{=total['keys']}}
</div>
<br />
@@ -183,8 +183,8 @@
{{=T.M("RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
dict(hours=ram['oldest'][0], min=ram['oldest'][1], sec=ram['oldest'][2]))}}
</p>
{{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle();')}}
<div class="hidden" id="ram_keys">
{{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle().toggleClass( "w2p_hidden" );')}}
<div class="w2p_hidden" id="ram_keys">
{{=ram['keys']}}
</div>
<br />
@@ -212,8 +212,8 @@
{{=T.M("DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
dict(hours=disk['oldest'][0], min=disk['oldest'][1], sec=disk['oldest'][2]))}}
</p>
{{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle();')}}
<div class="hidden" id="disk_keys">
{{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle().toggleClass( "w2p_hidden" );')}}
<div class="w2p_hidden" id="disk_keys">
{{=disk['keys']}}
</div>
<br />
@@ -249,8 +249,8 @@
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['png'])}}">png</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['svg'])}}">svg</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['pdf'])}}">pdf</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['ps'])}}">ps</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['dot'])}}">dot</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['ps'])}}">ps</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['dot'])}}">dot</a></li>
</ul>
</div>
<br />

View File

@@ -1,5 +1,7 @@
{{extend 'layout.html'}}
{{
import re
regex_space = re.compile('\s+')
def all(items):
return reduce(lambda a,b:a and b,items,True)
def peekfile(path,file,vars={},title=None):
@@ -205,7 +207,7 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
{{=peekfile('views',c, dict(id=id))}}
</span>
<span class="extras celled celled-one">
{{if extend.has_key(c):}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
{{if c in extend:}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
</span>
</li>
@@ -304,7 +306,7 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
while path!=file_path:
if len(file_path)>=len(path) and all([v==file_path[k] for k,v in enumerate(path)]):
path.append(file_path[len(path)])
thispath='static__'+'__'.join(path)
thispath = regex_space.sub('-', 'static__'+'__'.join(path))
}}
<li class="folder"><i>&nbsp;</i>
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
@@ -475,11 +477,11 @@ function filter_files() {
message=data['message'];
for(var i=0; i<files.length; i++)
jQuery('li#_'+files[i].replace(/\//g,'__').replace('.','__')).slideDown();
jQuery('.flash').html(message).slideDown();
jQuery('.w2p_flash').html(message).slideDown();
});
} else {
jQuery('.component_contents li, .formfield, .comptools').slideDown();
jQuery('.flash').html('').hide();
jQuery('.w2p_flash').html('').hide();
}
}
jQuery(document).ready(function(){

View File

@@ -25,6 +25,7 @@
<form action="{{=URL(args=request.args)}}" method="POST">
<h2>{{=T('Select Files to Package')}}</h2>
<input type="submit" value="{{=T('Download .w2p')}}" class="btn"/>
<input type="submit" name="doexe" value="{{=T('Download as .exe')}}" class="btn"/>
<div style="margin-top:20px">
{{tree(base)}}
</div>

View File

@@ -144,7 +144,7 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
{{=peekfile('views',c)}}
</span>
<span class="extras celled">
{{if extend.has_key(c):}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
{{if c in extend:}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
</span>
</li>

View File

@@ -27,7 +27,9 @@
{{buttons.append((URL('pack',args=a), T("Pack all")))}}
{{buttons.append((URL('pack_custom',args=a), T("Pack custom")))}}
{{if not os.path.exists('applications/%s/compiled' % a):}}
{{buttons.append((URL('compile_app',args=a), T("Compile")))}}
{{buttons.append((URL('compile_app',args=[a, 'skip_failed_views']),
T("Compile (skip failed views)")))}}
{{buttons.append((URL('compile_app',args=a), T("Compile (all or nothing)")))}}
{{else:}}
{{buttons.append((URL('pack',args=(a, 'compiled')), T("Pack compiled")))}}
{{if glob.glob('applications/%s/controllers/*.py' % a):}}
@@ -54,7 +56,7 @@
{{pass}}
</ul>
</div>
{{=button_enable(URL('enable',args=a), a) if a!='admin' else ''}}
{{=button_enable(URL('enable',args=a, hmac_key=session.hmac_key), a) if a!='admin' else ''}}
</td>
</tr>
{{pass}}
@@ -138,6 +140,7 @@
<p class="row-buttons">
{{=button(URL('gae','deploy'), T('Deploy on Google App Engine'))}}
{{=button(URL('openshift','deploy'),T('Deploy to OpenShift'))}}
{{=button(URL('pythonanywhere','deploy'), T('Deploy to PythonAnywhere'))}}
</p>
</div> <!-- /DEPLOY ON GAE -->
<!-- APP WIZARD -->

View File

@@ -47,7 +47,7 @@
<div id="{{=globals().get('main_id', 'main')}}" class="container-fluid">
<div id="main_inner" class="row-fluid">
<div class="span12">
<div class="flash alert">{{=response.flash or ''}}</div>
<div class="w2p_flash alert">{{=response.flash or ''}}</div>
{{include}}
</div><!-- /main span12 -->
</div><!-- /main row-fluid -->
@@ -77,6 +77,7 @@
<script type="text/javascript">
jQuery(document).ready(function(){
jQuery("[rel=tooltip]").tooltip();
jQuery(":input").attr("autocomplete","off");
});
</script>
<script>

View File

@@ -0,0 +1,176 @@
{{extend 'layout.html'}}
<h2><span style="color:#139FD7">python</span>anywhere {{=T('Deployment Interface')}}</h2>
<div id="register_form">
<h3>{{=T('Login/Register')}}</h3>
<form class="form-horizontal" id="palogin">
<div class="control-group" id="username__row">
<label class="control-label" for="username">{{=T('Username')}}</label>
<div class="controls">
<input type="text" name="username" id="username"><span class="help-inline">*</span>
<span class="help-block"></span>
</div>
</div>
<div class="control-group" id="email_address__row">
<label class="control-label" for="email_address">{{=T('Email Address')}}</label>
<div class="controls">
<input type="text" name="email_address" id="email_address">
<span class="help-block"></span>
</div>
</div>
<div class="control-group" id="pythonanywhere_password__row">
<label class="control-label" for="pythonanywhere_password">{{=T('PythonAnywhere Password')}}</label>
<div class="controls">
<input type="password" name="pythonanywhere_password" id="pythonanywhere_password">
<span class="help-block"></span>
</div>
</div>
<div class="control-group" id="web2py_admin_password__row">
<label class="control-label" for="web2py_admin_password">{{=T('web2py Admin Password')}}</label>
<div class="controls">
<input type="password" name="web2py_admin_password" id="web2py_admin_password"><span class="help-inline">*</span>
<span class="help-block"></span>
</div>
</div>
<div class="control-group" id="accepts_terms__row">
<div class="controls">
<label class="checkbox">
<input type="checkbox" name="accepts_terms" id="accepts_terms"><a target="_blank" href="https://www.pythonanywhere.com/terms/">{{=T('Accept Terms')}}</a>
</label>
<span class="help-block"></span>
</div>
</div>
<div class="control-group">
<div class="controls">
<button type="submit" class="btn btn-primary" id="submit_palogin">{{=T('Submit')}}</button>
</div>
</div>
</form>
<p>* {{=T('You only need these if you have already registered')}}</p>
</div>
<div class="row-fluid" id="app_manager" style="display:none;">
<div class="span6">
<h3>{{=T('Local Apps')}}</h3>
<form id="apppicker">
<select name="apps" class="form-control" id="local" multiple>
<option>{{=T('Loading...')}}</option>
</select>
<input type="submit" value="Deploy" id="deploy_button" class="btn btn-primary">
</form>
<div class="alert alert-info">
<strong>{{=T('Warning!')}}</strong> {{=T('if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.')}}
</div>
</div>
<div class="span6">
<h3>{{=T('PythonAnywhere Apps')}}</h3>
<ul id="pythonanywhere">
<li>{{=T('Loading...')}}</li>
</ul>
</div>
</div>
<script>
$(document).ready(function() {
$('#palogin').off('submit');
$('#palogin').submit(function(event) {
var data = $('#palogin').serialize();
$.web2py.disableElement($('#submit_palogin'));
$.web2py.disableFormElements($('#palogin'));
$.ajax({
url: '{{=URL("pythonanywhere", "create_account")}}',
type: 'POST',
data: data,
dataType: 'json',
}).done(function(data, textStatus, jqXHR) {
$('#palogin .error').removeClass('error');
$('#palogin .help-block').text('');
if(data.status == 'error') {
for(var error in data.errors) {
$('#' + error + '__row').addClass('error');
$('#' + error + '__row .help-block').text(data.errors[error][0]);
}
$.web2py.enableElement($('#submit_palogin'));
$.web2py.enableFormElements($('#palogin'));
$.web2py.flash("{{=T('Form has errors')}}");
} else {
$.web2py.flash("{{=T('Login successful')}}");
$('#register_form').hide();
$('#app_manager').show();
refresh_apps();
}
}).fail(function(){
$.web2py.flash("{{=T('Something went wrong please wait a few minutes before retrying')}}");
$.web2py.enableElement($('#submit_palogin'));
$.web2py.enableFormElements($('#palogin'));
});
event.preventDefault();
});
$('#apppicker').off('submit');
$('#apppicker').submit(function(event) {
var data = $('#apppicker').serialize();
$.web2py.disableElement($('#deploy_button'));
$.ajax({
url: '{{=URL("pythonanywhere", "bulk_install")}}',
type: 'POST',
data: {username: $('#username').val(), password: $('#web2py_admin_password').val(), apps: $('#local').val()},
dataType: 'json',
}).done(function(data, textStatus, jqXHR) {
refresh_apps();
$.web2py.enableElement($('#deploy_button'));
}).fail(function(){
$.web2py.flash("{{=T('Something went wrong please wait a few minutes before retrying')}}");
$.web2py.enableElement($('#deploy_button'));
});
event.preventDefault();
});
});
function refresh_apps() {
// Refresh List of Apps
$('#deploy_button').prop('disabled', true);
$.ajax({
url: '{{=URL("pythonanywhere", "list_apps")}}',
type: 'GET',
data: {username: $('#username').val(), password: $('#web2py_admin_password').val()},
dataType: 'json',
}).done(function(data, textStatus, jqXHR) {
var i = 0;
$('#local').html('')
for(i = 0; i < data.local.length; i++) {
$('#local').append($('<option>', {
value: data.local[i],
text: data.local[i]
}));
}
$('#local').multiSelect('refresh');
$('#pythonanywhere').html('')
for(i = 0; i < data.pythonanywhere.length; i++) {
$('#pythonanywhere').append($('<li>', {
text: data.pythonanywhere[i]
}));
}
$('#deploy_button').prop('disabled', false);
$.web2py.hide_flash();
}).fail(function(){
// Mostly this happens if it's a new account, just waiting a bit should be enough.
$.get('http://' + $('#username').val() + '.pythonanywhere.com'); // Kickstart the instance
$.web2py.flash("{{=T('Please wait, giving pythonanywhere a moment...')}}");
setTimeout(refresh_apps, 30000);
});
}
</script>

View File

@@ -3,6 +3,7 @@
var w2p_ajax_confirm_message = "{{=T('Are you sure you want to delete this object?')}}";
var w2p_ajax_date_format = "{{=T('%Y-%m-%d')}}";
var w2p_ajax_datetime_format = "{{=T('%Y-%m-%d %H:%M:%S')}}";
var w2p_ajax_disable_with_message = "{{=T('Working...')}}";
var ajax_error_500 = '{{=T.M('An error occured, please [[reload %s]] the page') % URL(args=request.args, vars=request.get_vars) }}'
//--></script>
{{

View File

@@ -49,7 +49,8 @@ if request.function == 'manage':
auth.table_group(),
auth.table_permission()])
manager_role = manager_action.get('role', None) if manager_action else None
auth.requires_membership(manager_role)(lambda: None)()
if not (gluon.fileutils.check_credentials(request) or auth.has_membership(manager_role)):
raise HTTP(403, "Not authorized")
menu = False
elif (request.application == 'admin' and not session.authorized) or \
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
@@ -80,7 +81,6 @@ if False and request.tickets_db:
def get_databases(request):
dbs = {}
for (key, value) in global_env.items():
cond = False
try:
cond = isinstance(value, GQLDB)
except:
@@ -420,7 +420,7 @@ def ccache():
'oldest': time.time(),
'keys': []
}
disk = copy.copy(ram)
total = copy.copy(ram)
disk['keys'] = []
@@ -445,30 +445,31 @@ def ccache():
gae_stats['oldest'] = GetInHMS(time.time() - gae_stats['oldest_item_age'])
total.update(gae_stats)
else:
# get ram stats directly from the cache object
ram_stats = cache.ram.stats[request.application]
ram['hits'] = ram_stats['hit_total'] - ram_stats['misses']
ram['misses'] = ram_stats['misses']
try:
ram['ratio'] = ram['hits'] * 100 / ram_stats['hit_total']
except (KeyError, ZeroDivisionError):
ram['ratio'] = 0
for key, value in cache.ram.storage.iteritems():
if isinstance(value, dict):
ram['hits'] = value['hit_total'] - value['misses']
ram['misses'] = value['misses']
try:
ram['ratio'] = ram['hits'] * 100 / value['hit_total']
except (KeyError, ZeroDivisionError):
ram['ratio'] = 0
else:
if hp:
ram['bytes'] += hp.iso(value[1]).size
ram['objects'] += hp.iso(value[1]).count
ram['entries'] += 1
if value[0] < ram['oldest']:
ram['oldest'] = value[0]
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
if hp:
ram['bytes'] += hp.iso(value[1]).size
ram['objects'] += hp.iso(value[1]).count
ram['entries'] += 1
if value[0] < ram['oldest']:
ram['oldest'] = value[0]
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
for key in cache.disk.storage:
value = cache.disk.storage[key]
if isinstance(value, dict):
disk['hits'] = value['hit_total'] - value['misses']
disk['misses'] = value['misses']
if isinstance(value[1], dict):
disk['hits'] = value[1]['hit_total'] - value[1]['misses']
disk['misses'] = value[1]['misses']
try:
disk['ratio'] = disk['hits'] * 100 / value['hit_total']
disk['ratio'] = disk['hits'] * 100 / value[1]['hit_total']
except (KeyError, ZeroDivisionError):
disk['ratio'] = 0
else:
@@ -480,12 +481,12 @@ def ccache():
disk['oldest'] = value[0]
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
total['entries'] = ram['entries'] + disk['entries']
total['bytes'] = ram['bytes'] + disk['bytes']
total['objects'] = ram['objects'] + disk['objects']
total['hits'] = ram['hits'] + disk['hits']
total['misses'] = ram['misses'] + disk['misses']
total['keys'] = ram['keys'] + disk['keys']
ram_keys = ram.keys() # ['hits', 'objects', 'ratio', 'entries', 'keys', 'oldest', 'bytes', 'misses']
ram_keys.remove('ratio')
ram_keys.remove('oldest')
for key in ram_keys:
total[key] = ram[key] + disk[key]
try:
total['ratio'] = total['hits'] * 100 / (total['hits'] +
total['misses'])
@@ -575,11 +576,9 @@ def bg_graph_model():
meta_graphmodel = dict(group=request.application, color='#ECECEC')
group = meta_graphmodel['group'].replace(' ', '')
if not subgraphs.has_key(group):
if group not in subgraphs:
subgraphs[group] = dict(meta=meta_graphmodel, tables=[])
subgraphs[group]['tables'].append(tablename)
else:
subgraphs[group]['tables'].append(tablename)
subgraphs[group]['tables'].append(tablename)
graph.add_node(tablename, name=tablename, shape='plaintext',
label=table_template(tablename))

View File

@@ -10,7 +10,7 @@ session.forget()
cache_expire = not request.is_local and 300 or 0
@cache.action(time_expire=300, cache_model=cache.ram, quick='P')
# @cache.action(time_expire=300, cache_model=cache.ram, quick='P')
def index():
return response.render()
@@ -19,14 +19,13 @@ def index():
def what():
import urllib
try:
images = XML(urllib.urlopen(
'http://www.web2py.com/poweredby/default/images').read())
images = XML(urllib.urlopen('http://www.web2py.com/poweredby/default/images').read())
except:
images = []
return response.render(images=images)
@cache.action(time_expire=300, cache_model=cache.ram, quick='P')
# @cache.action(time_expire=300, cache_model=cache.ram, quick='P')
def download():
return response.render()
@@ -74,14 +73,15 @@ def license():
filename = os.path.join(request.env.gluon_parent, 'LICENSE')
return response.render(dict(license=MARKMIN(read_file(filename))))
def version():
if request.args(0)=='raw':
if request.args(0) == 'raw':
return request.env.web2py_version
from gluon.fileutils import parse_version
(a, b, c, pre_release, build) = parse_version(request.env.web2py_version)
return 'Version %i.%i.%i (%.4i-%.2i-%.2i %.2i:%.2i:%.2i) %s' % (
a,b,c,build.year,build.month,build.day,
build.hour,build.minute,build.second,pre_release)
return 'Version %i.%i.%i (%.4i-%.2i-%.2i %.2i:%.2i:%.2i) %s' % \
(a, b, c, build.year, build.month, build.day, build.hour, build.minute, build.second, pre_release)
@cache.action(time_expire=300, cache_model=cache.ram, quick='P')
def examples():

View File

@@ -35,12 +35,6 @@ def hello6():
response.flash = 'Hello World in a flash!'
return dict(message=T('Hello World'))
def status():
""" page that shows internal status"""
return dict(toolbar=response.toolbar())
def redirectme():
""" redirects to /{{=request.application}}/{{=request.controller}}/hello3 """

View File

@@ -27,4 +27,4 @@ def xml():
def beautify():
return dict(message=BEAUTIFY(request))
return dict(message=BEAUTIFY(dict(a=1,b=[2,3,dict(hello='world')])))

View File

@@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
response.menu = [
(T('Home'), False, URL('default', 'index')),
(T('About'), False, URL('default', 'what')),
(T('Download'), False, URL('default', 'download')),
(T('Docs & Resources'), False, URL('default', 'documentation')),
(T('Support'), False, URL('default', 'support')),
(T('Contributors'), False, URL('default', 'who'))]
(T('Home'), request.controller == 'default' and request.function == 'index', URL('default', 'index')),
(T('About'), request.controller == 'default' and request.function == 'what', URL('default', 'what')),
(T('Download'), request.controller == 'default' and request.function == 'download', URL('default', 'download')),
(T('Docs & Resources'), request.controller == 'default' and request.function == 'documentation', URL('default', 'documentation')),
(T('Support'), request.controller == 'default' and request.function == 'support', URL('default', 'support')),
(T('Contributors'), request.controller == 'default' and request.function == 'who', URL('default', 'who'))]
#########################################################################
## Changes the menu active item

View File

@@ -1 +1,3 @@
session.connect(request,response,cookie_key='yoursecret')
from gluon.utils import web2py_uuid
cookie_key = cache.ram('cookie_key',lambda: web2py_uuid(),None)
session.connect(request,response,cookie_key=cookie_key)

View File

@@ -8,6 +8,9 @@
#### Learning and Demos
- [[Intro video http://www.youtube.com/watch?v=BXzqmHx6edY]] and [[code examples https://github.com/mjhea0/web2py]]
- [[Step by step tutorial https://milesm.pythonanywhere.com/wiki]]
- [[web2py Reference Project http://www.web2pyref.com/]]
- [[An advanced tutorial https://milesm.pythonanywhere.com/wiki]]
- [[Killer Web Development Tutorial http://killer-web-development.com/]]
- [[Real Python for the Web http://www.realpython.com]] (web development with web2py and more!)
- [[Admin Demo http://www.web2py.com/demo_admin popup]] (web-based IDE)
@@ -17,10 +20,11 @@
#### Code
- [[web2pyslices (recipes) http://www.web2pyslices.com popup]]
- [[Layouts http://www.web2py.com/layouts popup]]
- [[Dashboard welcome app https://github.com/mjbeller/web2py-starter]]
- [[stupid.css theme https://github.com/mdipierro/web2py-welcome-theme-stupid]]
- [[Plugins http://www.web2py.com/plugins popup]]
- [[More Plugins http://dev.s-cubism.com/web2py_plugins]]
- [[Appliances http://www.web2py.com/appliances popup]]
- [[web2py utils http://packages.python.org/web2py_utils/ popup]]
- [[Sublime text 3 plugin https://bitbucket.org/kfog/w2p popup]]
#### [[Sites Powered by web2py http://www.web2py.com/poweredby popup]]

View File

@@ -24,6 +24,10 @@ French speakers group
``web2py-fr``:groupdates
## Italian Group
- [[https://groups.google.com/forum/?fromgroups#!forum/web2py-it https://groups.google.com/forum/?fromgroups#!forum/web2py-it popup]]
## Japanese Group
Japanese speakers group

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,11 @@
.calendar{z-index:99;position:relative;display:none;background:#fff;border:2px solid #000;font-size:11px;color:#000;cursor:default;font-family:Arial,Helvetica,sans-serif;
border-radius: 10px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
}.calendar table{margin:0px;font-size:11px;color:#000;cursor:default;font-family:tahoma,verdana,sans-serif;}.calendar .button{text-align:center;padding:1px;color:#fff;background:#000;}.calendar .nav{background:#000;color:#fff}.calendar thead .title{font-weight:bold;padding:1px;background:#000;color:#fff;text-align:center;}.calendar thead .name{padding:2px;text-align:center;background:#bbb;}.calendar thead .weekend{color:#f00;}.calendar thead .hilite {background-color:#666;}.calendar thead .active{padding:2px 0 0 2px;background-color:#c4c0b8;}.calendar tbody .day{width:2em;text-align:right;padding:2px 4px 2px 2px;}.calendar tbody .day.othermonth{color:#aaa;}.calendar tbody .day.othermonth.oweekend{color:#faa;}.calendar table .wn{padding:2px 3px 2px 2px;background:#bbb;}.calendar tbody .rowhilite td{background:#ddd;}.calendar tbody td.hilite{background:#bbb;}.calendar tbody td.active{background:#bbb;}.calendar tbody td.selected{font-weight:bold;background:#ddd;}.calendar tbody td.weekend{color:#f00;}.calendar tbody td.today{font-weight:bold;color:#00f;}.calendar tbody .disabled{color:#999;}.calendar tbody .emptycell{visibility:hidden;}.calendar tbody .emptyrow{display:none;}.calendar tfoot .ttip{background:#bbb;padding:1px;background:#000;color:#fff;text-align:center;}.calendar tfoot .hilite{background:#ddd;}.calendar tfoot .active{}.calendar .combo{position:absolute;display:none;width:4em;top:0;left:0;cursor:default;background:#e4e0d8;padding:1px;z-index:100;}.calendar .combo .label,.calendar .combo .label-IEfix{text-align:center;padding:1px;}.calendar .combo .label-IEfix{width:4em;}.calendar .combo .active{background:#c4c0b8;}.calendar .combo .hilite{background:#048;color:#fea;}.calendar td.time{padding:1px 0;text-align:center;background-color:#bbb;}.calendar td.time .hour,.calendar td.time .minute,.calendar td.time .ampm{padding:0 3px 0 4px;font-weight:bold;}.calendar td.time .ampm{text-align:center;}.calendar td.time .colon{padding:0 2px 0 3px;font-weight:bold;}.calendar td.time span.hilite{}.calendar td.time span.active{border-color:#f00;background-color:#000;color:#0f0;}.hour,.minute{font-size:2em;}
.calendar {z-index:2000;position:relative;margin-top:140px;display:none;background-color:white;border:1px solid #000;color:#000;cursor:default;box-shadow:0 0 10px #666}.calendar * {text-align: center;font-size:10px!important}
.calendar table {border-collapse:collapse}
.calendar tbody tr:hover {background-color:#fbf6d9}
.calendar td, th {padding:5px; vertical-align:top; text-align:left; border:0}
.calendar thead tr {background-color:#f1f1f1}
.calendar tbody tr {border-bottom:2px solid #f1f1f1}
.calendar th {font-weight:string; padding:5px; vertical-align:bottom; text-align:left}
.calendar thead th {vertical-align:bottom}
.calendar tbody th {vertical-align:top}
#CP_hourcont{z-index:99;padding:0;position:absolute;border:1px dashed #666;background-color:#eee;display:none;}#CP_minutecont{z-index:99;background-color:#ddd;padding:1px;position:absolute;width:45px;display:none;}.floatleft{float:left;}.CP_hour{z-index:99;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:35px;}.CP_minute{z-index:99;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:auto;}.CP_over{background-color:#fff;z-index:99}
#CP_hourcont{z-index:2000;padding:0;position:absolute;border:1px dashed #666;background-color:#eee;display:none;}#CP_minutecont{z-index:2000;background-color:#ddd;padding:1px;position:absolute;width:45px;display:none;}.floatleft{float:left;}.CP_hour{z-index:2000;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:35px;}.CP_minute{z-index:2000;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:auto;}.CP_over{background-color:#fff;z-index:2000}

View File

@@ -1,20 +1,69 @@
@import url(http://fonts.googleapis.com/css?family=Economica);
@@import url(http://fonts.googleapis.com/css?family=Belleza);
body { font-family: Arial, Helvetica; }
a, a:visited, a:hover, h1,h2,h3,h4,h5 {color: #658883}
a.btn-danger, a.btn-warning, a.btn-success {color:white}
h1,h2,h3,h4,h5 { font-family: "Economica", Arial, Helevtica; }
body {
background: url('../images/stripes.png') repeat-x;
}
#header {
margin-top: 40px;
}
.btn-180 {
width: 180px;
}
.page-header {
border-bottom: 0;
}
/* Gray the black as suggested by Anthony */
h1,h2,h3,h4,h5,h6 {color: rgb(35, 35, 35); text-transform:none}
.black {
color: rgb(35, 35, 35);
background-color: rgb(35, 35, 35);
}
/* Spacing between thead and tbody */
/* Ref: http://stackoverflow.com/questions/9258754/spacing-between-thead-and-tbody */
tbody:before {
content: "-";
display: block;
line-height: 1em;
color: transparent;
}
/* Improve buttons in download page */
th, td {padding: 0}
tbody tr:hover {background-color:transparent}
tbody tr {border-bottom: none}
p {text-align: left}
p, li { line-height: 1.6em}
/* Improve CODE() display though padding has no effect as some PRE are hardcoded somewhere can't find it */
/* padding of 10px should make it... */
pre {background-color: rgb(35, 35, 35)!important; border-radius:5px; color:white; padding: 10px}
/* Improve buttons in download page */
a.btn.btn180 {padding:10px; font-size:1.2em; width:200px}
.menu .web2py-menu-active a {
color: #26a69a;
}
.spaced-vertical {
margin: 0 0.5em 0.5em 0;
}
.btn:hover,
a.noeffect img:hover {
transition: scale .5s;
transform: scale(1.05);
}
.btn,
a.noeffect img {
transition: all .2s ease-in-out;
}
/* Lower saturation of color #26a69a - 20 points lower */
/* The below change to color #26a69a should come before other color change or they override all buttons background-color */
/* The color should maybe change at stupid.css level as it herited from there also in stupid.css it would be better
to define this color at one place actually color is defined all over the place */
a {color:#47a69d}
.btn, button, [type=button], [type=submit] {background-color:#47a69d}
.progress .determinate {background-color:#47a69d}
.progress .indeterminate {background-color:#47a69d}
a:not(.btn):not(.noeffect):hover {color:#47a69d}
a:not(.btn):not(.noeffect):after {background-color:#47a69d}
.tags > span {background-color:#47a69d}
.tags.dismissible > span.off:hover {background-color:#47a69d}
.aquamarine{background-color:#47a69d}
/* Lower the saturation of 20 points */
.green {background-color: #58cc65}
.yellow {background-color: #ffe333}
.red {background-color: #cc4229}

View File

@@ -0,0 +1,359 @@
/************
Created by Massimo Di Pierro
Stupid.css is what the names says, take it with a grain of salt
License: BSD
************/
/*** basic styles ***/
html {box-sizing:border-box;}
*, *:after, *:before {border:0; margin:0; padding:0; box-sizing:inherit;}
html, body {max-width: 100vw; overflow-x: hidden}
body {font-family:"HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif}
p, li {margin-bottom:0.5em}
p {text-align:justify}
label, strong {font-weight:bold}
ul {list-style-type:none; padding-left:20px}
a {text-decoration:none; color:#26a69a; white-space:nowrap}
a:hover {cursor:pointer}
h1,h2,h3,h4,h5,h6{font-weight:bold; text-transform:uppercase}
h1{font-size:4em; margin:1.0em 0 0.25em 0}
h2{font-size:2.4em; margin:0.9em 0 0.25em 0}
h3{font-size:1.8em; margin:0.8em 0 0.25em 0}
h4{font-size:1.6em; margin:0.7em 0 0.25em 0}
h5{font-size:1.4em; margin:0.6em 0 0.25em 0}
h6{font-size:1.2em; margin:0.5em 0 0.25em 0}
table {border-collapse:collapse}
tbody tr:hover {background-color:#fbf6d9}
thead tr {background-color:#f1f1f1}
tbody tr {border-bottom:2px solid #f1f1f1}
td, th {padding: 5px; text-align: left; vertical-align:top}
thead th {vertical-align:bottom}
header, main, footer {display:block; with:100%} /* IE fix */
@media all and (max-width:599px) {
h1{font-size:2em}
h2{font-size:1.8em}
h3{font-size:1.6em}
h4{font-size:1.4em}
h5{font-size:1.2em}
h6{font-size:1.0em}
}
/*** buttons ***/
.btn, button, [type=button], [type=submit] {padding:0.5em 1em; margin:0 0.5em 0.5em 0; display:inline-block; background-color:#26a69a; color:white}
.btn:hover, button:hover, [type=button]:hover, [type=submit]:hover {box-shadow:0 0 10px #666; text-decoration:none; cursor:pointer}
.btn.small, table .btn {padding:0.25em 0.5em; font-size:0.8em}
.btn.large {padding:1em 2em; font-size:1.2em}
.btn.oval {border-radius:50%}
/*** helpers ***/
.rounded {-moz-border-radius:5px; border-radius:5px}
.padded {padding:10px 20px}
.center {text-align:center; margin-left:auto; margin-right:auto}
.center>div {text-align:left}
.right {right:0; text-align:right}
.middle div {vertical-align:middle}
.bottom div {vertical-align:bottom}
.xscroll {overflow-x:scroll}
.yscroll {overflow-y:scroll}
.nowrap {white-space:nowrap; overflow-x:hidden}
.fill {width:100%}
.lifted {box-shadow:5px 5px 10px #666}
.relative {position:relative}
.relative>div {position:absolute}
.spaced {margin-bottom:20px; margin-top:20px}
.hidden {display:none}
/*** forms ***/
input:not([type]), input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]), [type=file]:before {outline:none; padding:0.5em 1em; margin:0.5px; border-bottom:1px solid #ddd; width:100%}
textarea {width:100%; border:1px solid #ddd; padding:4px 8px; outline:none; outline:none}
select {-webkit-appearance:none; outline:none; padding:0.5em 1em; border-radius:0; margin:0.5px; border-bottom:1px solid #ddd; width:100%;background-color:transparent}
input, textarea, select, button, .btn {font-size:12px}
input:not([type]):hover, input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]):hover, select:hover, textarea:hover {background-color:#fbf6d9; transition:background-color 1s ease}
input:invalid, input.error {background:#cc1f00;color:white}
/*** grid ***/
.container {margin-right:-20px}
.container>.quarter, .container>.half, .container>.third, .container>.twothirds, .container>.threequarters {display:inline-block; padding: 0 20px 0 0; vertical-align:top}
.container>.fill{display: inline-block}
.container img, .container video {max-width:100%}
@media all and (min-width:800px) {
.max900 {max-width:900px; margin-left:auto; margin-right:auto}
.quarter {width:25%; margin-right:-5px}
.half {width:50%; margin-right:-10px}
.third {width:33.33%; margin-right:-6.66px}
.twothirds {width:66.66%; margin-right:-13.33px}
.threequarters {width:75%; margin-right:-15px}
}
@media all and (min-width:600px) and (max-width:799px) {
.quarter.compressible {width:25%; margin-right:-5px}
.half.compressible {width:50%; margin-right:-10px}
.threequarters.compressible {width:75%; margin-right:-15px}
.quarter:not(.compressible), .half:not(.compressible), .threequarters:not(.compressible) {width:100%; margin-right:-20px}
.third {width:33.33%; margin-right:-6.66px}
.twothirds {width:66.66%; margin-right:-13.33px}
label.quarter:not(.compressible).right, label.half:not(.compressible).right, label.threequarters:not(.compressible).right {float:left; text-align:left}
}
@media all and (max-width:599px) {
.quarter:not(.compressible), .half:not(.compressible), .third:not(.compressible), .twothirds:not(.compressible), .threequarters:not(.compressible) {width:100%;}
label.quarter:not(.compressible).right, label.half:not(.compressible).right, label.threequarters:not(.compressible).right,
label.third:not(.compressible).right, label.twothirds:not(.compressible).right {float:left; text-align:left}
.quarter.compressible {width:25%; margin-right:-5px}
.half.compressible {width:50%; margin-right:-10px}
.third.compressible {width:33.33%; margin-right:-6.66px}
.twothirds.compressible {width:66.66%; margin-right:-13.33px}
.threequarters.compressible {width:75%; margin-right:-15px}
}
/*** progress bar from http://codepen.io/holdencreative/details/pvxGxy ***/
.progress {
margin-left:-15px;
margin-right:-15px;
position:relative;
height:8px;
display:block;
width:120%;
background-color:#acece6;
border-radius:0;
background-clip:padding-box;
overflow:hidden;
}
.progress .determinate {
position:absolute;
background-color:inherit;
top:0;
bottom:0;
background-color:#26a69a;
transition:width .3s linear;
}
.progress .indeterminate {
background-color:#26a69a;
}
.progress .indeterminate:before {
content:'';
position:absolute;
background-color:inherit;
top:0;
left:0;
bottom:0;
will-change:left, right;
animation:indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
}
.progress .indeterminate:after {
content:'';
position:absolute;
background-color:inherit;
top:0;
left:0;
bottom:0;
will-change:left, right;
animation:indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
animation-delay:1.15s;
}
@-webkit-keyframes indeterminate {
0% {left:-35%; right:100%}
60% {left:100%; right:-90%}
100% {left:100%; right:-90%}
}
@-moz-keyframes indeterminate {
0% {left:-35%; right:100%}
60% {left:100%; right:-90%}
100% {left:100%; right:-90%}
}
@keyframes indeterminate {
0% {left:-35%; right:100%}
60% {left:100%; right:-90%}
100% {left:100%; right:-90%}
}
@-webkit-keyframes indeterminate-short {
0% {left:-200%; right:100%}
60% {left:107%; right:-8%}
100% {left:107%; right:-8%}
}
@-moz-keyframes indeterminate-short {
0% {left:-200%; right:100%}
60% {left:107%; right:-8%}
100% {left:107%; right:-8%}
}
@keyframes indeterminate-short {
0% {left:-200%; right:100%}
60% {left:107%; right:-8%}
100% {left:107%; right:-8%}
}
/**** dropdown menu from http://codepen.io/philhoyt/pen/ujHzd ***/
.menu {list-style:none; position:relative; margin:0; padding:0}
.menu.right {float:right}
.menu a {padding:0 15px; text-decoration:none;text-align:left;font-family:"HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; text-align:left}
.menu li {position:relative; float:left; margin:0; padding:0}
.menu ul {background:white; border:1px solid #e1e1e1; visibility:hidden; opacity:0; position:absolute; top:110%; padding:0; z-index:1000; transition:all 0.2s ease-out; list-style-type:none; box-shadow:5px 5px 10px #666}
.menu ul a {padding:10px 15px; color:#333; font-weight:700; font-size:12px; line-height:16px; display: block}
.menu ul li {float:none; width:200px}
.menu ul ul {top:0; left:80%; z-index:1100}
.menu li:hover > ul {visibility:visible; opacity:1}
.menu>li>ul>li:first-child:before{content:''; position:absolute; width:1px; height:1px; border:10px solid transparent; left:50px; top:-20px; margin-left:-10px; border-bottom-color:white}
.menu.dark ul {background:#111111; border:1px solid #111111}
.menu.dark ul a {color:white}
.menu.dark>li>ul>li:first-child:before{border-bottom-color:#111111}
@media all and (max-width:599px) {
header .menu li, header .menu ul {width: 100%}
header .menu.right {float:left; text-align:left}
header .menu ul ul {top:2.5em; left:-1px}
}
@media all and (min-width:600px) {
.ham {display:none!important}
.burger.accordion * {max-height:1000px; overflow:visible}
}
/*** pulsating ring from https://jsfiddle.net/mandynicole/7xrKP/ *******/
.pulse:after {
content:"";
border:3px solid #00e6ac;
-webkit-border-radius:30px;
height:40px;
width:40px;
position:absolute;
margin-left:-20px;
margin-top:-20px;
-webkit-animation:pulsate 1s ease-out;
-webkit-animation-iteration-count:infinite;
opacity:0.0
}
@-webkit-keyframes pulsate {
0% {-webkit-transform:scale(0.1, 0.1); opacity:0.0}
50% {opacity:1.0}
100% {-webkit-transform:scale(1.2, 1.2); opacity:0.0}
}
/**** underline effect ***/
a:not(.btn):not(.noeffect) {position:relative}
a:not(.btn):not(.noeffect):hover {color:#26a69a}
a:not(.btn):not(.noeffect):hover:after {width:100%}
a:not(.btn):not(.noeffect):after {
display:block;
position:absolute;
left:0;
bottom:-1px;
width:0;
height:2px;
background-color:#26a69a;
content:"";
transition:width 0.2s;
}
/**** modal ***/
.modal {
position:fixed;
z-index:9999;
top:0;
bottom:0;
left:0;
right:0;
background-color:rgba(0,0,0,0.8);
padding-top:20vh;
transition:opacity 500ms;
visibility:hidden;
opacity:0;
}
.modal:target {visibility:visible; opacity:1}
.modal div {margin-left:auto; margin-right:auto}
.modal .close:not(.btn) {position:absolute; top:10px; right:10px; font-size:20px}
.modal .close {transition:all 200ms}
/*** tooltips from http://codepen.io/trezy/pen/Khnzy ***/
[data-tooltip] {position:relative}
[data-tooltip]:before, [data-tooltip]:after {display:none; position:absolute; top:0}
[data-tooltip]:hover:after,[data-tooltip]:hover:before {display:block}
[data-tooltip]:hover:before {
border-bottom:.6em solid #111111;
border-bottom:.6em solid #111111;
border-left:7px solid transparent;
border-right:7px solid transparent;
content:"";
left:0;
margin-top:12px;
z-index:2000;
}
[data-tooltip]:hover:after {
z-index:2000;
background-color:rgba(0,0,0,0.8);
border:4px solid rgba(0,0,0,0.8);
border-radius:7px;
color:white;
text-transform:none;
font-size: 12px;
content:attr(data-tooltip);
left:0;
top:2px;
margin-left:-20px;
margin-top:1.5em;
padding:5px 15px;
white-space:pre-wrap;
width:100px;
}
/*** accordion ***/
.accordion>input ~ label:before {content:"▲ "; color:#ddd}
.accordion>input:checked ~ label:before {content:"▼ "; color:#ddd}
.accordion>input {display:none}
.accordion>input:checked ~ *:not(label) {
max-height: 1000px !important;
overflow:visible !important;
-webkit-transition: max-height .3s ease-in;
transition: max-height .3s ease-in;
}
.accordion>*:not(label) {
max-height: 0;
overflow: hidden;
margin: 0;
padding: 0;
-webkit-transition: max-height .3s ease-out;
transition: max-height .3s ease-out;
}
/*** cards from http://codepen.io/edeesims/pen/iGDzk ***/
.card {perspective: 500px; max-width:100%}
.card>div {
position: absolute;
width: 100%;
height: 100%;
box-shadow: 0 0 15px rgba(0,0,0,0.1);
transition: transform 1s;
transform-style: preserve-3d;
}
.card:hover>div {
transform: rotateY( 180deg ) ;
transition: transform 0.5s;
}
.card>div>div {
position: absolute;
height: 100%;
width: 100%;
backface-visibility: hidden;
}
.card>div>div:nth-child(2) {
transform: rotateY( 180deg );
}
/**** tags ****/
.tags > span {
padding: 4px 9px;
white-space: nowrap;
color: white;
background-color: #26a69a;
border-radius: 5px;
font-size:12px;
margin: 2px 5px 2px 0;
display: inline-block;
}
.tags.dismissible > span:hover {opacity: 0.5}
.tags.dismissible > span:not(.off):after {content:" ✕"}
.tags > span.off {background-color: #ccc}
.tags.dismissible > span.off:hover {background-color:#26a69a}
/*** colors from http://clrs.cc/ ***/
.navy{background-color:#001f3f;color:white}.blue{background-color:#0074d9;color:white}.aqua{background-color:#7fdbff;color:#111111}.teal{background-color:#39cccc;color:white}.olive{background-color:#3d9970;color:white}.green{background-color:#2ecc40;color:white}.aquamarine{background-color:#26a69a;color:white}.lime{background-color:#01ff70;color:#111111}.yellow{background-color:#ffdc00;color:#111111}.orange{background-color:#ff851b;color:white}.red{background-color:#cc1f00;color:white}.fuchsia{background-color:#f012be;color:white}.pink{background-color:#ee6e73;color:white}.purple{background-color:#b10dc9;color:white}.maroon{background-color:#85144b;color:white}.white{background-color:#fff;color:#111111;-webkit-box-shadow:inset 0px 0px 0px 1px #ddd;-moz-box-shadow:inset 0px 0px 0px 1px #ddd;box-shadow:inset 0px 0px 0px 1px #ddd}.gray{background-color:#aaa;color:white}.silver{background-color:#f1f1f1;color:#111111}.black{background-color:#111111;color:white}.glass{background:rgba(255,255,255,0.5);color:#111111}

View File

@@ -1,84 +1,17 @@
/** these MUST stay **/
a {text-decoration:none; white-space:nowrap}
a:hover {text-decoration:underline}
a.button {text-decoration:none}
h1,h2,h3,h4,h5,h6 {margin:0.5em 0 0.25em 0; display:block;
font-family:Helvetica}
h1 {font-size:4.00em}
h2 {font-size:3.00em}
h3 {font-size:2.00em}
h4 {font-size:1.50em}
h5 {font-size:1.25em}
h6 {font-size:1.12em}
th,label {font-weight:bold; white-space:nowrap;}
td,th {text-align:left; padding:2px 5px 2px 5px}
th {vertical-align:middle; border-right:1px solid white}
td {vertical-align:top}
form table tr td label {text-align:left}
p,table,ol,ul {padding:0; margin: 0.75em 0}
p {text-align:justify}
ol, ul {list-style-position:outside; margin-left:2em}
li {margin-bottom:0.5em}
span,input,select,textarea,button,label,a {display:inline}
img {border:0}
blockquote,blockquote p,p blockquote {
font-style:italic; margin:0.5em 30px 0.5em 30px; font-size:0.9em}
i,em {font-style:italic}
strong {font-weight:bold}
small {font-size:0.8em}
code {font-family:Courier}
textarea {width:100%}
video {width:400px}
audio {width:200px}
[type="text"], [type="password"], select {
margin-right: 5px; width: 300px;
}
.hidden {display:none;visibility:visible}
header a {color: white; font-size:1.1em}
main {min-height: 70vh}
.form-group {padding-bottom: 10px !important;}
.w2p_hidden {display:none;visibility:visible}
.right {float:right; text-align:right}
.left {float:left; text-align:left}
.center {width:100%; text-align:center; vertical-align:middle}
/** end **/
/* Sticky footer begin */
.main {
padding:20px 0 50px 0;
}
.footer,.push {
height:6em;
padding:1em 0;
clear:both;
}
.footer-content {position:relative; bottom:-4em; width:100%}
.auth_navbar {
white-space:nowrap;
}
/* Sticky footer end */
.footer {
border-top:1px #DEDEDE solid;
}
.header {
/* background:<fill here for header image>; */
}
fieldset {padding:16px; border-top:1px #DEDEDE solid}
fieldset legend {text-transform:uppercase; font-weight:bold; padding:4px 16px 4px 16px; background:#f1f1f1}
/* fix ie problem with menu */
td.w2p_fw {padding-bottom:1px}
td.w2p_fl,td.w2p_fw,td.w2p_fc {vertical-align:top}
td.w2p_fl {text-align:left}
td.w2p_fl, td.w2p_fw {padding-right:7px}
td.w2p_fl,td.w2p_fc {padding-top:4px}
div.w2p_export_menu {margin:5px 0}
div.w2p_export_menu a, div.w2p_wiki_tags a, div.w2p_cloud a {margin-left:5px; padding:2px 5px; background-color:#f1f1f1; border-radius:5px; -moz-border-radius:5px; -webkit-border-radius:5px;}
div.w2p_export_menu {white-space: wrap; margin:5px 0}
div.w2p_export_menu a, div.w2p_wiki_tags a, div.w2p_cloud a {margin-left:5px; padding:2px 5px; background-color:#f1f1f1; border-radius:5px; -moz-border-radius:5px; -webkit-border-radius:5px; font-size:0.7em; color: black}
/* tr#submit_record__row {border-top:1px solid #E5E5E5} */
#submit_record__row td {padding-top:.5em}
@@ -88,54 +21,30 @@ div.w2p_export_menu a, div.w2p_wiki_tags a, div.w2p_cloud a {margin-left:5px; pa
#web2py_user_form td {vertical-align:top}
/*********** web2py specific ***********/
div.flash {
div.w2p_flash {
font-weight:bold;
display:none;
position:fixed;
padding:10px;
top:48px;
right:250px;
min-width:280px;
padding:20px 20px 20px 50px;
width:100%;
opacity:0.95;
margin:0px 0px 10px 10px;
vertical-align:middle;
cursor:pointer;
color:#fff;
background-color:#000;
border:2px solid #fff;
border-radius:8px;
-o-border-radius: 8px;
-moz-border-radius:8px;
-webkit-border-radius:8px;
background-image: -webkit-linear-gradient(top,#222,#000);
background-image: -o-linear-gradient(top,#222,#000);
background-image: -moz-linear-gradient(90deg, #222, #000);
background-image: linear-gradient(top,#222,#000);
background-repeat: repeat-x;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
color:#000;
background-color:#ffdc00;
z-index:2000;
}
div.flash #closeflash{color:inherit; float:right; margin-left:15px;}
div.w2p_flash:before{content:"×";float:right; margin-right:100px; color:black;}
.ie-lte7 div.flash #closeflash
{color:expression(this.parentNode.currentStyle['color']);float:none;position:absolute;right:4px;}
div.flash:hover { opacity:0.25; }
div.w2p_flash:hover { opacity:0.80; }
div.error_wrapper {display:block}
div.error {
width: 298px;
background:red;
border: 2px solid #d00;
color:white;
color:red;
padding:5px;
display:inline-block;
background-image: -webkit-linear-gradient(left,#f00,#fdd);
background-image: -o-linear-gradient(left,#f00,#fdd);
background-image: -moz-linear-gradient(0deg, #f00, #fdd);
background-image: linear-gradient(left,#f00,#fdd);
background-repeat: repeat-y;
}
.topbar {
@@ -190,34 +99,8 @@ div.error {
*/
/* .web2py_table {border:1px solid #ccc} */
.web2py_paginator {}
.web2py_grid {width:100%}
.web2py_grid table {width:100%}
.web2py_grid tbody td {padding:2px 5px 2px 5px; vertical-align: middle;}
.web2py_grid .web2py_form td {vertical-align: top;}
.web2py_grid thead th,.web2py_grid tfoot td {
background-color:#EAEAEA;
padding:10px 5px 10px 5px;
}
.web2py_grid tr.odd {background-color:#F9F9F9}
.web2py_grid tr:hover {background-color:#F5F5F5}
/*
.web2py_breadcrumbs a {
line-height:20px; margin-right:5px; display:inline-block;
padding:3px 5px 3px 5px;
font-family:'lucida grande',tahoma,verdana,arial,sans-serif;
color:#3C3C3D;
text-shadow:1px 1px 0 #FFFFFF;
white-space:nowrap; overflow:visible; cursor:pointer;
background:#ECECEC;
border:1px solid #CACACA;
-webkit-border-radius:2px; -moz-border-radius:2px;
-webkit-background-clip:padding-box; border-radius:2px;
outline:none; position:relative; zoom:1; *display:inline;
}
*/
.web2py_grid td {color: black;}
.web2py_console form {
width: 100%;
@@ -302,11 +185,6 @@ li.w2p_grid_breadcrumb_elem {
.web2py_console input, .web2py_console select,
.web2py_console a { margin: 2px; }
.web2py_htmltable {
width: 100%;
overflow-x: auto;
-ms-overflow-x:scroll;
}
#wiki_page_body {
width: 600px;
@@ -317,6 +195,10 @@ li.w2p_grid_breadcrumb_elem {
/* fix some IE problems */
.ie-lte7 .topbar .container {z-index:2}
.ie-lte8 div.flash{ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0 ); }
.ie-lte8 div.flash:hover {filter:alpha(opacity=25);}
.ie-lte8 div.w2p_flash{ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0 ); }
.ie-lte8 div.w2p_flash:hover {filter:alpha(opacity=25);}
.ie9 #w2p_query_panel {padding-bottom:2px}
.web2py_console .form-control {width: 20%; display: inline;}
.web2py_console #w2p_keywords {width: 50%;}
.web2py_search_actions a, .web2py_console input[type=submit], .web2py_console input[type=button], .web2py_console button { padding: 6px 12px; }

View File

@@ -1,264 +0,0 @@
/*=============================================================
CUSTOM RULES
==============================================================*/
body{height:auto;} /* to avoid vertical scroll bar */
a{}
a:visited{}
a:hover{}
a:focus{}
a:active{}
h1{}
h2{}
h3{}
h4{}
h5{}
h6{}
div.flash.flash-center{left:25%;right:25%;}
div.flash.flash-top,div.flash.flash-top:hover{
position:relative;
display:block;
margin:0;
padding:1em;
top:0;
left:0;
width:100%;
text-align:center;
text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);
color:#865100;
background:#feea9a;
border:1px solid;
border-top:0px;
border-left:0px;
border-right:0px;
border-radius:0;
opacity:1;
}
#header{margin-top:60px;}
.mastheader h1 {
margin-bottom:9px;
font-size:81px;
font-weight:bold;
letter-spacing:-1px;
line-height:1;
font-size:54px;
}
.mastheader small {
font-size:20px;
font-weight:300;
}
/* auth navbar - primitive style */
.auth_navbar,.auth_navbar a{color:inherit;}
.navbar-inner {-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
.ie-lte7 .auth_navbar,.auth_navbar a{color:expression(this.parentNode.currentStyle['color']); /* ie7 doesn't support inherit */}
.auth_navbar a{white-space:nowrap;} /* to avoid the nav split on more lines */
.auth_navbar a:hover{color:white;text-decoration:none;}
ul#navbar>.auth_navbar{
display:inline-block;
padding:5px;
}
/* form errors message box customization */
div.error_wrapper{margin-bottom:9px;}
div.error_wrapper .error{
border-radius: 4px;
-o-border-radius: 4px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
}
/* below rules are only for formstyle = bootstrap
trying to make errors look like bootstrap ones */
div.controls .error_wrapper{
display:inline-block;
margin-bottom:0;
vertical-align:middle;
}
div.controls .error{
min-width:5px;
background:inherit;
color:#B94A48;
border:none;
padding:0;
margin:0;
/*display:inline;*/ /* uncommenting this, the animation effect is lost */
}
div.controls .help-inline{color:#3A87AD;}
div.controls .error_wrapper +.help-inline {margin-left:-99999px;}
div.controls select +.error_wrapper {margin-left:5px;}
.ie-lte7 div.error{color:#fff;}
/* beautify brand */
.navbar {margin-bottom:0}
.navbar-inverse .brand{color:#c6cecc;}
.navbar-inverse .brand b{display:inline-block;margin-top:-1px;}
.navbar-inverse .brand b>span{font-size:22px;color:white}
.navbar-inverse .brand:hover b>span{color:white}
/* beautify web2py link in navbar */
span.highlighted{color:#d8d800;}
.open span.highlighted{color:#ffff00;}
/*=============================================================
OVERRIDING WEB2PY.CSS RULES
==============================================================*/
/* reset to default */
a{white-space:normal;}
li{margin-bottom:0;}
textarea,button{display:block;}
/*reset ul padding */
ul#navbar{padding:0;}
/* label aligned to related input */
td.w2p_fl,td.w2p_fc {padding:0;}
#web2py_user_form td{vertical-align:middle;}
/*=============================================================
OVERRIDING BOOTSTRAP.CSS RULES
==============================================================*/
/* because web2py handles this via js */
textarea { width:90%}
.hidden{visibility:visible;}
/* right folder for bootstrap black images/icons */
[class^="icon-"],[class*=" icon-"]{
background-image:url("../images/glyphicons-halflings.png")
}
/* right folder for bootstrap white images/icons */
.icon-white,
.nav-tabs > .active > a > [class^="icon-"],
.nav-tabs > .active > a > [class*=" icon-"],
.nav-pills > .active > a > [class^="icon-"],
.nav-pills > .active > a > [class*=" icon-"],
.nav-list > .active > a > [class^="icon-"],
.nav-list > .active > a > [class*=" icon-"],
.navbar-inverse .nav > .active > a > [class^="icon-"],
.navbar-inverse .nav > .active > a > [class*=" icon-"],
.dropdown-menu > li > a:hover > [class^="icon-"],
.dropdown-menu > li > a:hover > [class*=" icon-"],
.dropdown-menu > .active > a > [class^="icon-"],
.dropdown-menu > .active > a > [class*=" icon-"] {
background-image:url("../images/glyphicons-halflings-white.png");
}
/* bootstrap has a label as input's wrapper while web2py has a div */
div>input[type="radio"],div>input[type="checkbox"]{margin:0;}
/* bootstrap has button instead of input */
input[type="button"], input[type="submit"]{margin-right:8px;}
/* web2py radio widget adjustment */
.generic-widget input[type='radio'] {margin:-1px 0 0 0; vertical-align: middle;}
.generic-widget input[type='radio'] + label {display:inline-block; margin:0 0 0 6px; vertical-align: middle;}
/*=============================================================
RULES FOR SOLVING CONFLICTS BETWEEN WEB2PY.CSS AND BOOTSTRAP.CSS
==============================================================*/
/*when formstyle=table3cols*/
tr#auth_user_remember__row>td.w2p_fw>div{padding-bottom:8px;}
td.w2p_fw div>label{vertical-align:middle;}
td.w2p_fc {padding-bottom:5px;}
/*when formstyle=divs*/
div#auth_user_remember__row{margin-top:4px;}
div#auth_user_remember__row>.w2p_fl{display:none;}
div#auth_user_remember__row>.w2p_fw{min-height:39px;}
div.w2p_fw,div.w2p_fc{
display:inline-block;
vertical-align:middle;
margin-bottom:0;
}
div.w2p_fc{
padding-left:5px;
margin-top:-8px;
}
/*when formstyle=ul*/
form>ul{
list-style:none;
margin:0;
}
li#auth_user_remember__row{margin-top:4px;}
li#auth_user_remember__row>.w2p_fl{display:none;}
li#auth_user_remember__row>.w2p_fw{min-height:39px;}
/*when formstyle=bootstrap*/
#auth_user_remember__row label.checkbox{display:block;}
span.inline-help{display:inline-block;}
input[type="text"].input-xlarge,input[type="password"].input-xlarge{width:270px;}
/*when recaptcha is used*/
#recaptcha{min-height:30px;display:inline-block;margin-bottom:0;line-height:30px;vertical-align:middle;}
td>#recaptcha{margin-bottom:6px;}
div>#recaptcha{margin-bottom:9px;}
div.control-group.error{
width:auto;
background:transparent;
border:0;
color:inherit;
padding:0;
background-repeat:repeat;
}
/*=============================================================
OTHER RULES
==============================================================*/
/* Massimo Di Pierro fixed alignment in forms with list:string */
form table tr{margin-bottom:9px;}
td.w2p_fw ul{margin-left:0px;}
/* web2py_console in grid and smartgrid */
.hidden{visibility:visible;}
.web2py_console input{
display: inline-block;
margin-bottom: 0;
vertical-align: middle;
}
.web2py_console input[type="submit"],
.web2py_console input[type="button"],
.web2py_console button{
padding-top:4px;
padding-bottom:4px;
margin:3px 0 0 2px;
}
.web2py_console a,
.web2py_console select,
.web2py_console input
{
margin:3px 0 0 2px;
}
.web2py_grid form table{width:auto;}
/* auth_user_remember checkbox extrapadding in IE fix */
.ie-lte9 input#auth_user_remember.checkbox {padding-left:0;}
div.controls .error {
width: auto;
}
/*=============================================================
MEDIA QUERIES
==============================================================*/
@media only screen and (max-width:979px){
body{padding-top:0px;}
#navbar{/*top:5px;*/}
div.flash{right:5px;}
.dropdown-menu ul{visibility:visible;}
}
@media only screen and (max-width:479px){
body{
padding-left:10px;
padding-right:10px;
}
.navbar-fixed-top,.navbar-fixed-bottom {
margin-left:-10px;
margin-right:-10px;
}
input[type="text"],input[type="password"],select{
width:95%;
}
}
@media (max-width: 767px) {
.navbar {
margin-right: -20px;
margin-left: -20px;
}
}

View File

@@ -1,122 +0,0 @@
/*=============================================================
BOOTSTRAP DROPDOWN MENU
==============================================================*/
.dropdown-menu ul{
left:100%;
position:absolute;
top:0;
visibility:hidden;
margin-top:-1px;
}
.dropdown-menu li:hover ul{visibility:visible;}
.navbar .dropdown-menu ul:before{
border-bottom:7px solid transparent;
border-left:none;
border-right:7px solid rgba(0, 0, 0, 0.2);
border-top:7px solid transparent;
left:-7px;
top:5px;
}
.nav > li.dropdown > a:after {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid #000000;
content: "";
display: inline-block;
height: 0;
opacity: 0.7;
vertical-align: top;
width: 0;
margin-left: 2px;
margin-top: 8px;
border-bottom-color: #FFFFFF;
border-top-color: #FFFFFF;
}
.dropdown-menu span{display:inline-block;}
ul.dropdown-menu li.dropdown > a:after {
border-left: 4px solid #000;
border-right: 4px solid transparent;
border-bottom: 4px solid transparent;
border-top: 4px solid transparent;
content: "";
display: inline-block;
height: 0;
opacity: 0.7;
vertical-align: top;
width: 0;
margin-left: 8px;
margin-top: 6px;
}
ul.nav li.dropdown:hover ul.dropdown-menu {
display: block;
}
.open >.dropdown-menu ul{display:block;} /* fix menu issue when BS2.0.4 is applied */
/*=============================================================
BOOTSTRAP SUBMIT BUTTON
==============================================================*/
input[type='submit']:not(.btn) {
display: inline-block;
padding: 4px 14px;
margin-bottom: 0;
font-size: 14px;
line-height: 20px;
color: #333;
text-align: center;
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
vertical-align: middle;
cursor: pointer;
background-color: whiteSmoke;
background-image: -webkit-gradient(linear,0 0,0 100%,from(white),to(#E6E6E6));
background-image: -webkit-linear-gradient(top,white,#E6E6E6);
background-image: -o-linear-gradient(top,white,#E6E6E6);
background-image: linear-gradient(to bottom,white,#E6E6E6);
background-image: -moz-linear-gradient(top,white,#E6E6E6);
background-repeat: repeat-x;
border: 1px solid #BBB;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
border-bottom-color: #A2A2A2;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);
filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
}
input[type='submit']:not(.btn):hover {
color: #333;
text-decoration: none;
background-color: #E6E6E6;
background-position: 0 -15px;
-webkit-transition: background-position .1s linear;
-moz-transition: background-position .1s linear;
-o-transition: background-position .1s linear;
transition: background-position .1s linear;
}
input[type='submit']:not(.btn).active, input[type='submit']:not(.btn):active {
background-color: #E6E6E6;
background-color: #D9D9D9 9;
background-image: none;
outline: 0;
-webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
-moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
}
/*=============================================================
OTHER
==============================================================*/
.ie-lte8 .navbar-fixed-top {position:static;}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,33 +0,0 @@
// this code improves bootstrap menus and adds dropdown support
jQuery(function(){
jQuery('.nav>li>a').each(function(){
if(jQuery(this).parent().find('ul').length)
jQuery(this).attr({'class':'dropdown-toggle','data-toggle':'dropdown'}).append('<b class="caret"></b>');
});
jQuery('.nav li li').each(function(){
if(jQuery(this).find('ul').length)
jQuery(this).addClass('dropdown-submenu');
});
function adjust_height_of_collapsed_nav() {
var cn = jQuery('div.collapse');
if (cn.get(0)) {
var cnh = cn.get(0).style.height;
if (cnh>'0px'){
cn.css('height','auto');
}
}
}
function hoverMenu(){
jQuery('ul.nav a.dropdown-toggle').parent().hover(function(){
adjust_height_of_collapsed_nav();
var mi = jQuery(this).addClass('open');
mi.children('.dropdown-menu').stop(true, true).delay(200).fadeIn(400);
}, function(){
var mi = jQuery(this);
mi.children('.dropdown-menu').stop(true, true).delay(200).fadeOut(function(){mi.removeClass('open')});
});
}
hoverMenu(); // first page load
jQuery(window).resize(hoverMenu); // on resize event
jQuery('ul.nav li.dropdown a').click(function(){window.location=jQuery(this).attr('href');});
});

View File

@@ -18,7 +18,7 @@
</ul>
<div class="tab-content">
<div class="tab-pane active" id="alltables">
<table>
<table class="table">
{{for db in sorted(databases):}}
{{for table in databases[db].tables:}}
{{qry='%s.%s.id>0'%(db,table)}}
@@ -40,7 +40,7 @@
{{=A("%s.%s" % (db,table),_href=URL('select',args=[db],vars=dict(query=qry)))}}
</th>
<td>
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn")}}
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn btn-default")}}
</td>
</tr>
{{pass}}
@@ -61,7 +61,7 @@
</pre>
{{pass}}
{{if table:}}
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/>
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn btn-default")}}<br/><br/>
<h3>{{=T("Rows in Table")}}</h3><br/>
{{else:}}
<h3>{{=T("Rows selected")}}</h3><br/>
@@ -72,8 +72,8 @@
{{=T('"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN')}}</p>
<br/><br/>
<h4>{{=T("%s selected", nrows)}}</h4>
{{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn")}}{{pass}}
{{if stop<nrows:}}{{=A(T('next %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start+step)),_class="btn")}}{{pass}}
{{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn btn-default")}}{{pass}}
{{if stop<nrows:}}{{=A(T('next %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start+step)),_class="btn btn-default")}}{{pass}}
{{if rows:}}
<div style="overflow:auto; width:80%;">
{{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}}
@@ -82,7 +82,7 @@
</div>
{{pass}}
<br/><br/><h3>{{=T("Import/Export")}}</h3><br/>
<a href="{{=URL('csv',args=request.args[0],vars=dict(query=query))}}" class="btn">{{=T("export as csv file")}}</a>
<a href="{{=URL('csv',args=request.args[0],vars=dict(query=query))}}" class="btn btn-default">{{=T("export as csv file")}}</a>
{{=formcsv or ''}}
{{elif request.function=='insert':}}
@@ -137,9 +137,9 @@
<h4>{{=T("Overview")}}</h4>
<p>{{=T.M("Number of entries: **%s**", total['entries'])}}</p>
{{if total['entries'] > 0:}}
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses})",
dict(ratio=total['ratio'], hits=total['hits'], misses=total['misses']))}}
</p>
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})",
dict( ratio=total['ratio'], hits=total['hits'], misses=total['misses']))}}
</p>
<p>
{{=T("Size of cache:")}}
{{if object_stats:}}
@@ -155,8 +155,8 @@
{{=T.M("Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
dict(hours=total['oldest'][0], min=total['oldest'][1], sec=total['oldest'][2]))}}
</p>
{{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle();')}}
<div class="hidden" id="all_keys">
{{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle().toggleClass( "w2p_hidden" );')}}
<div class="w2p_hidden" id="all_keys">
{{=total['keys']}}
</div>
<br />
@@ -183,8 +183,8 @@
{{=T.M("RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
dict(hours=ram['oldest'][0], min=ram['oldest'][1], sec=ram['oldest'][2]))}}
</p>
{{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle();')}}
<div class="hidden" id="ram_keys">
{{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle().toggleClass( "w2p_hidden" );')}}
<div class="w2p_hidden" id="ram_keys">
{{=ram['keys']}}
</div>
<br />
@@ -212,8 +212,8 @@
{{=T.M("DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
dict(hours=disk['oldest'][0], min=disk['oldest'][1], sec=disk['oldest'][2]))}}
</p>
{{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle();')}}
<div class="hidden" id="disk_keys">
{{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle().toggleClass( "w2p_hidden" );')}}
<div class="w2p_hidden" id="disk_keys">
{{=disk['keys']}}
</div>
<br />
@@ -249,8 +249,8 @@
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['png'])}}">png</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['svg'])}}">svg</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['pdf'])}}">pdf</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['ps'])}}">ps</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['dot'])}}">dot</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['ps'])}}">ps</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['dot'])}}">dot</a></li>
</ul>
</div>
<br />

View File

@@ -1,14 +1,13 @@
{{extend 'layout.html'}}
<iframe src="//player.vimeo.com/hubnut/album/3016728?color=ff6600&amp;background=ffffff&amp;slideshow=1&amp;video_title=1&amp;video_byline=1" width="400" height="300" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
<div class="contentleft">
<div >
{{=get_content('main')}}
</div>
{{=get_content('official')}}
{{=get_content('community')}}
{{=get_content('more')}}
<div>
{{=get_content('main')}}
<center>
<iframe src="//player.vimeo.com/hubnut/album/3016728?color=ff6600&amp;background=ffffff&amp;slideshow=1&amp;video_title=1&amp;video_byline=1" width="400" height="300" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
</center>
{{=get_content('official')}}
{{=get_content('community')}}
{{=get_content('more')}}
</div>

View File

@@ -5,47 +5,73 @@
<h2>web2py<sup style="font-size:0.5em;">TM</sup> Download</h2>
<center style="padding:20px">
<table class="downloads">
<tr>
<th>For Normal Users</th>
<th>For Testers</th>
<th>For Developers</th>
</tr>
<tr>
<td><a class="btn btn-180 btn-success" href="http://www.web2py.com/examples/static/web2py_win.zip">For Windows</a></td>
<td><a class="btn btn-180 btn-warning" href="http://www.web2py.com/examples/static/nightly/web2py_win.zip">For Windows</a></td>
<td><a class="btn btn-180 btn-danger" href="http://github.com/web2py/web2py/">Git Repository</a></td>
</tr>
<tr>
<td><a class="btn btn-180 btn-success" href="http://www.web2py.com/examples/static/web2py_osx.zip">For Mac</a></td>
<td><a class="btn btn-180 btn-warning" href="http://www.web2py.com/examples/static/nightly/web2py_osx.zip">For Mac</a></td>
<td></td>
</tr>
<tr>
<td><a class="btn btn-180 btn-success" href="http://www.web2py.com/examples/static/web2py_src.zip">Source Code</a></td>
<td><a class="btn btn-180 btn-warning" href="http://www.web2py.com/examples/static/nightly/web2py_src.zip">Source Code</a></td>
<td><a class="btn btn-180 btn-danger" href="http://web2py.readthedocs.org/en/latest/">Source code docs</a></td>
</tr>
<tr>
<td><a class="btn btn-180 btn-success" href="https://dl.dropbox.com/u/18065445/web2py/web2py_manual_5th.pdf">Manual</a></td>
<td><a class="btn btn-180" href="https://github.com/web2py/web2py/releases">Change Log</a></td>
<td><a class="btn btn-180" href="https://github.com/web2py/web2py/issues">Report a Bug</a></td>
</tr>
<center class="spaced">
<table class="twothirds">
<thead>
<tr>
<th>For Normal Users</th>
<th>For Testers</th>
<th>For Developers</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<a class="btn btn180 rounded green" href="http://www.web2py.com/examples/static/web2py_win.zip">For Windows</a>
</td>
<td>
<a class="btn btn180 rounded yellow" href="http://www.web2py.com/examples/static/nightly/web2py_win.zip">For Windows</a>
</td>
<td>
<a class="btn btn180 rounded red" href="http://github.com/web2py/web2py/">Git Repository</a>
</td>
</tr>
<tr>
<td>
<a class="btn btn180 rounded green" href="http://www.web2py.com/examples/static/web2py_osx.zip">For Mac</a>
</td>
<td>
<a class="btn btn180 rounded yellow" href="http://www.web2py.com/examples/static/nightly/web2py_osx.zip">For Mac</a>
</td>
<td></td>
</tr>
<tr>
<td>
<a class="btn btn180 rounded green" href="http://www.web2py.com/examples/static/web2py_src.zip">Source Code</a>
</td>
<td>
<a class="btn btn180 rounded yellow" href="http://www.web2py.com/examples/static/nightly/web2py_src.zip">Source Code</a>
</td>
<td>
<a class="btn btn180 rounded red" href="http://web2py.readthedocs.org/en/latest/">Source code docs</a>
</td>
</tr>
<tr>
<td>
<a class="btn btn180 rounded green" href="https://dl.dropbox.com/u/18065445/web2py/web2py_manual_5th.pdf">Manual</a>
</td>
<td>
<a class="btn btn180 rounded" href="https://github.com/web2py/web2py/releases">Change Log</a>
</td>
<td>
<a class="btn btn180 rounded" href="https://github.com/web2py/web2py/issues">Report a Bug</a>
</td>
</tr>
</tbody>
</table>
</center>
<p style="text-align:left;">
The source code version works on all supported platforms, including Linux, but it requires Python 2.5, 2.6, or 2.7.
The source code version works on all supported platforms, including Linux, but it requires Python 2.6, or 2.7 (recommended).
It runs on Windows and most Unix systems, including <b>Linux</b> and <b>BSD</b>.
</p>
<h3>Instructions</h3>
<p>After download, unzip it and click on web2py.exe (windows) or web2py.app (osx).
To run from source, type:</p>
{{=CODE("python2.7 web2py.py",language=None,counter='>',_class='boxCode')}}
{{=CODE("python2.7 web2py.py", language=None, counter='>', _class='boxCode')}}
<p>or for more info type:</p>
{{=CODE("python2.7 web2py.py -h",language=None,counter='>',_class='boxCode')}}
{{=CODE("python2.7 web2py.py -h", language=None, counter='>', _class='boxCode')}}
<h3>Caveats</h3>
@@ -58,7 +84,7 @@
<p>Applications built with web2py can be released under any license the author wishes as long they do not contain web2py code. They can link unmodified web2py libraries and they can be distributed with official web2py binaries. In particular web2py applications can be distributed in closed source. The admin interface provides a button to byte-code compile.</p>
<p>It is fine to distribute web2py (source or compiled) with your applications as long as you make it clear in the license where your application ends and web2py starts.</p>
<p>web2py is copyrighted by Massimo Di Pierro. The web2py trademark is owned by Massimo Di Pierro.</p>
<a class="btn btn-small" href="{{=URL('license')}}">read more</a>
<a class="btn btn-small rounded" href="{{=URL('license')}}">read more</a>
<h3>Artwork</h3>
<center>

View File

@@ -32,7 +32,7 @@ def hello1():
return "Hello World"
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>If the controller function returns a string, that is the body of the rendered page.<br/>Try it here: <a href="/{{=request.application}}/simple_examples/hello1">hello1</a></p>
<p>If the controller function returns a string, that is the body of the rendered page.<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/hello1">hello1</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
{{=CODE("""
@@ -40,7 +40,7 @@ def hello2():
return T("Hello World")
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>The function T() marks strings that need to be translated. Translation dictionaries can be created at /admin/default/design<br/>Try it here: <a href="/{{=request.application}}/simple_examples/hello2">hello2</a></p>
<p>The function T() marks strings that need to be translated. Translation dictionaries can be created at /admin/default/design<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/hello2">hello2</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
{{=CODE("""
@@ -51,7 +51,7 @@ def hello3():
<b>and view: simple_examples/hello3.html</b>
{{=CODE(open(os.path.join(request.folder,'views/simple_examples/hello3.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>If you return a dictionary, the variables defined in the dictionery are visible to the view (template).
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/hello3.html">hello3</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/hello3.html">hello3</a></p>
<p>Actions can also be be rendered in other formsts like JSON, <a href="/{{=request.application}}/simple_examples/hello3.json">hello3.json</a>, and XML, <a href="/{{=request.application}}/simple_examples/hello3.xml">hello3.xml</a></p>
@@ -62,7 +62,7 @@ def hello4():
return dict(message=T("Hello World"))
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>You can change the view, but the default is /[controller]/[function].html. If the default is not found web2py tries to render the page using the generic.html view.
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/hello4">hello4</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/hello4">hello4</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
{{=CODE("""
@@ -76,7 +76,7 @@ def hello5():
<li>named arguments and name starts with '_'. These are mapped blindly into tag attributes and the '_' is removed. attributes without value like "READONLY" can be created with the argument "_readonly=ON".</li>
<li>named arguments and name does not start with '_'. They have a special meaning. See "value=" for INPUT, TEXTAREA, SELECT tags later.
</ul>
<p>Try it here: <a href="/{{=request.application}}/simple_examples/hello5">hello5</a></p>
<p>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/hello5">hello5</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
{{=CODE("""
@@ -86,7 +86,7 @@ def hello6():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>response.flash allows you to flash a message to the user when the page is returned. Use session.flash instead of response.flash to display a message after redirection. With default layout, you can click on the flash to make it disappear.
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/hello6">hello6</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/hello6">hello6</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
{{=CODE("""
@@ -94,7 +94,6 @@ def status():
return dict(toobar=response.toolbar())
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>Here we are showing the request, session and response objects using the generic.html template.
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/status">status</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
{{=CODE("""
@@ -102,7 +101,7 @@ def redirectme():
redirect(URL('hello3'))
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>You can do redirect.
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/redirectme">redirectme</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/redirectme">redirectme</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
{{=CODE("""
@@ -110,7 +109,7 @@ def raisehttp():
raise HTTP(400,"internal error")
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>You can raise HTTP exceptions to return an error page.
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/raisehttp">raisehttp</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/raisehttp">raisehttp</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
{{=CODE("""
@@ -128,7 +127,7 @@ def servejs():
return 'alert("This is a Javascript document, it is not supposed to run!");'
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>You can serve other than HTML pages by changing the contenttype via the response.headers. The gluon.contenttype module can help you figure the type of the file to be served. NOTICE: this is not necessary for static files unless you want to require authorization.
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/servejs">servejs</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/servejs">servejs</a></p>
<h3 id="example_json">Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
{{=CODE("""
@@ -136,7 +135,7 @@ def servejs():
return response.json(['foo', {'bar': ('baz', None, 1.0, 2)}])
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>If you are into Ajax, web2py includes gluon.contrib.<a href="http://cheeseshop.python.org/pypi/simplejson">simplejson</a>, developed by Bob Ippolito. This module provides a fast and easy way to serve asynchronous content to your Ajax page. gluon.simplesjson.dumps(...) can serialize most Python types into <a href="http://www.json.org">JSON</a>. gluon.contrib.simplejson.loads(...) performs the reverse operation.
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/makejson">makejson</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/makejson">makejson</a></p>
<p>New in web2py 1.63: Any normal action returning a dict is automatically serialized in JSON if '.json' is appended to the URL.</p>
@@ -152,7 +151,7 @@ def makertf():
response.headers['Content-Type']='text/rtf'
return q.dumps(doc)
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>web2py also includes gluon.contrib.<a href="http://pyrtf.sourceforge.net/">pyrtf</a>, developed by Simon Cusack and revised by Grant Edwards. This module allows you to generate Rich Text Format documents including colored formatted text and pictures.<br/>Try it here: <a href="/{{=request.application}}/simple_examples/makertf">makertf</a></p>
<p>web2py also includes gluon.contrib.<a href="http://pyrtf.sourceforge.net/">pyrtf</a>, developed by Simon Cusack and revised by Grant Edwards. This module allows you to generate Rich Text Format documents including colored formatted text and pictures.<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/makertf">makertf</a></p>
<h3 id="example_rss">Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
{{=CODE("""
@@ -179,7 +178,7 @@ def rss_aggregator():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>web2py includes gluon.contrib.<a href="http://www.dalkescientific.com/Python/PyRSS2Gen.html">rss2</a>, developed by Dalke Scientific Software, which generates RSS2 feeds, and
gluon.contrib.<a href="http://www.feedparser.org/">feedparser</a>, developed by Mark Pilgrim, which collects RSS and ATOM feeds. The above controller collects a slashdot feed and makes new one.
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/rss_aggregator">rss_aggregator</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/rss_aggregator">rss_aggregator</a></p>
<h3 id="example_wiki">Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
@@ -194,7 +193,7 @@ def ajaxwiki_onclick():
return MARKMIN(request.vars.text).xml()
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>The markmin wiki markup is described <a href="{{=URL('static','markmin.html')}}">here</a>.
web2py also includes gluon.contrib.<a href="http://code.google.com/p/python-markdown2/">markdown</a>.WIKI helper (markdown2) which converts WIKI markup to HTML following <a href="http://en.wikipedia.org/wiki/Markdown">this syntax</a>. In this example we added a fancy ajax effect.<br/>Try it here: <a href="/{{=request.application}}/simple_examples/ajaxwiki">ajaxwiki</a></p>
web2py also includes gluon.contrib.<a href="http://code.google.com/p/python-markdown2/">markdown</a>.WIKI helper (markdown2) which converts WIKI markup to HTML following <a href="http://en.wikipedia.org/wiki/Markdown">this syntax</a>. In this example we added a fancy ajax effect.<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/ajaxwiki">ajaxwiki</a></p>
<h2 id="session_examples">Session Examples</h2>
@@ -207,7 +206,7 @@ def counter():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: session_examples/counter.html</b>
{{=CODE(open(os.path.join(request.folder,'views/session_examples/counter.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>Click to count. The session.counter is persistent for this user and application. Every applicaiton within the system has its own separate session management.
<br/>Try it here: <a href="/{{=request.application}}/session_examples/counter">counter</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/session_examples/counter">counter</a></p>
<h2 id="template_examples">Template Examples</h2>
@@ -219,7 +218,7 @@ def variables():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/variables.html</b>
{{=CODE(open(os.path.join(request.folder,'views/template_examples/variables.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>A view (also known as template) is just an HTML file with &#123;&#123;...&#125;&#125; tags. You can put ANY python code into the tags, no need to indent but you must use pass to close blocks. The view is transformed into a python code and then executed. &#123;&#123;=a&#125;&#125; prints a.xml() or escape(str(a)).
<br/>Try it here: <a href="/{{=request.application}}/template_examples/variables">variables</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/variables">variables</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
{{=CODE("""
@@ -228,7 +227,7 @@ def test_for():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/test_for.html</b>
{{=CODE(open(os.path.join(request.folder,'views/template_examples/test_for.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>You can do for and while loops.
<br/>Try it here: <a href="/{{=request.application}}/template_examples/test_for">test_for</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/test_for">test_for</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
{{=CODE("""
@@ -237,7 +236,7 @@ def test_if():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/test_if.html</b>
{{=CODE(open(os.path.join(request.folder,'views/template_examples/test_if.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>You can do if, elif, else.
<br/>Try it here: <a href="/{{=request.application}}/template_examples/test_if">test_if</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/test_if">test_if</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
{{=CODE("""
@@ -246,7 +245,7 @@ def test_try():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/test_try.html</b>
{{=CODE(open(os.path.join(request.folder,'views/template_examples/test_try.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>You can do try, except, finally.
<br/>Try it here: <a href="/{{=request.application}}/template_examples/test_try">test_try</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/test_try">test_try</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
{{=CODE("""
@@ -255,7 +254,7 @@ def test_def():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/test_def.html</b>
{{=CODE(open(os.path.join(request.folder,'views/template_examples/test_def.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>You can write functions in HTML too.
<br/>Try it here: <a href="/{{=request.application}}/template_examples/test_def">test_def</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/test_def">test_def</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
{{=CODE("""
@@ -264,7 +263,7 @@ def escape():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/escape.html</b>
{{=CODE(open(os.path.join(request.folder,'views/template_examples/escape.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>The argument of &#123;&#123;=...&#125;&#125; is always escaped unless it is an object with a .xml() method such as link, A(...), a FORM(...), a XML(...) block, etc.
<br/>Try it here: <a href="/{{=request.application}}/template_examples/escape">escape</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/escape">escape</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
{{=CODE("""
@@ -273,16 +272,16 @@ def xml():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/xml.html</b>
{{=CODE(open(os.path.join(request.folder,'views/template_examples/xml.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>If you do not want to escape the argument of &#123;&#123;=...&#125;&#125; mark it as XML.
<br/>Try it here: <a href="/{{=request.application}}/template_examples/xml">xml</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/xml">xml</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
{{=CODE("""
def beautify():
return dict(message=BEAUTIFY(request))
dict(message=BEAUTIFY(dict(a=1,b=[2,3,dict(hello='world')])))
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/beautify.html</b>
{{=CODE(open(os.path.join(request.folder,'views/template_examples/beautify.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>You can use BEAUTIFY to turn lists and dictionaries into organized HTML.
<br/>Try it here: <a href="/{{=request.application}}/template_examples/beautify">beautify</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/beautify">beautify</a></p>
<h2 id="layout_examples">Layout Examples</h2>
@@ -298,7 +297,7 @@ def civilized():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: layout_examples/civilized.html</b>
{{=CODE(open(os.path.join(request.folder,'views/layout_examples/civilized.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>You can specify the layout file at the top of your view. civilized Layout file is a view that somewhere in the body contains &#123;&#123;include&#125;&#125;.
<br/>Try it here: <a href="/{{=request.application}}/layout_examples/civilized">civilized</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/layout_examples/civilized">civilized</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: layout_examples.py </b>
{{=CODE("""
@@ -310,7 +309,7 @@ def slick():
return dict(message="you clicked on slick")
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: layout_examples/slick.html</b>
{{=CODE(open(os.path.join(request.folder,'views/layout_examples/slick.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>Same here, but using a different template.<br/>Try it here: <a href="/{{=request.application}}/layout_examples/slick">slick</a></p>
<p>Same here, but using a different template.<br/>Try it here: <a class="btn" href="/{{=request.application}}/layout_examples/slick">slick</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: layout_examples.py </b>
{{=CODE("""
@@ -323,7 +322,7 @@ def basic():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: layout_examples/basic.html</b>
{{=CODE(open(os.path.join(request.folder,'views/layout_examples/basic.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>'layout.html' is the default template, every application has a copy of it.
<br/>Try it here: <a href="/{{=request.application}}/layout_examples/basic">basic</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/layout_examples/basic">basic</a></p>
<h2 id="form_examples">Form Examples</h2>
@@ -347,7 +346,7 @@ def form():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>You can use HTML helpers like FORM, INPUT, TEXTAREA, OPTION, SELECT to build forms. The "value=" attribute sets the initial value of the field (works for TEXTAREA and OPTION/SELECT too) and the requires attribute sets the validators.
FORM.accepts(..) tries to validate the form and, on success, stores vars into form.vars. On failure the error messages are stored into form.errors and shown in the form.
<br/>Try it here: <a href="/{{=request.application}}/form_examples/form">form</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/form_examples/form">form</a></p>
<h2 id="database_examples">Database Examples</h2>
@@ -497,7 +496,7 @@ def cache_in_ram():
return dict(time=t,link=A('click to reload',_href=URL(r=request)))
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>The output of <tt>lambda:time.ctime()</tt> is cached in ram for 5 seconds. The string 'time' is used as cache key.
<br/>Try it here: <a href="/{{=request.application}}/cache_examples/cache_in_ram">cache_in_ram</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/cache_examples/cache_in_ram">cache_in_ram</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
@@ -508,7 +507,7 @@ def cache_on_disk():
return dict(time=t,link=A('click to reload',_href=URL(r=request)))
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>The output of <tt>lambda:time.ctime()</tt> is cached on disk (using the shelve module) for 5 seconds.
<br/>Try it here: <a href="/{{=request.application}}/cache_examples/cache_on_disk">cache_on_disk</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/cache_examples/cache_on_disk">cache_on_disk</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
{{=CODE("""
@@ -519,7 +518,7 @@ def cache_in_ram_and_disk():
return dict(time=t,link=A('click to reload',_href=URL(r=request)))
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>The output of <tt>lambda:time.ctime()</tt> is cached on disk (using the shelve module) and then in ram for 5 seconds. web2py looks in ram first and if not there it looks on disk. If it is not on disk it calls the function. This is useful in a multiprocess type of environment. The two times do not have to be the same.
<br/>Try it here: <a href="/{{=request.application}}/cache_examples/cache_in_ram_and_disk">cache_in_ram_and_disk</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/cache_examples/cache_in_ram_and_disk">cache_in_ram_and_disk</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
@@ -530,7 +529,7 @@ def cache_in_ram_and_disk():
t=time.ctime()
return dict(time=t,link=A('click to reload',_href=URL(r=request)))""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>Here the entire controller (dictionary) is cached in ram for 5 seconds. The result of a select cannot be cached unless it is first serialized into a table <tt>lambda:SQLTABLE(db().select(db.user.ALL)).xml()</tt>. You can read below for an even better way to do it.
<br/>Try it here: <a href="/{{=request.application}}/cache_examples/cache_controller_in_ram">cache_controller_in_ram</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/cache_examples/cache_controller_in_ram">cache_controller_in_ram</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
{{=CODE("""
@@ -541,7 +540,7 @@ def cache_controller_on_disk():
return dict(time=t,link=A('click to reload',_href=URL(r=request)))
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>Here the entire controller (dictionary) is cached on disk for 5 seconds. This will not work if the dictionary contains unpickleable objects.
<br/>Try it here: <a href="/{{=request.application}}/cache_examples/cache_controller_on_disk">cache_controller_on_disk</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/cache_examples/cache_controller_on_disk">cache_controller_on_disk</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
{{=CODE("""
@@ -553,7 +552,7 @@ def cache_controller_and_view():
return response.render(d)
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p><tt>response.render(d)</tt> renders the dictionary inside the controller, so everything is cached now for 5 seconds. This is best and fastest way of caching!
<br/>Try it here: <a href="/{{=request.application}}/cache_examples/cache_controller_and_view">cache_controller_and_view</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/cache_examples/cache_controller_and_view">cache_controller_and_view</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
{{=CODE("""
@@ -583,7 +582,7 @@ def data():
<b>In view: ajax_examples/index.html</b>
{{=CODE(open(os.path.join(request.folder,'views/ajax_examples/index.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>The javascript function "ajax" is provided in "web2py_ajax.html" and included by "layout.html". It takes three arguments, a url, a list of ids and a target id. When called, it sends to the url (via a get) the values of the ids and display the response in the value (of innerHTML) of the target id.
<br/>Try it here: <a href="/{{=request.application}}/ajax_examples/index">index</a></p>
<br/>Try it here: <a class="btn" href="/{{=request.application}}/ajax_examples/index">index</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: ajax_examples.py </b>
{{=CODE("""
@@ -591,7 +590,7 @@ def flash():
response.flash='this text should appear!'
return dict()
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<p>Try it here: <a href="/{{=request.application}}/ajax_examples/flash">flash</a></p>
<p>Try it here: <a class="btn" href="/{{=request.application}}/ajax_examples/flash">flash</a></p>
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: ajax_examples.py </b>
{{=CODE("""
@@ -600,7 +599,7 @@ def fade():
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
<b>In view: ajax_examples/fade.html </b><br/>
{{=CODE(open(os.path.join(request.folder,'views/ajax_examples/fade.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
<p>Try it here: <a href="/{{=request.application}}/ajax_examples/fade">fade</a></p>
<p>Try it here: <a class="btn" href="/{{=request.application}}/ajax_examples/fade">fade</a></p>
<h3>Excel-like spreadsheet via Ajax</h3>
Web2py includes a widget that acts like an Excel-like spreadsheet and can be used to build forms

View File

@@ -1,37 +1,24 @@
{{extend 'layout.html'}}
{{
import random
quotes = [
("web2py was the life saver today for me, my blog post: Standalone Usage of web2py's", "caglartoklu", "http://twitter.com/#!/caglartoklu/status/84292131707031553"),
("Get Things Done - Faster, Better and More Easily with web2py",
"Bruno Rocha", "http://twitter.com/#!/rochacbruno/status/73583156044890112"),
("Please use www.web2py.com when using MVC , no PHP/SQL stuff please...its 2011 not 1999", "rabblesoft", "http://twitter.com/#!/rabblesoft/status/79189028431343616"),
('web2py rules! as a sysadmin I like the no installation and no configuration approach a lot)', "kjogut", "http://twitter.com/#!/jkogut/status/61414554273447936"),
("web2py it is. Compatible with everything under the sun and great interfaces to googleappengine", "comamitc","http://twitter.com/#!/comamitc/status/51744719071477760"),
("If you are still learning python, web2py is best tool by far", "pbreit", "http://twitter.com/#!/pbreit/status/48260905775017984")
]
random.shuffle(quotes)
}}
<div class="row-fluid">
<div class="span12">
<div class="span8">
<h3>web2py<sup>TM</sup> Web Framework</h3>
<div class="container">
<div class="twothirds">
<div class="padded">
<h3><img src="{{=URL('static/images', 'web2py_logo.png')}}"> Web Framework</h3>
<p>Free open source full-stack framework for rapid development of fast, scalable, <a href="http://www.web2py.com/book/default/chapter/01#Security" target="_blank">secure</a> and portable database-driven web-based applications. Written and programmable in <a href="http://www.python.org" target="_blank">Python</a>.</p>
<table width="100%">
<tr>
<td>
<a href="http://web2py.com/book">
<a class="noeffect" href="http://web2py.com/book">
<img src="{{=URL('static','images/book-5th.png')}}" />
</a>
</td>
<td>
<a href="https://vimeo.com/album/3016728">
<a class="noeffect" href="https://vimeo.com/album/3016728">
<img src="{{=URL('static','images/videos.png')}}" />
</a>
</td>
<td>
<a href="http://link.packtpub.com/SUlnrN">
<a class="noeffect" href="http://link.packtpub.com/SUlnrN">
<img src="{{=URL('static','images/book-recipes.png')}}" />
</a>
</td>
@@ -39,45 +26,44 @@ random.shuffle(quotes)
</table>
<p>Current version: <a href="{{=URL('download')}}">{{=request.env.web2py_version}} (<a href="http://www.gnu.org/licenses/lgpl.html">LGPLv3 License</a>)</p>
</div>
<div class="span4" style="text-align:center">
<a href="http://www.infoworld.com/slideshow/24605/infoworlds-2012-technology-of-the-year-award-winners-183313#slide23"><img src="{{=URL('static','images/infoworld2012.jpeg')}}" width="200px"/></a><br/>
<a class="btn btn-danger" href="{{=URL('download')}}" style="margin-top:10px; width:180px; color:white">Download Now</a><br/>
<a class="btn btn-danger" href="https://www.pythonanywhere.com/try-web2py" style="margin-top:10px; width:180px; color:white">Try it now online</a><br/>
<a class="btn btn-danger" href="http://web2py.com/poweredby" style="margin-top:10px; width:180px; color:white">Sites Powered by web2py</a><br/><br/>
<a class="coinbase-button" data-code="df71ec5c2d5bc3b1c18139ab645f352b" data-button-style="donation_large" href="https://coinbase.com/checkouts/df71ec5c2d5bc3b1c18139ab645f352b">Donate Bitcoins</a><script src="https://coinbase.com/assets/button.js" type="text/javascript"></script>
</div>
<div class="third">
<div class="padded center">
<a class="noeffect" href="http://www.infoworld.com/slideshow/24605/infoworlds-2012-technology-of-the-year-award-winners-183313#slide23">
<img class="spaced-vertical" src="{{=URL('static','images/infoworld2012.jpeg')}}">
</a>
<a class="btn rounded red fill" href="{{=URL('download')}}">
Download Now
</a>
<a class="btn rounded red fill" href="{{=URL('examples')}}">
Quick Examples
</a>
<a class="btn rounded red fill" href="https://www.pythonanywhere.com/try-web2py">
Try it now online
</a>
<a class="btn rounded red fill" href="http://web2py.com/poweredby">
Sites Powered by web2py
</a>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<div class="span4">
<h3><a href="{{=URL('what')}}">Batteries Included</a></h3>
<div class="container">
<div class="third">
<div class="padded">
<h5><a href="{{=URL('what')}}">Batteries Included</a></h5>
<p>Everything you need in one package including fast multi-threaded web server, SQL database and web-based interface. No third party dependencies but works with <a href={{=URL('what')}}>third party tools</a>.</p>
</div>
<div class="span4">
<h3><a href="http://web2py.com/demo_admin">Web-Based IDE</a></h3>
</div>
<div class="third">
<div class="padded">
<h5><a href="http://web2py.com/demo_admin">Web-Based IDE</a></h5>
<p>Create, modify, deploy and manage application from anywhere using your browser. One web2py instance can run multiple web sites using different databases. Try the <a href="http://www.web2py.com/demo_admin">interactive demo</a>.</p>
</div>
<div class="span4">
<h3><a href="{{=URL('documentation')}}">Extensive Docs</a></h3>
<p>Start with some <a href="{{=URL('examples')}}">quick examples</a>, then read the <a href="http://www.web2py.com/book" target="_blank">manual</a> and the <a href="http://web2py.readthedocs.org/en/latest/" target="_blank">Sphinx docs</a>, watch <a href="http://vimeo.com/album/178500" target="_blank">videos</a>, and join a <a href="{{=URL('default', 'usergroups')}}">user group</a> for discussion. Take advantage of the <a href="http://www.web2py.com/layouts" target="_blank">layouts</a>, <a href="http://dev.s-cubism.com/web2py_plugins" target="_blank">plugins</a>, <a href="http://www.web2py.com/appliances" target="_blank">appliances</a>, and <a href="http://web2pyslices.com" target="_blank">recipes</a>.</p>
</div>
<div class="third">
<div class="padded">
<h5><a href="{{=URL('documentation')}}">Extensive Docs</a></h5>
<p>Start with some <a href="{{=URL('examples')}}">quick examples</a>, then read the <a href="http://www.web2py.com/book" target="_blank">manual</a> and the <a href="http://web2py.readthedocs.org/en/latest/" target="_blank">Sphinx docs</a>, watch <a href="http://vimeo.com/album/178500" target="_blank">videos</a>, and join a <a href="{{=URL('default', 'usergroups')}}">user group</a> for discussion. Take advantage of the <a href="http://www.web2py.com/layouts" target="_blank">layouts</a>, <a href="http://www.web2pyslices.com/home?content_type=Package" target="_blank">plugins</a>, <a href="http://www.web2py.com/appliances" target="_blank">appliances</a>, and <a href="http://web2pyslices.com" target="_blank">recipes</a>.</p>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<img class="scale-with-grid centered" src="/examples/static/images/shadow-bottom.png">
</div>
</div>
<div class="row-fluid">
<div class="span12">
{{for k,quote in enumerate(quotes[:3]):}}
<div class="span4">
<p style="text-align: left"><em>{{=quote[0]}}</em></p>
<span class="right">
<a href="{{=quote[2]}}">{{=quote[1]}}</a>
</span>
</div>
{{pass}}
</div>
</div>

View File

@@ -17,22 +17,26 @@
<ul>
<li><a target="_blank" href="http://experts4solutions.com">Experts4Soutions</a> (worldwide)</li>
<li><a target="_blank" href="http://www.planethost.com">PlanetHost</a> (USA)</li>
<li><a target="_blank" href="http://www.formatics.nl">Formatics</a> (Netherlands)</li>
<li><a target="_blank" href="http://www.corebyte.nl">Corebyte</a> (Netherlands)</li>
<li><a target="_blank" href="http://www.dutveul.nl">Dutveul</a> (Netherlands)</li>
<li><a target="_blank" href="http://www.onemewebservices.com">OneMeWebServices</a> (Canada)</li>
<li><a target="_blank" href="http://www.budgetbytes.nl">BudgetBytes</a> (The Netherlands)</li>
<li><a target="_blank" href="http://www.androsoft.pl">ANDROSoft</a> (Poland)</li>
<li><a target="_blank" href="www.sonnetech.com.br">Sonne Tech</a> (Brazil)</li>
<li><a target="_blank" href="http://www.sonnetech.com.br">Sonne Tech</a> (Brazil)</li>
<li><a target="_blank" href="http://www.nrg.com.br">NRG Internet Solutions</a> (Brazil)</li>
<li><a target="_blank" href="http://itjp.net.br/">ITJP</a> (Brazil)</li>
<li><a target="_blank" href="http://i-am.pt">I am Consultoria</a> (Portugal)</li>
<li><a target="_blank" href="http://www.definescope.com/">DefineScope</a> (Portugal)</li>
<li><a target="_blank" href="http://lpfx.com.br">LPFX</a> (Brazil)</li>
<li><a target="_blank" href="http://emotionull.com">Emotionull</a> (Greece and Cyprus)</li>
<li><a target="_blank" href="http://www.vsa-services.com/">VSA Services</a> (Singapore)</li>
<li><a target="_blank" href="http://www.albendas.com">Albendas</a> (Spain)</li>
<li><a target="_blank" href="https://loadinfo-net.appspot.com">LoadInfo</a> (Bulgaria)</li>
<li><a target="_blank" href="http://www.appliedobjects.com">Applied Objects</a> (New Zealand)</li>
<li><a target="_blank" href="http://www.sistemasagiles.com.ar/">Sistemas Ágiles</a> ("Agile Systems") (Argentina)</li>
<li><a target="_blank" href="http://www.tasko.it/">Tasko</a> (Italy)</li>
<li><a target="_blank" href="http://www.geekondemand.it/"> GeekOnDemand</a> (Italy)</li>
<li><a target="_blank" href="http://stifix.com"> Stifix</a> (Indonesia)</li>
<li><a target="_blank" href="http://www.garciac.es"> Garciac</a> (Spain)</li>
<li><a target="_blank" href="http://memoriapersistente.pt "> Memoria persistente</a> (Portugal)</li>
</ul>
</div>

View File

@@ -5,6 +5,7 @@
{{block right_sidebar}}
<center>
<!--
<h3 class="feature-title">SITES POWERED BY WEB2PY</h3>
<a href="http://web2py.com/poweredby"><img class="frame" id="img1" width="200px"/></a>
<a href="http://web2py.com/poweredby"><img class="frame" id="img2" width="200px"/></a>
@@ -14,7 +15,7 @@
<a href="http://web2py.com/poweredby"><img class="frame" id="img6" width="200px"/></a>
<a href="http://web2py.com/poweredby"><img class="frame" id="img7" width="200px"/></a>
<a href="http://web2py.com/poweredby"><img class="frame" id="img8" width="200px"/></a>
</div>
-->
</center>
<script>
function showimages() {

View File

@@ -82,6 +82,7 @@
</li><li>Keith Yang (openid)
</li><li><a href="http://dev.s-cubism.com/web2py_plugins">Kenji Hosoda</a> (plugins)
</li><li>Kyle Smith (javascript)
</li><li><a href="https://github.com/leonelcamara">Leonel Câmara</a>
</li><li><a href="http://blog.donews.com/limodou/">Limodou</a> (winservice)
</li><li><a href="https://github.com/lucasdavila">Lucas D'Ávila</a>
</li><li>Marc Abramowitz (tests and travis continuous integration)
@@ -99,6 +100,7 @@
</li><li>Michael Willis (shell)
</li><li>Michele Comitini (facebook)
</li><li>Michael Toomim (scheduler)
</li><li>Narendra Bhati (security)
</li><li>Nathan Freeze (admin design, IS_STRONG, DAL features, <a href="http://web2pyslices.com">web2pyslices.com</a>)
</li><li>Niall Sweeny (MSSQL support)
</li><li>Niccolo Polo (epydoc)

View File

@@ -1,173 +1,67 @@
<!--[if HTML5]><![endif]-->
<!DOCTYPE html>
<!-- paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ -->
<!--[if lt IE 7]><html class="ie ie6 ie-lte9 ie-lte8 ie-lte7 no-js" lang="{{=T.accepted_language or 'en'}}"> <![endif]-->
<!--[if IE 7]><html class="ie ie7 ie-lte9 ie-lte8 ie-lte7 no-js" lang="{{=T.accepted_language or 'en'}}"> <![endif]-->
<!--[if IE 8]><html class="ie ie8 ie-lte9 ie-lte8 no-js" lang="{{=T.accepted_language or 'en'}}"> <![endif]-->
<!--[if IE 9]><html class="ie9 ie-lte9 no-js" lang="{{=T.accepted_language or 'en'}}"> <![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--> <html class="no-js" lang="{{=T.accepted_language or 'en'}}"> <!--<![endif]-->
<head>
<title>{{=response.title or request.application}}</title>
<!--[if !HTML5]>
<meta http-equiv="X-UA-Compatible" content="IE=edge{{=not request.is_local and ',chrome=1' or ''}}">
<![endif]-->
<!-- www.phpied.com/conditional-comments-block-downloads/ -->
<!-- Always force latest IE rendering engine
(even in intranet) & Chrome Frame
Remove this if you use the .htaccess -->
<meta charset="utf-8" />
<!-- http://dev.w3.org/html5/markup/meta.name.html -->
<meta name="application-name" content="{{=request.application}}" />
<!-- Speaking of Google, don't forget to set your site up:
http://google.com/webmasters -->
<meta name="google-site-verification" content="" />
<!-- Mobile Viewport Fix
j.mp/mobileviewport & davidbcalhoun.com/2010/viewport-metatag
device-width: Occupy full width of the screen in its current orientation
initial-scale = 1.0 retains dimensions instead of zooming out if page height > device height
user-scalable = yes allows the user to zoom in -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="{{=URL('static','images/favicon.ico')}}" type="image/x-icon">
<link rel="apple-touch-icon" href="{{=URL('static','images/favicon.png')}}">
<!-- All JavaScript at the bottom, except for Modernizr which enables
HTML5 elements & feature detects -->
<script src="{{=URL('static','js/modernizr.custom.js')}}"></script>
<!-- include stylesheets -->
{{
response.files.append(URL('static','css/web2py.css'))
response.files.append(URL('static','css/bootstrap.min.css'))
response.files.append(URL('static','css/bootstrap-responsive.min.css'))
response.files.append(URL('static','css/web2py_bootstrap.css'))
response.files.append(URL('static','css/examples.css'))
}}
{{include 'web2py_ajax.html'}}
{{
# using sidebars need to know what sidebar you want to use
left_sidebar_enabled = globals().get('left_sidebar_enabled',False)
right_sidebar_enabled = globals().get('right_sidebar_enabled',False)
middle_columns = {0:'span12',1:'span9',2:'span6'}[
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<link href="{{=URL('static','css/calendar.css')}}" rel="stylesheet" type="text/css"/>
<link href="{{=URL('static','css/web2py.css')}}" rel="stylesheet" type="text/css"/>
<link href="{{=URL('static','css/stupid.css')}}" rel="stylesheet" type="text/css"/>
<link href="{{=URL('static','css/examples.css')}}" rel="stylesheet" type="text/css"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<link rel="shortcut icon" href="{{=URL('static','images/favicon.ico')}}" type="image/x-icon">
<link rel="apple-touch-icon" href="{{=URL('static','images/favicon.png')}}">
{{
left_sidebar_enabled = globals().get('left_sidebar_enabled', False)
right_sidebar_enabled = globals().get('right_sidebar_enabled', False)
middle_column = {0: 'fill', 1: 'threequarters', 2: 'half'}[
(left_sidebar_enabled and 1 or 0)+(right_sidebar_enabled and 1 or 0)]
}}
<!-- uncomment here to load jquery-ui
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/base/jquery-ui.css" type="text/css" media="all" />
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js" type="text/javascript"></script>
uncomment to load jquery-ui //-->
<noscript><link href="{{=URL('static', 'css/web2py_bootstrap_nojs.css')}}" rel="stylesheet" type="text/css" /></noscript>
{{block head}}{{end}}
</head>
<body>
<!-- Navbar ================================================== -->
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="flash">{{=response.flash or ''}}</div>
<div class="navbar-inner">
<div class="container">
<!-- the next tag is necessary for bootstrap menus, do not remove -->
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
{{=response.logo or ''}}
<ul id="navbar" class="nav pull-right">{{='auth' in globals() and auth.navbar(mode="dropdown") or ''}}</ul>
<div class="nav-collapse">
{{is_mobile=request.user_agent().is_mobile}}
{{if response.menu:}}
{{=MENU(response.menu, _class='mobile-menu nav' if is_mobile else 'nav',mobile=is_mobile,li_class='dropdown',ul_class='dropdown-menu')}}
{{pass}}
</div><!--/.nav-collapse -->
</div>
</div>
</div><!--/top navbar -->
<div class="container">
<!-- Masthead ================================================== -->
<header class="mastheader" id="header">
<div class="span4">
<div class="page-header">
<img src="{{=URL('static','images/web2py_logo.png')}}" class="logo" alt="web2py logo" />
}}
{{include "web2py_ajax.html"}}
</head>
<body class="black">
<header class="black padded">
<div class="container middle max900">
<div class="fill middle">
<label class="ham" for="menu"><i class="fa fa-bars padded"></i></label>
<div class="burger accordion">
<input type="checkbox" id="menu"/>
{{=MENU(response.menu,_class='menu')}}
</div>
</div>
</div>
</header>
</div>
<div class="container">
<section id="main" class="main row">
{{if left_sidebar_enabled:}}
<div class="span3 left-sidebar">
{{block left_sidebar}}
<h3>Left Sidebar</h3>
<p></p>
{{end}}
</div>
{{pass}}
<div class="{{=middle_columns}}">
{{block center}}
{{include}}
{{end}}
</div>
{{if right_sidebar_enabled:}}
<div class="span3">
{{block right_sidebar}}
<h3>Right Sidebar</h3>
<p></p>
{{end}}
</div>
{{pass}}
</section><!--/main-->
<!-- Footer ================================================== -->
<div class="row">
<footer class="footer span12" id="footer">
<div class="footer-content">
{{block footer}} <!-- this is default footer -->
<div id="poweredBy" class="pull-right">
{{=T('Copyright')}} &#169; {{=request.now.year}} -
{{=T('Powered by')}}
<a href="http://www.web2py.com/">web2py</a> -
{{=T('Hosted by')}}
<a href="http://pythonanywhere.com">PythonAnywhere</a>
</div>
{{end}}
</div>
</footer>
{{if response.flash:}}
<div class="w2p_flash">
{{=response.flash}}
</div>
</div> <!-- /container -->
<!-- The javascript =============================================
(Placed at the end of the document so the pages load faster) -->
<script src="{{=URL('static','js/bootstrap.min.js')}}"></script>
<script src="{{=URL('static','js/web2py_bootstrap.js')}}"></script>
<!--[if lt IE 7 ]>
<script src="{{=URL('static','js/dd_belatedpng.js')}}"></script>
<script> DD_belatedPNG.fix('img, .png_bg'); //fix any <img> or .png_bg background-images </script>
<![endif]-->
{{if response.google_analytics_id:}}
<script src="{{=URL('static','js/analytics.min.js')}}"></script>
<script type="text/javascript">
analytics.initialize({
'Google Analytics':{trackingId:'{{=response.google_analytics_id}}'}
});</script>
{{pass}}
<script src="{{=URL('static','js/share.js',vars=dict(static=URL('static','images')))}}"></script>
<a style="position:fixed;bottom:0;left:0;z-index:1000" href="https://groups.google.com/forum/?fromgroups#!forum/web2py" target="_blank">
<img src="{{=URL('static','images/questions.png')}}" />
</a>
</body>
{{pass}}
<main class="white">
<div class="container max900">
{{if left_sidebar_enabled:}}
<div class="quarter padded">{{block left_sidebar}}{{end}}</div>
{{pass}}
<div class="{{=middle_column}} padded">{{include}}</div>
{{if right_sidebar_enabled:}}
<div class="quarter padded">{{block right_sidebar}}{{end}}</div>
{{pass}}
</div>
<div class="silver center padded">
<a class="fa fa-twitter" href="https://twitter.com/web2py/"></a>
<a class="fa fa-facebook" href="https://www.facebook.com/web2py/"></a>
</div>
</main>
<footer class="black">
<div class="container padded max900">
<div class="fill">
Copyright @ 2016 - Powered by Web2py
</div>
</div>
</footer>
</body>
<script>
// prevent android horizontal scrolling
window.addEventListener("scroll", function(){window.scroll(0, window.pageYOffset);}, false);
</script>
</html>

View File

@@ -1,3 +0,0 @@
{{extend 'layout.html'}}
{{=toolbar}}

View File

@@ -49,7 +49,8 @@ if request.function == 'manage':
auth.table_group(),
auth.table_permission()])
manager_role = manager_action.get('role', None) if manager_action else None
auth.requires_membership(manager_role)(lambda: None)()
if not (gluon.fileutils.check_credentials(request) or auth.has_membership(manager_role)):
raise HTTP(403, "Not authorized")
menu = False
elif (request.application == 'admin' and not session.authorized) or \
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
@@ -80,7 +81,6 @@ if False and request.tickets_db:
def get_databases(request):
dbs = {}
for (key, value) in global_env.items():
cond = False
try:
cond = isinstance(value, GQLDB)
except:
@@ -420,7 +420,7 @@ def ccache():
'oldest': time.time(),
'keys': []
}
disk = copy.copy(ram)
total = copy.copy(ram)
disk['keys'] = []
@@ -445,30 +445,31 @@ def ccache():
gae_stats['oldest'] = GetInHMS(time.time() - gae_stats['oldest_item_age'])
total.update(gae_stats)
else:
# get ram stats directly from the cache object
ram_stats = cache.ram.stats[request.application]
ram['hits'] = ram_stats['hit_total'] - ram_stats['misses']
ram['misses'] = ram_stats['misses']
try:
ram['ratio'] = ram['hits'] * 100 / ram_stats['hit_total']
except (KeyError, ZeroDivisionError):
ram['ratio'] = 0
for key, value in cache.ram.storage.iteritems():
if isinstance(value, dict):
ram['hits'] = value['hit_total'] - value['misses']
ram['misses'] = value['misses']
try:
ram['ratio'] = ram['hits'] * 100 / value['hit_total']
except (KeyError, ZeroDivisionError):
ram['ratio'] = 0
else:
if hp:
ram['bytes'] += hp.iso(value[1]).size
ram['objects'] += hp.iso(value[1]).count
ram['entries'] += 1
if value[0] < ram['oldest']:
ram['oldest'] = value[0]
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
if hp:
ram['bytes'] += hp.iso(value[1]).size
ram['objects'] += hp.iso(value[1]).count
ram['entries'] += 1
if value[0] < ram['oldest']:
ram['oldest'] = value[0]
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
for key in cache.disk.storage:
value = cache.disk.storage[key]
if isinstance(value, dict):
disk['hits'] = value['hit_total'] - value['misses']
disk['misses'] = value['misses']
if isinstance(value[1], dict):
disk['hits'] = value[1]['hit_total'] - value[1]['misses']
disk['misses'] = value[1]['misses']
try:
disk['ratio'] = disk['hits'] * 100 / value['hit_total']
disk['ratio'] = disk['hits'] * 100 / value[1]['hit_total']
except (KeyError, ZeroDivisionError):
disk['ratio'] = 0
else:
@@ -480,12 +481,12 @@ def ccache():
disk['oldest'] = value[0]
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
total['entries'] = ram['entries'] + disk['entries']
total['bytes'] = ram['bytes'] + disk['bytes']
total['objects'] = ram['objects'] + disk['objects']
total['hits'] = ram['hits'] + disk['hits']
total['misses'] = ram['misses'] + disk['misses']
total['keys'] = ram['keys'] + disk['keys']
ram_keys = ram.keys() # ['hits', 'objects', 'ratio', 'entries', 'keys', 'oldest', 'bytes', 'misses']
ram_keys.remove('ratio')
ram_keys.remove('oldest')
for key in ram_keys:
total[key] = ram[key] + disk[key]
try:
total['ratio'] = total['hits'] * 100 / (total['hits'] +
total['misses'])
@@ -575,11 +576,9 @@ def bg_graph_model():
meta_graphmodel = dict(group=request.application, color='#ECECEC')
group = meta_graphmodel['group'].replace(' ', '')
if not subgraphs.has_key(group):
if group not in subgraphs:
subgraphs[group] = dict(meta=meta_graphmodel, tables=[])
subgraphs[group]['tables'].append(tablename)
else:
subgraphs[group]['tables'].append(tablename)
subgraphs[group]['tables'].append(tablename)
graph.add_node(tablename, name=tablename, shape='plaintext',
label=table_template(tablename))

View File

@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
# this file is released under public domain and you can use without limitations
#########################################################################
## This is a sample controller
## - index is the default action of any application
## - user is required for authentication and authorization
## - download is for downloading files uploaded in the db (does streaming)
#########################################################################
# -------------------------------------------------------------------------
# This is a sample controller
# - index is the default action of any application
# - user is required for authentication and authorization
# - download is for downloading files uploaded in the db (does streaming)
# -------------------------------------------------------------------------
def index():
"""
@@ -29,11 +30,12 @@ def user():
http://..../[app]/default/user/profile
http://..../[app]/default/user/retrieve_password
http://..../[app]/default/user/change_password
http://..../[app]/default/user/manage_users (requires membership in
http://..../[app]/default/user/bulk_register
use @auth.requires_login()
@auth.requires_membership('group name')
@auth.requires_permission('read','table name',record_id)
to decorate functions that need access control
also notice there is http://..../[app]/appadmin/manage/auth to allow administrator to manage users
"""
return dict(form=auth())

View File

@@ -1,480 +1,491 @@
# coding: utf8
{
'!langcode!': 'cs-cz',
'!langname!': 'čeština',
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". Výsledky databázového JOINu nemůžete mazat ani upravovat.',
'"User Exception" debug mode. An error ticket could be issued!': '"User Exception" debug mode. An error ticket could be issued!',
'%%{Row} in Table': '%%{řádek} v tabulce',
'%%{Row} selected': 'označených %%{řádek}',
'%s %%{row} deleted': '%s smazaných %%{záznam}',
'%s %%{row} updated': '%s upravených %%{záznam}',
'%s selected': '%s označených',
'%Y-%m-%d': '%d.%m.%Y',
'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S',
'(requires internet access)': '(vyžaduje připojení k internetu)',
'(requires internet access, experimental)': '(requires internet access, experimental)',
'(something like "it-it")': '(například "cs-cs")',
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)',
'@markmin\x01Searching: **%s** %%{file}': 'Hledání: **%s** %%{soubor}',
'About': 'O programu',
'About application': 'O aplikaci',
'Access Control': 'Řízení přístupu',
'Add breakpoint': 'Přidat bod přerušení',
'Additional code for your application': 'Další kód pro Vaši aplikaci',
'Admin design page': 'Admin design page',
'Admin language': 'jazyk rozhraní',
'Administrative interface': 'pro administrátorské rozhraní klikněte sem',
'Administrative Interface': 'Administrátorské rozhraní',
'administrative interface': 'rozhraní pro správu',
'Administrator Password:': 'Administrátorské heslo:',
'Ajax Recipes': 'Recepty s ajaxem',
'An error occured, please %s the page': 'An error occured, please %s the page',
'and rename it:': 'a přejmenovat na:',
'appadmin': 'appadmin',
'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení',
'Application': 'Application',
'application "%s" uninstalled': 'application "%s" odinstalována',
'application compiled': 'aplikace zkompilována',
'Application name:': 'Název aplikace:',
'are not used': 'nepoužita',
'are not used yet': 'ještě nepoužita',
'Are you sure you want to delete this object?': 'Opravdu chcete odstranit tento objekt?',
'Are you sure you want to uninstall application "%s"?': 'Opravdu chcete odinstalovat aplikaci "%s"?',
'arguments': 'arguments',
'at char %s': 'at char %s',
'at line %s': 'at line %s',
'ATTENTION:': 'ATTENTION:',
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.',
'Available Databases and Tables': 'Dostupné databáze a tabulky',
'back': 'zpět',
'Back to wizard': 'Back to wizard',
'Basics': 'Basics',
'Begin': 'Začít',
'breakpoint': 'bod přerušení',
'Breakpoints': 'Body přerušení',
'breakpoints': 'body přerušení',
'Buy this book': 'Koupit web2py knihu',
'Cache': 'Cache',
'cache': 'cache',
'Cache Keys': 'Klíče cache',
'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny',
'can be a git repo': 'může to být git repo',
'Cancel': 'Storno',
'Cannot be empty': 'Nemůže být prázdné',
'Change Admin Password': 'Změnit heslo pro správu',
'Change admin password': 'Změnit heslo pro správu aplikací',
'Change password': 'Změna hesla',
'check all': 'vše označit',
'Check for upgrades': 'Zkusit aktualizovat',
'Check to delete': 'Označit ke smazání',
'Check to delete:': 'Označit ke smazání:',
'Checking for upgrades...': 'Zjišťuji, zda jsou k dispozici aktualizace...',
'Clean': 'Pročistit',
'Clear CACHE?': 'Vymazat CACHE?',
'Clear DISK': 'Vymazat DISK',
'Clear RAM': 'Vymazat RAM',
'Click row to expand traceback': 'Pro rozbalení stopy, klikněte na řádek',
'Click row to view a ticket': 'Pro zobrazení chyby (ticketu), klikněte na řádku...',
'Client IP': 'IP adresa klienta',
'code': 'code',
'Code listing': 'Code listing',
'collapse/expand all': 'vše sbalit/rozbalit',
'Community': 'Komunita',
'Compile': 'Zkompilovat',
'compiled application removed': 'zkompilovaná aplikace smazána',
'Components and Plugins': 'Komponenty a zásuvné moduly',
'Condition': 'Podmínka',
'continue': 'continue',
'Controller': 'Kontrolér (Controller)',
'Controllers': 'Kontroléry',
'controllers': 'kontroléry',
'Copyright': 'Copyright',
'Count': 'Počet',
'Create': 'Vytvořit',
'create file with filename:': 'vytvořit soubor s názvem:',
'created by': 'vytvořil',
'Created By': 'Vytvořeno - kým',
'Created On': 'Vytvořeno - kdy',
'crontab': 'crontab',
'Current request': 'Aktuální požadavek',
'Current response': 'Aktuální odpověď',
'Current session': 'Aktuální relace',
'currently running': 'právě běží',
'currently saved or': 'uloženo nebo',
'customize me!': 'upravte mě!',
'data uploaded': 'data nahrána',
'Database': 'Rozhraní databáze',
'Database %s select': 'databáze %s výběr',
'Database administration': 'Database administration',
'database administration': 'správa databáze',
'Date and Time': 'Datum a čas',
'day': 'den',
'db': 'db',
'DB Model': 'Databázový model',
'Debug': 'Ladění',
'defines tables': 'defines tables',
'Delete': 'Smazat',
'delete': 'smazat',
'delete all checked': 'smazat vše označené',
'delete plugin': 'delete plugin',
'Delete this file (you will be asked to confirm deletion)': 'Smazat tento soubor (budete požádán o potvrzení mazání)',
'Delete:': 'Smazat:',
'deleted after first hit': 'smazat po prvním dosažení',
'Demo': 'Demo',
'Deploy': 'Nahrát',
'Deploy on Google App Engine': 'Nahrát na Google App Engine',
'Deploy to OpenShift': 'Nahrát na OpenShift',
'Deployment Recipes': 'Postupy pro deployment',
'Description': 'Popis',
'design': 'návrh',
'Detailed traceback description': 'Podrobný výpis prostředí',
'details': 'podrobnosti',
'direction: ltr': 'směr: ltr',
'Disable': 'Zablokovat',
'DISK': 'DISK',
'Disk Cache Keys': 'Klíče diskové cache',
'Disk Cleared': 'Disk smazán',
'docs': 'dokumentace',
'Documentation': 'Dokumentace',
"Don't know what to do?": 'Nevíte kudy kam?',
'done!': 'hotovo!',
'Download': 'Stáhnout',
'download layouts': 'stáhnout moduly rozvržení stránky',
'download plugins': 'stáhnout zásuvné moduly',
'E-mail': 'E-mail',
'Edit': 'Upravit',
'edit all': 'edit all',
'Edit application': 'Správa aplikace',
'edit controller': 'edit controller',
'Edit current record': 'Upravit aktuální záznam',
'Edit Profile': 'Upravit profil',
'edit views:': 'upravit pohled:',
'Editing file "%s"': 'Úprava souboru "%s"',
'Editing Language file': 'Úprava jazykového souboru',
'Editing Plural Forms File': 'Editing Plural Forms File',
'Email and SMS': 'Email a SMS',
'Enable': 'Odblokovat',
'enter a number between %(min)g and %(max)g': 'zadejte číslo mezi %(min)g a %(max)g',
'enter an integer between %(min)g and %(max)g': 'zadejte celé číslo mezi %(min)g a %(max)g',
'Error': 'Chyba',
'Error logs for "%(app)s"': 'Seznam výskytu chyb pro aplikaci "%(app)s"',
'Error snapshot': 'Snapshot chyby',
'Error ticket': 'Ticket chyby',
'Errors': 'Chyby',
'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s',
'Exception %s': 'Exception %s',
'Exception instance attributes': 'Prvky instance výjimky',
'Expand Abbreviation': 'Expand Abbreviation',
'export as csv file': 'exportovat do .csv souboru',
'exposes': 'vystavuje',
'exposes:': 'vystavuje funkce:',
'extends': 'rozšiřuje',
'failed to compile file because:': 'soubor se nepodařilo zkompilovat, protože:',
'FAQ': 'Často kladené dotazy',
'File': 'Soubor',
'file': 'soubor',
'file "%(filename)s" created': 'file "%(filename)s" created',
'file saved on %(time)s': 'soubor uložen %(time)s',
'file saved on %s': 'soubor uložen %s',
'Filename': 'Název souboru',
'filter': 'filtr',
'Find Next': 'Najít další',
'Find Previous': 'Najít předchozí',
'First name': 'Křestní jméno',
'Forgot username?': 'Zapomněl jste svoje přihlašovací jméno?',
'forgot username?': 'zapomněl jste svoje přihlašovací jméno?',
'Forms and Validators': 'Formuláře a validátory',
'Frames': 'Frames',
'Free Applications': 'Aplikace zdarma',
'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.',
'Generate': 'Vytvořit',
'Get from URL:': 'Stáhnout z internetu:',
'Git Pull': 'Git Pull',
'Git Push': 'Git Push',
'Globals##debug': 'Globální proměnné',
'go!': 'OK!',
'Goto': 'Goto',
'graph model': 'graph model',
'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena',
'Group ID': 'ID skupiny',
'Groups': 'Skupiny',
'Hello World': 'Ahoj světe',
'Help': 'Nápověda',
'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty',
'Hits': 'Kolikrát dosaženo',
'Home': 'Domovská stránka',
'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně',
'How did you get here?': 'Jak jste se sem vlastně dostal?',
'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download',
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.',
'import': 'import',
'Import/Export': 'Import/Export',
'includes': 'zahrnuje',
'Index': 'Index',
'insert new': 'vložit nový záznam ',
'insert new %s': 'vložit nový záznam %s',
'inspect attributes': 'inspect attributes',
'Install': 'Instalovat',
'Installed applications': 'Nainstalované aplikace',
'Interaction at %s line %s': 'Interakce v %s, na řádce %s',
'Interactive console': 'Interaktivní příkazová řádka',
'Internal State': 'Vnitřní stav',
'Introduction': 'Úvod',
'Invalid email': 'Neplatný email',
'Invalid password': 'Nesprávné heslo',
'invalid password.': 'neplatné heslo',
'Invalid Query': 'Neplatný dotaz',
'invalid request': 'Neplatný požadavek',
'Is Active': 'Je aktivní',
'It is %s %%{day} today.': 'Dnes je to %s %%{den}.',
'Key': 'Klíč',
'Key bindings': 'Vazby klíčů',
'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin',
'languages': 'jazyky',
'Languages': 'Jazyky',
'Last name': 'Příjme',
'Last saved on:': 'Naposledy uloženo:',
'Layout': 'Rozvržení stránky (layout)',
'Layout Plugins': 'Moduly rozvržení stránky (Layout Plugins)',
'Layouts': 'Rozvržení stránek',
'License for': 'Licence pro',
'Line number': 'Číslo řádku',
'LineNo': 'Č.řádku',
'Live Chat': 'Online pokec',
'loading...': 'nahrávám...',
'locals': 'locals',
'Locals##debug': 'Lokální proměnné',
'Logged in': 'Přihlášení proběhlo úspěšně',
'Logged out': 'Odhlášení proběhlo úspěšně',
'Login': 'Přihlásit se',
'login': 'přihlásit se',
'Login to the Administrative Interface': 'Přihlásit se do Správce aplikací',
'logout': 'odhlásit se',
'Logout': 'Odhlásit se',
'Lost Password': 'Zapomněl jste heslo',
'Lost password?': 'Zapomněl jste heslo?',
'lost password?': 'zapomněl jste heslo?',
'Manage': 'Manage',
'Manage Cache': 'Manage Cache',
'Menu Model': 'Model rozbalovací nabídky',
'Models': 'Modely',
'models': 'modely',
'Modified By': 'Změněno - kým',
'Modified On': 'Změněno - kdy',
'Modules': 'Moduly',
'modules': 'moduly',
'My Sites': 'Správa aplikací',
'Name': 'Jméno',
'new application "%s" created': 'nová aplikace "%s" vytvořena',
'New Application Wizard': 'Nový průvodce aplikací',
'New application wizard': 'Nový průvodce aplikací',
'New password': 'Nové heslo',
'New Record': 'Nový záznam',
'new record inserted': 'nový záznam byl založen',
'New simple application': 'Vytvořit primitivní aplikaci',
'next': 'next',
'next 100 rows': 'dalších 100 řádků',
'No databases in this application': 'V této aplikaci nejsou žádné databáze',
'No Interaction yet': 'Ještě žádná interakce nenastala',
'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen',
'Object or table name': 'Objekt či tabulka',
'Old password': 'Původní heslo',
'online designer': 'online návrhář',
'Online examples': 'Příklady online',
'Open new app in new window': 'Open new app in new window',
'or alternatively': 'or alternatively',
'Or Get from URL:': 'Or Get from URL:',
'or import from csv file': 'nebo importovat z .csv souboru',
'Origin': 'Původ',
'Original/Translation': 'Originál/Překlad',
'Other Plugins': 'Ostatní moduly',
'Other Recipes': 'Ostatní zásuvné moduly',
'Overview': 'Přehled',
'Overwrite installed app': 'Přepsat instalovanou aplikaci',
'Pack all': 'Zabalit',
'Pack compiled': 'Zabalit zkompilované',
'pack plugin': 'pack plugin',
'password': 'heslo',
'Password': 'Heslo',
"Password fields don't match": 'Hesla se neshodu',
'Peeking at file': 'Peeking at file',
'Please': 'Prosím',
'Plugin "%s" in application': 'Plugin "%s" in application',
'plugins': 'zásuvné moduly',
'Plugins': 'Zásuvné moduly',
'Plural Form #%s': 'Plural Form #%s',
'Plural-Forms:': 'Množná čísla:',
'Powered by': 'Poháněno',
'Preface': 'Předmluva',
'previous 100 rows': 'předchozích 100 řádků',
'Private files': 'Soukromé soubory',
'private files': 'soukromé soubory',
'profile': 'profil',
'Project Progress': 'Vývoj projektu',
'Python': 'Python',
'Query:': 'Dotaz:',
'Quick Examples': 'Krátké příklady',
'RAM': 'RAM',
'RAM Cache Keys': 'Klíče RAM Cache',
'Ram Cleared': 'RAM smazána',
'Readme': 'Nápověda',
'Recipes': 'Postupy jak na to',
'Record': 'Záznam',
'record does not exist': 'záznam neexistuje',
'Record ID': 'ID záznamu',
'Record id': 'id záznamu',
'refresh': 'obnovte',
'register': 'registrovat',
'Register': 'Zaregistrovat se',
'Registration identifier': 'Registrační identifikátor',
'Registration key': 'Registrační klíč',
'reload': 'reload',
'Reload routes': 'Znovu nahrát cesty',
'Remember me (for 30 days)': 'Zapamatovat na 30 dní',
'Remove compiled': 'Odstranit zkompilované',
'Removed Breakpoint on %s at line %s': 'Bod přerušení smazán - soubor %s na řádce %s',
'Replace': 'Zaměnit',
'Replace All': 'Zaměnit vše',
'request': 'request',
'Reset Password key': 'Reset registračního klíče',
'response': 'response',
'restart': 'restart',
'restore': 'obnovit',
'Retrieve username': 'Získat přihlašovací jméno',
'return': 'return',
'revert': 'vrátit se k původnímu',
'Role': 'Role',
'Rows in Table': 'Záznamy v tabulce',
'Rows selected': 'Záznamů zobrazeno',
'rules are not defined': 'pravidla nejsou definována',
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Spustí testy v tomto souboru (ke spuštění všech testů, použijte tlačítko 'test')",
'Running on %s': 'Běží na %s',
'Save': 'Uložit',
'Save file:': 'Save file:',
'Save via Ajax': 'Uložit pomocí Ajaxu',
'Saved file hash:': 'hash uloženého souboru:',
'Semantic': 'Modul semantic',
'Services': 'Služby',
'session': 'session',
'session expired': 'session expired',
'Set Breakpoint on %s at line %s: %s': 'Bod přerušení nastaven v souboru %s na řádce %s: %s',
'shell': 'příkazová řádka',
'Singular Form': 'Singular Form',
'Site': 'Správa aplikací',
'Size of cache:': 'Velikost cache:',
'skip to generate': 'skip to generate',
'Sorry, could not find mercurial installed': 'Bohužel mercurial není nainstalován.',
'Start a new app': 'Vytvořit novou aplikaci',
'Start searching': 'Začít hledání',
'Start wizard': 'Spustit průvodce',
'state': 'stav',
'Static': 'Static',
'static': 'statické soubory',
'Static files': 'Statické soubory',
'Statistics': 'Statistika',
'Step': 'Step',
'step': 'step',
'stop': 'stop',
'Stylesheet': 'CSS styly',
'submit': 'odeslat',
'Submit': 'Odeslat',
'successful': 'úspěšně',
'Support': 'Podpora',
'Sure you want to delete this object?': 'Opravdu chcete smazat tento objekt?',
'Table': 'tabulka',
'Table name': 'Název tabulky',
'Temporary': 'Dočasný',
'test': 'test',
'Testing application': 'Testing application',
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je podmínka, například "db.tabulka1.pole1==\'hodnota\'". Podmínka "db.tabulka1.pole1==db.tabulka2.pole2" pak vytvoří SQL JOIN.',
'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikace: každá URL je mapována na funkci vystavovanou kontrolérem.',
'The Core': 'Jádro (The Core)',
'The data representation, define database tables and sets': 'Reprezentace dat: definovat tabulky databáze a záznamy',
'The output of the file is a dictionary that was rendered by the view %s': 'Výstup ze souboru je slovník, který se zobrazil v pohledu %s.',
'The presentations layer, views are also known as templates': 'Prezentační vrstva: pohledy či templaty (šablony)',
'The Views': 'Pohledy (The Views)',
'There are no controllers': 'There are no controllers',
'There are no modules': 'There are no modules',
'There are no plugins': 'Žádné moduly nejsou instalovány.',
'There are no private files': 'Žádné soukromé soubory neexistují.',
'There are no static files': 'There are no static files',
'There are no translators, only default language is supported': 'There are no translators, only default language is supported',
'There are no views': 'There are no views',
'These files are not served, they are only available from within your app': 'Tyto soubory jsou klientům nepřístupné. K dispozici jsou pouze v rámci aplikace.',
'These files are served without processing, your images go here': 'Tyto soubory jsou servírovány bez přídavné logiky, sem patří např. obrázky.',
'This App': 'Tato aplikace',
'This is a copy of the scaffolding application': 'Toto je kopie aplikace skelet.',
'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk',
'This is the %(filename)s template': 'This is the %(filename)s template',
'this page to see if a breakpoint was hit and debug interaction is required.': 'tuto stránku, abyste uviděli, zda se dosáhlo bodu přerušení.',
'Ticket': 'Ticket',
'Ticket ID': 'Ticket ID',
'Time in Cache (h:m:s)': 'Čas v Cache (h:m:s)',
'Timestamp': 'Časové razítko',
'to previous version.': 'k předchozí verzi.',
'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete soubor/adresář plugin_[jméno modulu]',
'To emulate a breakpoint programatically, write:': 'K nastavení bodu přerušení v kódu programu, napište:',
'to use the debugger!': ', abyste mohli ladící program používat!',
'toggle breakpoint': 'vyp./zap. bod přerušení',
'Toggle Fullscreen': 'Na celou obrazovku a zpět',
'too short': 'Příliš krátké',
'Traceback': 'Traceback',
'Translation strings for the application': 'Překlad textů pro aplikaci',
'try something like': 'try something like',
'Try the mobile interface': 'Zkuste rozhraní pro mobilní zařízení',
'try view': 'try view',
'Twitter': 'Twitter',
'Type python statement in here and hit Return (Enter) to execute it.': 'Type python statement in here and hit Return (Enter) to execute it.',
'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.',
'Unable to check for upgrades': 'Unable to check for upgrades',
'unable to parse csv file': 'csv soubor nedá sa zpracovat',
'uncheck all': 'vše odznačit',
'Uninstall': 'Odinstalovat',
'update': 'aktualizovat',
'update all languages': 'aktualizovat všechny jazyky',
'Update:': 'Upravit:',
'Upgrade': 'Upgrade',
'upgrade now': 'upgrade now',
'upgrade now to %s': 'upgrade now to %s',
'upload': 'nahrát',
'Upload': 'Upload',
'Upload a package:': 'Nahrát balík:',
'Upload and install packed application': 'Nahrát a instalovat zabalenou aplikaci',
'upload file:': 'nahrát soubor:',
'upload plugin file:': 'nahrát soubor modulu:',
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT pro sestavení složitějších dotazů.',
'User %(id)s Logged-in': 'Uživatel %(id)s přihlášen',
'User %(id)s Logged-out': 'Uživatel %(id)s odhlášen',
'User %(id)s Password changed': 'Uživatel %(id)s změnil heslo',
'User %(id)s Profile updated': 'Uživatel %(id)s upravil profil',
'User %(id)s Registered': 'Uživatel %(id)s se zaregistroval',
'User %(id)s Username retrieved': 'Uživatel %(id)s si nachal zaslat přihlašovací jméno',
'User ID': 'ID uživatele',
'Username': 'Přihlašovací jméno',
'variables': 'variables',
'Verify Password': 'Zopakujte heslo',
'Version': 'Verze',
'Version %s.%s.%s (%s) %s': 'Verze %s.%s.%s (%s) %s',
'Versioning': 'Verzování',
'Videos': 'Videa',
'View': 'Pohled (View)',
'Views': 'Pohledy',
'views': 'pohledy',
'Web Framework': 'Web Framework',
'web2py is up to date': 'Máte aktuální verzi web2py.',
'web2py online debugger': 'Ladící online web2py program',
'web2py Recent Tweets': 'Štěbetání na Twitteru o web2py',
'web2py upgrade': 'web2py upgrade',
'web2py upgraded; please restart it': 'web2py upgraded; please restart it',
'Welcome': 'Vítejte',
'Welcome to web2py': 'Vitejte ve web2py',
'Welcome to web2py!': 'Vítejte ve web2py!',
'Which called the function %s located in the file %s': 'která zavolala funkci %s v souboru (kontroléru) %s.',
'You are successfully running web2py': 'Úspěšně jste spustili web2py.',
'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Nastavovat a mazat body přerušení je též možno v rámci editování zdrojového souboru přes tlačítko Vyp./Zap. bod přerušení',
'You can modify this application and adapt it to your needs': 'Tuto aplikaci si můžete upravit a přizpůsobit ji svým potřebám.',
'You need to set up and reach a': 'Je třeba nejprve nastavit a dojít až na',
'You visited the url %s': 'Navštívili jste stránku %s,',
'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Aplikace bude blokována než se klikne na jedno z tlačítek (další, krok, pokračovat, atd.)',
'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné',
}
# -*- coding: utf-8 -*-
{
'!langcode!': 'cs-cz',
'!langname!': 'čeština',
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". Výsledky databázového JOINu nemůžete mazat ani upravovat.',
'"User Exception" debug mode. An error ticket could be issued!': '"User Exception" debug mode. An error ticket could be issued!',
'%%{Row} in Table': '%%{řádek} v tabulce',
'%%{Row} selected': 'označených %%{řádek}',
'%s %%{row} deleted': '%s smazaných %%{záznam}',
'%s %%{row} updated': '%s upravených %%{záznam}',
'%s selected': '%s označených',
'%Y-%m-%d': '%d.%m.%Y',
'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S',
'(requires internet access)': '(vyžaduje připojení k internetu)',
'(requires internet access, experimental)': '(vyžaduje internetové připojení, experimentální)',
'(something like "it-it")': '(například "cs-cz")',
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '@markmin\x01(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)',
'@markmin\x01An error occured, please [[reload %s]] the page': '@markmin\x01Došlo k chybě, prosím [[obnovte stránku %s]]',
'@markmin\x01Searching: **%s** %%{file}': '@markmin\x01Hledání: **%s** %%{soubor}',
'About': 'O programu',
'About application': 'O aplikaci',
'Access Control': 'Řízení přístupu',
'Add breakpoint': 'Přidat bod přerušení',
'Additional code for your application': 'Další kód pro Vaši aplikaci',
'admin': 'admin',
'Admin design page': 'Admin design page',
'Admin language': 'jazyk rozhraní',
'Administrative interface': 'pro administrátorské rozhraní klikněte sem',
'Administrative Interface': 'Administrátorské rozhraní',
'administrative interface': 'rozhraní pro správu',
'Administrator Password:': 'Administrátorské heslo:',
'Ajax Recipes': 'Recepty s ajaxem',
'An error occured, please %s the page': 'Došlo k chybě, prosím %s stránku',
'and rename it:': 'a přejmenovat na:',
'appadmin': 'appadmin',
'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení',
'Application': 'Aplikace',
'application "%s" uninstalled': 'application "%s" odinstalována',
'application compiled': 'aplikace zkompilována',
'Application name:': 'Název aplikace:',
'are not used': 'nepoužita',
'are not used yet': 'ještě nepoužita',
'Are you sure you want to delete this object?': 'Opravdu chcete odstranit tento objekt?',
'Are you sure you want to uninstall application "%s"?': 'Opravdu chcete odinstalovat aplikaci "%s"?',
'arguments': 'argumenty',
'at char %s': 'na pozici znaku %s',
'at line %s': 'na řádku %s',
'ATTENTION:': 'POZOR:',
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.',
'Available Databases and Tables': 'Dostupné databáze a tabulky',
'back': 'zpět',
'Back to wizard': 'Zpátky do průvodce',
'Basics': 'Základy',
'Begin': 'Začít',
'breakpoint': 'bod přerušení',
'Breakpoints': 'Body přerušení',
'breakpoints': 'body přerušení',
'Buy this book': 'Koupit Web2py knihu',
"Buy web2py's book": 'Koupit Web2py knihu',
'Cache': 'Cache',
'cache': 'cache',
'Cache Keys': 'Klíče cache',
'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny',
'can be a git repo': 'může to být git repo',
'Cancel': 'Storno',
'Cannot be empty': 'Nemůže být prázdné',
'Change Admin Password': 'Změnit heslo pro správu',
'Change admin password': 'Změnit heslo pro správu aplikací',
'Change password': 'Změna hesla',
'check all': 'vše označit',
'Check for upgrades': 'Zkusit aktualizovat',
'Check to delete': 'Označit ke smazání',
'Check to delete:': 'Označit ke smazání:',
'Checking for upgrades...': 'Zjišťuji, zda jsou k dispozici aktualizace...',
'Clean': 'Pročistit',
'Clear CACHE?': 'Vymazat CACHE?',
'Clear DISK': 'Vymazat DISK',
'Clear RAM': 'Vymazat RAM',
'Click row to expand traceback': 'Pro rozbalení stopy, klikněte na řádek',
'Click row to view a ticket': 'Pro zobrazení chyby (ticketu), klikněte na řádku...',
'Client IP': 'IP adresa klienta',
'code': 'kód',
'Code listing': 'Výpis kódu',
'collapse/expand all': 'vše sbalit/rozbalit',
'Community': 'Komunita',
'Compile': 'Zkompilovat',
'compiled application removed': 'zkompilovaná aplikace smazána',
'Components and Plugins': 'Komponenty a zásuvné moduly',
'Condition': 'Podmínka',
'Config.ini': 'Config.ini',
'continue': 'pokračovat',
'Controller': 'Kontrolér (Controller)',
'Controllers': 'Kontroléry',
'controllers': 'kontroléry',
'Copyright': 'Copyright',
'Count': 'Počet',
'Create': 'Vytvořit',
'create file with filename:': 'vytvořit soubor s názvem:',
'created by': 'vytvořil',
'Created By': 'Vytvořeno - kým',
'Created On': 'Vytvořeno - kdy',
'crontab': 'crontab',
'Current request': 'Aktuální požadavek',
'Current response': 'Aktuální odpověď',
'Current session': 'Aktuální relace',
'currently running': 'právě běží',
'currently saved or': 'uloženo nebo',
'customize me!': 'upravte mě!',
'data uploaded': 'data nahrána',
'Database': 'Rozhraní databáze',
'Database %s select': 'databáze %s výběr',
'Database administration': 'Administrace databáze',
'database administration': 'správa databáze',
'Date and Time': 'Datum a čas',
'day': 'den',
'db': 'db',
'DB Model': 'Databázový model',
'Debug': 'Ladění',
'defines tables': 'definuje tabulky',
'Delete': 'Smazat',
'delete': 'smazat',
'delete all checked': 'smazat vše označené',
'delete plugin': 'zrušit plugin',
'Delete this file (you will be asked to confirm deletion)': 'Smazat tento soubor (budete požádán o potvrzení mazání)',
'Delete:': 'Smazat:',
'deleted after first hit': 'smazat po prvním dosažení',
'Demo': 'Demo',
'Deploy': 'Nahrát',
'Deploy on Google App Engine': 'Nahrát na Google App Engine',
'Deploy to OpenShift': 'Nahrát na OpenShift',
'Deployment Recipes': 'Postupy pro deployment',
'Description': 'Popis',
'design': 'návrh',
'Design': 'Design',
'Detailed traceback description': 'Podrobný výpis prostředí',
'details': 'podrobnosti',
'direction: ltr': 'směr: ltr',
'Disable': 'Zablokovat',
'DISK': 'DISK',
'Disk Cache Keys': 'Klíče diskové cache',
'Disk Cleared': 'Disk smazán',
'docs': 'dokumentace',
'Documentation': 'Dokumentace',
"Don't know what to do?": 'Kde najdu další informace ?',
'done!': 'hotovo!',
'Download': 'Stáhnout',
'download layouts': 'stáhnout moduly rozvržení stránky',
'download plugins': 'stáhnout zásuvné moduly',
'E-mail': 'E-mail',
'Edit': 'Upravit',
'edit all': 'editovat vše',
'Edit application': 'Správa aplikace',
'edit controller': 'editovat controller',
'Edit current record': 'Upravit aktuální záznam',
'Edit Profile': 'Upravit profil',
'edit views:': 'upravit pohled:',
'Editing file "%s"': 'Úprava souboru "%s"',
'Editing Language file': 'Úprava jazykového souboru',
'Editing Plural Forms File': 'Editování souboru množných čísel',
'Email and SMS': 'Email a SMS',
'Enable': 'Odblokovat',
'enter a number between %(min)g and %(max)g': 'zadejte číslo mezi %(min)g a %(max)g',
'Enter an integer between %(min)g and %(max)g': 'Enter an integer between %(min)g and %(max)g',
'enter an integer between %(min)g and %(max)g': 'zadejte celé číslo mezi %(min)g a %(max)g',
'Error': 'Chyba',
'Error logs for "%(app)s"': 'Seznam výskytu chyb pro aplikaci "%(app)s"',
'Error snapshot': 'Snapshot chyby',
'Error ticket': 'Ticket chyby',
'Errors': 'Chyby',
'Exception %(extype)s: %(exvalue)s': 'Výjimka %(extype)s: %(exvalue)s',
'Exception %s': 'Výjimka %s',
'Exception instance attributes': 'Prvky instance výjimky',
'Expand Abbreviation': 'Expandovat zkratku',
'export as csv file': 'exportovat do .csv souboru',
'exposes': 'vystavuje',
'exposes:': 'vystavuje funkce:',
'extends': 'rozšiřuje',
'failed to compile file because:': 'soubor se nepodařilo zkompilovat, protože:',
'FAQ': 'Často kladené dotazy',
'File': 'Soubor',
'file': 'soubor',
'file "%(filename)s" created': 'soubor "%(filename)s" byl vytvořen',
'file saved on %(time)s': 'soubor uložen %(time)s',
'file saved on %s': 'soubor uložen %s',
'Filename': 'Název souboru',
'filter': 'filtr',
'Find Next': 'Najít další',
'Find Previous': 'Najít předchozí',
'First name': 'Křestní jméno',
'Forgot username?': 'Zapomněl jste svoje přihlašovací jméno?',
'forgot username?': 'zapomněl jste svoje přihlašovací jméno?',
'Forms and Validators': 'Formuláře a validátory',
'Frames': 'Framy',
'Free Applications': 'Aplikace zdarma',
'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.',
'Generate': 'Vytvořit',
'Get from URL:': 'Stáhnout z internetu:',
'Git Pull': 'Git Pull',
'Git Push': 'Git Push',
'Globals##debug': 'Globální proměnné',
'go!': 'OK!',
'Goto': 'Přejít na',
'graph model': 'grafický model',
'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena',
'Group ID': 'ID skupiny',
'Groups': 'Skupiny',
'Hello World': 'Ahoj všichni',
'Help': 'Nápověda',
'Helping web2py': 'Podpořte Web2py',
'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty',
'Hits': 'Kolikrát dosaženo',
'Home': 'Domovská stránka',
'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně',
'How did you get here?': 'Jak se Ti tato stránka vlastně zobrazila?',
'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download',
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\r\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.',
'import': 'import',
'Import/Export': 'Import/Export',
'includes': 'zahrnuje',
'Index': 'Index',
'insert new': 'vložit nový záznam ',
'insert new %s': 'vložit nový záznam %s',
'inspect attributes': 'prohlédnout atributy',
'Install': 'Instalovat',
'Installed applications': 'Nainstalované aplikace',
'Interaction at %s line %s': 'Interakce v %s, na řádce %s',
'Interactive console': 'Interaktivní příkazová řádka',
'Internal State': 'Vnitřní stav',
'Introduction': 'Úvod',
'Invalid email': 'Neplatný email',
'Invalid password': 'Nesprávné heslo',
'invalid password.': 'neplatné heslo',
'Invalid Query': 'Neplatný dotaz',
'invalid request': 'Neplatný požadavek',
'Is Active': 'Je aktiv',
'It is %s %%{day} today.': 'Dnes je to %s %%{den}.',
'Key': 'Klíč',
'Key bindings': 'Vazby klíčů',
'Key bindings for ZenCoding Plugin': 'Key bindings pro ZenCoding Plugin',
'languages': 'jazyky',
'Languages': 'Jazyky',
'Last name': 'Příjmení',
'Last saved on:': 'Naposledy uloženo:',
'Layout': 'Rozvržení stránky (layout)',
'Layout Plugins': 'Moduly rozvržení stránky (Layout Plugins)',
'Layouts': 'Rozvržení stránek',
'License for': 'Licence pro',
'Line number': 'Číslo řádku',
'LineNo': 'Č.řádku',
'Live Chat': 'Online chat',
'loading...': 'nahrávám...',
'locals': 'locals',
'Locals##debug': 'Lokální proměnné',
'Log In': 'Přihlásit se',
'Logged in': 'Přihlášení proběhlo úspěšně',
'Logged out': 'Odhlášení proběhlo úspěšně',
'Login': 'Přihlásit se',
'login': 'přihlásit se',
'Login to the Administrative Interface': 'Přihlásit se do Správce aplikací',
'logout': 'odhlásit se',
'Logout': 'Odhlásit se',
'Lost Password': 'Zapomněl jste heslo',
'Lost password?': 'Zapomněl jste heslo?',
'lost password?': 'zapomněl jste heslo?',
'Manage': 'Spravovat',
'Manage Cache': 'Spravovat cache',
'Menu Model': 'Model rozbalovací nabídky',
'Models': 'Modely',
'models': 'modely',
'Modified By': 'Změněno - kým',
'Modified On': 'Změněno - kdy',
'Modules': 'Moduly',
'modules': 'moduly',
'My Sites': 'Správa aplikací',
'Name': 'Jméno',
'new application "%s" created': 'nová aplikace "%s" vytvořena',
'New application wizard': 'Nový průvodce aplikací',
'New Application Wizard': 'Nový průvodce aplikací',
'New password': 'Nové heslo',
'New Record': 'Nový záznam',
'new record inserted': 'nový záznam byl založen',
'New simple application': 'Vytvořit novou aplikaci',
'next': 'další',
'next 100 rows': 'dalších 100 řádků',
'No databases in this application': 'V této aplikaci nejsou žádné databáze',
'No Interaction yet': 'Ještě žádná interakce nenastala',
'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen',
'Object or table name': 'Objekt či tabulka',
'Old password': 'Původní heslo',
'Online book': 'Online kniha',
'online designer': 'online návrhář',
'Online examples': 'Ukázka aplikace: web2py stránky',
'Open new app in new window': 'Otevřít novou aplikaci v novém okně',
'or alternatively': 'nebo případně',
'Or Get from URL:': 'Nebo získat z URL adresy:',
'or import from csv file': 'nebo importovat z .csv souboru',
'Origin': 'Původ',
'Original/Translation': 'Originál/Překlad',
'Other Plugins': 'Ostatní moduly',
'Other Recipes': 'Ostatní zásuvné moduly',
'Overview': 'Přehled',
'Overwrite installed app': 'Přepsat instalovanou aplikaci',
'Pack all': 'Zabalit',
'Pack compiled': 'Zabalit zkompilované',
'pack plugin': 'pack (zabalit) plugin',
'password': 'heslo',
'Password': 'Heslo',
"Password fields don't match": 'Hesla se neshodují',
'Peeking at file': 'Sledování souboru',
'Please': 'Prosím',
'Plugin "%s" in application': 'Plugin "%s" v aplikaci',
'plugins': 'zásuvné moduly',
'Plugins': 'Zásuvné moduly',
'Plural Form #%s': 'Množné číslo #%s',
'Plural-Forms:': 'Množná čísla:',
'Powered by': 'Používá technologii',
'Preface': 'Předmluva',
'previous 100 rows': 'předchozích 100 řádků',
'Private files': 'Soukromé soubory',
'private files': 'soukromé soubory',
'profile': 'profil',
'Project Progress': 'Vývoj projektu',
'Python': 'Python',
'Query:': 'Dotaz:',
'Quick Examples': 'Krátké příklady',
'RAM': 'RAM',
'RAM Cache Keys': 'Klíče RAM Cache',
'Ram Cleared': 'RAM smazána',
'Readme': 'Nápověda',
'Recipes': 'Postupy jak na to',
'Record': 'Záznam',
'record does not exist': 'záznam neexistuje',
'Record ID': 'ID záznamu',
'Record id': 'id záznamu',
'refresh': 'obnovte',
'register': 'registrovat',
'Register': 'Zaregistrovat se',
'Registration identifier': 'Registrační identifikátor',
'Registration key': 'Registrační klíč',
'reload': 'reload',
'Reload routes': 'Znovu nahrát cesty',
'Remember me (for 30 days)': 'Zapamatovat na 30 dní',
'Remove compiled': 'Odstranit zkompilované',
'Removed Breakpoint on %s at line %s': 'Bod přerušení smazán - soubor %s na řádce %s',
'Replace': 'Zaměnit',
'Replace All': 'Zaměnit vše',
'request': 'request',
'Reset Password key': 'Reset registračního klíče',
'response': 'response',
'restart': 'restart',
'restore': 'obnovit',
'Retrieve username': 'Získat přihlašovací jméno',
'return': 'return',
'revert': 'vrátit se k původnímu',
'Role': 'Role',
'Rows in Table': 'Záznamy v tabulce',
'Rows selected': 'Záznamů zobrazeno',
'rules are not defined': 'pravidla nejsou definována',
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Spustí testy v tomto souboru (ke spuštění všech testů, použijte tlačítko 'test')",
'Running on %s': 'Běží na %s',
'Save': 'Uložit',
'Save file:': 'Uložit soubor:',
'Save via Ajax': 'Uložit pomocí Ajaxu',
'Saved file hash:': 'hash uloženého souboru:',
'Semantic': 'Modul semantic',
'Services': 'Služby',
'session': 'session',
'session expired': 'vypršela session',
'Set Breakpoint on %s at line %s: %s': 'Bod přerušení nastaven v souboru %s na řádce %s: %s',
'shell': 'příkazová řádka',
'Sign Up': 'Registrovat se',
'Singular Form': 'Jednotné číslo',
'Site': 'Správa aplikací',
'Size of cache:': 'Velikost cache:',
'skip to generate': 'přeskočit pro vytvoření',
'Sorry, could not find mercurial installed': 'Bohužel mercurial není nainstalován.',
'Start a new app': 'Vytvořit novou aplikaci',
'Start searching': 'Začít hledání',
'Start wizard': 'Spustit průvodce',
'state': 'stav',
'Static': 'Statické soubory',
'static': 'statické soubory',
'Static files': 'Statické soubory',
'Statistics': 'Statistika',
'Step': 'Krok',
'step': 'krok',
'stop': 'zastavit',
'Stylesheet': 'CSS styly',
'submit': 'odeslat',
'Submit': 'Odeslat',
'successful': 'úspěšně',
'Support': 'Podpora',
'Sure you want to delete this object?': 'Opravdu chcete smazat tento objekt?',
'Table': 'tabulka',
'Table name': 'Název tabulky',
'Temporary': 'Dočasný',
'test': 'test',
'Testing application': 'Zkušební aplikace',
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je podmínka, například "db.tabulka1.pole1==\'hodnota\'". Podmínka "db.tabulka1.pole1==db.tabulka2.pole2" pak vytvoří SQL JOIN.',
'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikace: každá URL je mapována na funkci vystavovanou kontrolérem.',
'The Core': 'Jádro (The Core)',
'The data representation, define database tables and sets': 'Reprezentace dat: definovat tabulky databáze a záznamy',
'The output of the file is a dictionary that was rendered by the view %s': 'Funkce vrátila dictionary (slovník) hodnot, a ty se vypsaly pomocí šablony %s.',
'The presentations layer, views are also known as templates': 'Prezentační vrstva: pohledy či templaty (šablony)',
'The Views': 'Pohledy (The Views)',
'There are no controllers': 'Nejsou vytvořeny žádné controllery',
'There are no modules': 'Nejsou přidány žádné moduly',
'There are no plugins': 'Žádné pluginy nejsou instalovány.',
'There are no private files': 'Žádné soukromé soubory neexistují.',
'There are no static files': 'Nejsou přidány žádné statické soubory',
'There are no translators, only default language is supported': 'There are no translators, only default language is supported',
'There are no views': 'Nejsou vytvořeny žádné šablony (views)',
'These files are not served, they are only available from within your app': 'Tyto soubory jsou klientům nepřístupné. K dispozici jsou pouze v rámci aplikace.',
'These files are served without processing, your images go here': 'Tyto soubory jsou servírovány bez přídavné logiky, sem patří např. obrázky.',
'This App': 'Tato aplikace',
'This is a copy of the scaffolding application': 'Toto je kopie aplikace skelet.',
'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk',
'This is the %(filename)s template': 'Toto je šablona %(filename)s',
'this page to see if a breakpoint was hit and debug interaction is required.': 'tuto stránku, abyste uviděli, zda se dosáhlo bodu přerušení.',
'Ticket': 'Tiket',
'Ticket ID': 'ID tiketu',
'Time in Cache (h:m:s)': 'Čas v Cache (h:m:s)',
'Timestamp': 'Časové razítko',
'to previous version.': 'k předchozí verzi.',
'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete soubor/adresář plugin_[jméno modulu]',
'To emulate a breakpoint programatically, write:': 'K nastavení bodu přerušení v kódu programu, napište:',
'to use the debugger!': ', abyste mohli ladící program používat!',
'toggle breakpoint': 'vyp./zap. bod přerušení',
'Toggle Fullscreen': 'Na celou obrazovku a zpět',
'too short': 'Příliš krátké',
'Traceback': 'Hierarchie volání',
'Translation strings for the application': 'Překlad textů pro aplikaci',
'try something like': 'zkuste něco jako',
'Try the mobile interface': 'Zkuste rozhraní pro mobilní zařízení',
'try view': 'vyzkoušet šablonu (view)',
'Twitter': 'Twitter',
'Type python statement in here and hit Return (Enter) to execute it.': 'Type python statement in here and hit Return (Enter) to execute it.',
'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.',
'Unable to check for upgrades': 'Nelze zjistit informaci o aktualizacích',
'unable to parse csv file': 'csv soubor nedá sa zpracovat',
'uncheck all': 'vše odznačit',
'Uninstall': 'Odinstalovat',
'update': 'aktualizovat',
'update all languages': 'aktualizovat všechny jazyky',
'Update:': 'Upravit:',
'Upgrade': 'Upgrade',
'upgrade now': 'upgradovat nyní',
'upgrade now to %s': 'upgradovat nyní na %s',
'upload': 'nahrát',
'Upload': 'Upload (nahrát)',
'Upload a package:': 'Nahrát balík:',
'Upload and install packed application': 'Nahrát a instalovat zabalenou aplikaci',
'upload file:': 'nahrát soubor:',
'upload plugin file:': 'nahrát soubor modulu:',
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT pro sestavení složitějších dotazů.',
'User %(id)s Logged-in': 'Uživatel %(id)s přihlášen',
'User %(id)s Logged-out': 'Uživatel %(id)s odhlášen',
'User %(id)s Password changed': 'Uživatel %(id)s změnil heslo',
'User %(id)s Profile updated': 'Uživatel %(id)s upravil profil',
'User %(id)s Registered': 'Uživatel %(id)s se zaregistroval',
'User %(id)s Username retrieved': 'Uživatel %(id)s si nachal zaslat přihlašovací jméno',
'User ID': 'ID uživatele',
'Username': 'Přihlašovací jméno',
'variables': 'proměnné',
'Verify Password': 'Zopakujte heslo',
'Version': 'Verze',
'Version %s.%s.%s (%s) %s': 'Verze %s.%s.%s (%s) %s',
'Versioning': 'Verzování',
'Videos': 'Videa',
'View': 'Pohled (View)',
'Views': 'Pohledy',
'views': 'pohledy',
'Web Framework': 'Webový framework',
'web2py is up to date': 'Máte aktuální verzi web2py.',
'web2py online debugger': 'Ladící online web2py program',
'web2py Recent Tweets': 'Štěbetání na Twitteru o web2py',
'web2py upgrade': 'aktualizace Web2py',
'web2py upgraded; please restart it': 'Web2py bylo aktualizováno; prosím restarujte jej',
'Welcome': 'Vítejte',
'Welcome to web2py': 'Vitejte ve Web2py aplikaci',
'Welcome to web2py!': 'Vítejte ve Web2py aplikaci.',
'Which called the function %s located in the file %s': 'Tím byla zavolána funkce %s ze souboru (kontroléru) %s.',
'Working...': 'Pracuji...',
'You are successfully running web2py': 'Spustil(a) jsi webový server a Web2py.',
'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Nastavovat a mazat body přerušení je též možno v rámci editování zdrojového souboru přes tlačítko Vyp./Zap. bod přerušení',
'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné',
'You can modify this application and adapt it to your needs': 'V ADMIN rozhraní můžeš Vytvořit novou aplikaci jako kopii ukázkové Welcome aplikace. A začít upravovat: modely, kontroléry, šablony pro URL adresy, které požaduješ.',
'You need to set up and reach a': 'Je třeba nejprve nastavit a dojít až na',
'You visited the url %s': 'Zadal jsi URL adresu %s.',
'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Aplikace bude blokována než se klikne na jedno z tlačítek (další, krok, pokračovat, atd.)',
}

View File

@@ -1,92 +1,132 @@
# -*- coding: utf-8 -*-
#########################################################################
## This scaffolding model makes your app work on Google App Engine too
## File is released under public domain and you can use without limitations
#########################################################################
# -------------------------------------------------------------------------
# This scaffolding model makes your app work on Google App Engine too
# File is released under public domain and you can use without limitations
# -------------------------------------------------------------------------
## if SSL/HTTPS is properly configured and you want all HTTP requests to
## be redirected to HTTPS, uncomment the line below:
if request.global_settings.web2py_version < "2.14.1":
raise HTTP(500, "Requires web2py 2.13.3 or newer")
# -------------------------------------------------------------------------
# if SSL/HTTPS is properly configured and you want all HTTP requests to
# be redirected to HTTPS, uncomment the line below:
# -------------------------------------------------------------------------
# request.requires_https()
## app configuration made easy. Look inside private/appconfig.ini
# -------------------------------------------------------------------------
# app configuration made easy. Look inside private/appconfig.ini
# -------------------------------------------------------------------------
from gluon.contrib.appconfig import AppConfig
## once in production, remove reload=True to gain full speed
# -------------------------------------------------------------------------
# once in production, remove reload=True to gain full speed
# -------------------------------------------------------------------------
myconf = AppConfig(reload=True)
if not request.env.web2py_runtime_gae:
## if NOT running on Google App Engine use SQLite or other DB
db = DAL(myconf.take('db.uri'), pool_size=myconf.take('db.pool_size', cast=int), check_reserved=['all'])
# ---------------------------------------------------------------------
# if NOT running on Google App Engine use SQLite or other DB
# ---------------------------------------------------------------------
db = DAL(myconf.get('db.uri'),
pool_size=myconf.get('db.pool_size'),
migrate_enabled=myconf.get('db.migrate'),
check_reserved=['all'])
else:
## connect to Google BigTable (optional 'google:datastore://namespace')
# ---------------------------------------------------------------------
# connect to Google BigTable (optional 'google:datastore://namespace')
# ---------------------------------------------------------------------
db = DAL('google:datastore+ndb')
## store sessions and tickets there
# ---------------------------------------------------------------------
# store sessions and tickets there
# ---------------------------------------------------------------------
session.connect(request, response, db=db)
## or store session in Memcache, Redis, etc.
## from gluon.contrib.memdb import MEMDB
## from google.appengine.api.memcache import Client
## session.connect(request, response, db = MEMDB(Client()))
# ---------------------------------------------------------------------
# or store session in Memcache, Redis, etc.
# from gluon.contrib.memdb import MEMDB
# from google.appengine.api.memcache import Client
# session.connect(request, response, db = MEMDB(Client()))
# ---------------------------------------------------------------------
## by default give a view/generic.extension to all actions from localhost
## none otherwise. a pattern can be 'controller/function.extension'
# -------------------------------------------------------------------------
# by default give a view/generic.extension to all actions from localhost
# none otherwise. a pattern can be 'controller/function.extension'
# -------------------------------------------------------------------------
response.generic_patterns = ['*'] if request.is_local else []
## choose a style for forms
response.formstyle = myconf.take('forms.formstyle') # or 'bootstrap3_stacked' or 'bootstrap2' or other
response.form_label_separator = myconf.take('forms.separator')
# -------------------------------------------------------------------------
# choose a style for forms
# -------------------------------------------------------------------------
response.formstyle = myconf.get('forms.formstyle') # or 'bootstrap3_stacked' or 'bootstrap2' or other
response.form_label_separator = myconf.get('forms.separator') or ''
## (optional) optimize handling of static files
# -------------------------------------------------------------------------
# (optional) optimize handling of static files
# -------------------------------------------------------------------------
# response.optimize_css = 'concat,minify,inline'
# response.optimize_js = 'concat,minify,inline'
## (optional) static assets folder versioning
# -------------------------------------------------------------------------
# (optional) static assets folder versioning
# -------------------------------------------------------------------------
# response.static_version = '0.0.0'
#########################################################################
## Here is sample code if you need for
## - email capabilities
## - authentication (registration, login, logout, ... )
## - authorization (role based authorization)
## - services (xml, csv, json, xmlrpc, jsonrpc, amf, rss)
## - old style crud actions
## (more options discussed in gluon/tools.py)
#########################################################################
# -------------------------------------------------------------------------
# Here is sample code if you need for
# - email capabilities
# - authentication (registration, login, logout, ... )
# - authorization (role based authorization)
# - services (xml, csv, json, xmlrpc, jsonrpc, amf, rss)
# - old style crud actions
# (more options discussed in gluon/tools.py)
# -------------------------------------------------------------------------
from gluon.tools import Auth, Service, PluginManager
auth = Auth(db)
# host names must be a list of allowed host names (glob syntax allowed)
auth = Auth(db, host_names=myconf.get('host.names'))
service = Service()
plugins = PluginManager()
## create all tables needed by auth if not custom tables
# -------------------------------------------------------------------------
# create all tables needed by auth if not custom tables
# -------------------------------------------------------------------------
auth.define_tables(username=False, signature=False)
## configure email
# -------------------------------------------------------------------------
# configure email
# -------------------------------------------------------------------------
mail = auth.settings.mailer
mail.settings.server = 'logging' if request.is_local else myconf.take('smtp.sender')
mail.settings.sender = myconf.take('smtp.sender')
mail.settings.login = myconf.take('smtp.login')
mail.settings.server = 'logging' if request.is_local else myconf.get('smtp.server')
mail.settings.sender = myconf.get('smtp.sender')
mail.settings.login = myconf.get('smtp.login')
mail.settings.tls = myconf.get('smtp.tls') or False
mail.settings.ssl = myconf.get('smtp.ssl') or False
## configure auth policy
# -------------------------------------------------------------------------
# configure auth policy
# -------------------------------------------------------------------------
auth.settings.registration_requires_verification = False
auth.settings.registration_requires_approval = False
auth.settings.reset_password_requires_verification = True
#########################################################################
## Define your tables below (or better in another model file) for example
##
## >>> db.define_table('mytable',Field('myfield','string'))
##
## Fields can be 'string','text','password','integer','double','boolean'
## 'date','time','datetime','blob','upload', 'reference TABLENAME'
## There is an implicit 'id integer autoincrement' field
## Consult manual for more options, validators, etc.
##
## More API examples for controllers:
##
## >>> db.mytable.insert(myfield='value')
## >>> rows=db(db.mytable.myfield=='value').select(db.mytable.ALL)
## >>> for row in rows: print row.id, row.myfield
#########################################################################
# -------------------------------------------------------------------------
# Define your tables below (or better in another model file) for example
#
# >>> db.define_table('mytable', Field('myfield', 'string'))
#
# Fields can be 'string','text','password','integer','double','boolean'
# 'date','time','datetime','blob','upload', 'reference TABLENAME'
# There is an implicit 'id integer autoincrement' field
# Consult manual for more options, validators, etc.
#
# More API examples for controllers:
#
# >>> db.mytable.insert(myfield='value')
# >>> rows = db(db.mytable.myfield == 'value').select(db.mytable.ALL)
# >>> for row in rows: print row.id, row.myfield
# -------------------------------------------------------------------------
## after defining tables, uncomment below to enable auditing
# -------------------------------------------------------------------------
# after defining tables, uncomment below to enable auditing
# -------------------------------------------------------------------------
# auth.enable_record_versioning(db)

View File

@@ -1,28 +1,32 @@
# -*- coding: utf-8 -*-
# this file is released under public domain and you can use without limitations
#########################################################################
## Customize your APP title, subtitle and menus here
#########################################################################
# ----------------------------------------------------------------------------------------------------------------------
# Customize your APP title, subtitle and menus here
# ----------------------------------------------------------------------------------------------------------------------
response.logo = A(B('web',SPAN(2),'py'),XML('&trade;&nbsp;'),
_class="navbar-brand",_href="http://www.web2py.com/",
response.logo = A(B('web', SPAN(2), 'py'), XML('&trade;&nbsp;'),
_class="navbar-brand", _href="http://www.web2py.com/",
_id="web2py-logo")
response.title = request.application.replace('_',' ').title()
response.title = request.application.replace('_', ' ').title()
response.subtitle = ''
## read more at http://dev.w3.org/html5/markup/meta.name.html
response.meta.author = 'Your Name <you@example.com>'
response.meta.description = 'a cool new app'
response.meta.keywords = 'web2py, python, framework'
response.meta.generator = 'Web2py Web Framework'
# ----------------------------------------------------------------------------------------------------------------------
# read more at http://dev.w3.org/html5/markup/meta.name.html
# ----------------------------------------------------------------------------------------------------------------------
response.meta.author = myconf.get('app.author')
response.meta.description = myconf.get('app.description')
response.meta.keywords = myconf.get('app.keywords')
response.meta.generator = myconf.get('app.generator')
## your http://google.com/analytics id
# ----------------------------------------------------------------------------------------------------------------------
# your http://google.com/analytics id
# ----------------------------------------------------------------------------------------------------------------------
response.google_analytics_id = None
#########################################################################
## this is the main application menu add/remove items as required
#########################################################################
# ----------------------------------------------------------------------------------------------------------------------
# this is the main application menu add/remove items as required
# ----------------------------------------------------------------------------------------------------------------------
response.menu = [
(T('Home'), False, URL('default', 'index'), [])
@@ -30,109 +34,118 @@ response.menu = [
DEVELOPMENT_MENU = True
#########################################################################
## provide shortcuts for development. remove in production
#########################################################################
# ----------------------------------------------------------------------------------------------------------------------
# provide shortcuts for development. remove in production
# ----------------------------------------------------------------------------------------------------------------------
def _():
# ------------------------------------------------------------------------------------------------------------------
# shortcuts
# ------------------------------------------------------------------------------------------------------------------
app = request.application
ctr = request.controller
# ------------------------------------------------------------------------------------------------------------------
# useful links to internal and external resources
# ------------------------------------------------------------------------------------------------------------------
response.menu += [
(T('My Sites'), False, URL('admin', 'default', 'site')),
(T('This App'), False, '#', [
(T('Design'), False, URL('admin', 'default', 'design/%s' % app)),
LI(_class="divider"),
(T('Controller'), False,
URL(
'admin', 'default', 'edit/%s/controllers/%s.py' % (app, ctr))),
(T('View'), False,
URL(
'admin', 'default', 'edit/%s/views/%s' % (app, response.view))),
(T('DB Model'), False,
URL(
'admin', 'default', 'edit/%s/models/db.py' % app)),
(T('Menu Model'), False,
URL(
'admin', 'default', 'edit/%s/models/menu.py' % app)),
(T('Config.ini'), False,
URL(
'admin', 'default', 'edit/%s/private/appconfig.ini' % app)),
(T('Layout'), False,
URL(
'admin', 'default', 'edit/%s/views/layout.html' % app)),
(T('Stylesheet'), False,
URL(
'admin', 'default', 'edit/%s/static/css/web2py-bootstrap3.css' % app)),
(T('Database'), False, URL(app, 'appadmin', 'index')),
(T('Errors'), False, URL(
'admin', 'default', 'errors/' + app)),
(T('About'), False, URL(
'admin', 'default', 'about/' + app)),
]),
('web2py.com', False, '#', [
(T('Download'), False,
'http://www.web2py.com/examples/default/download'),
(T('Support'), False,
'http://www.web2py.com/examples/default/support'),
(T('Demo'), False, 'http://web2py.com/demo_admin'),
(T('Quick Examples'), False,
'http://web2py.com/examples/default/examples'),
(T('FAQ'), False, 'http://web2py.com/AlterEgo'),
(T('Videos'), False,
'http://www.web2py.com/examples/default/videos/'),
(T('Free Applications'),
False, 'http://web2py.com/appliances'),
(T('Plugins'), False, 'http://web2py.com/plugins'),
(T('Recipes'), False, 'http://web2pyslices.com/'),
]),
(T('Documentation'), False, '#', [
(T('Online book'), False, 'http://www.web2py.com/book'),
LI(_class="divider"),
(T('Preface'), False,
'http://www.web2py.com/book/default/chapter/00'),
(T('Introduction'), False,
'http://www.web2py.com/book/default/chapter/01'),
(T('Python'), False,
'http://www.web2py.com/book/default/chapter/02'),
(T('Overview'), False,
'http://www.web2py.com/book/default/chapter/03'),
(T('The Core'), False,
'http://www.web2py.com/book/default/chapter/04'),
(T('The Views'), False,
'http://www.web2py.com/book/default/chapter/05'),
(T('Database'), False,
'http://www.web2py.com/book/default/chapter/06'),
(T('Forms and Validators'), False,
'http://www.web2py.com/book/default/chapter/07'),
(T('Email and SMS'), False,
'http://www.web2py.com/book/default/chapter/08'),
(T('Access Control'), False,
'http://www.web2py.com/book/default/chapter/09'),
(T('Services'), False,
'http://www.web2py.com/book/default/chapter/10'),
(T('Ajax Recipes'), False,
'http://www.web2py.com/book/default/chapter/11'),
(T('Components and Plugins'), False,
'http://www.web2py.com/book/default/chapter/12'),
(T('Deployment Recipes'), False,
'http://www.web2py.com/book/default/chapter/13'),
(T('Other Recipes'), False,
'http://www.web2py.com/book/default/chapter/14'),
(T('Helping web2py'), False,
'http://www.web2py.com/book/default/chapter/15'),
(T("Buy web2py's book"), False,
'http://stores.lulu.com/web2py'),
]),
(T('Community'), False, None, [
(T('Groups'), False,
'http://www.web2py.com/examples/default/usergroups'),
(T('Twitter'), False, 'http://twitter.com/web2py'),
(T('Live Chat'), False,
'http://webchat.freenode.net/?channels=web2py'),
]),
]
if DEVELOPMENT_MENU: _()
(T('This App'), False, '#', [
(T('Design'), False, URL('admin', 'default', 'design/%s' % app)),
LI(_class="divider"),
(T('Controller'), False,
URL(
'admin', 'default', 'edit/%s/controllers/%s.py' % (app, ctr))),
(T('View'), False,
URL(
'admin', 'default', 'edit/%s/views/%s' % (app, response.view))),
(T('DB Model'), False,
URL(
'admin', 'default', 'edit/%s/models/db.py' % app)),
(T('Menu Model'), False,
URL(
'admin', 'default', 'edit/%s/models/menu.py' % app)),
(T('Config.ini'), False,
URL(
'admin', 'default', 'edit/%s/private/appconfig.ini' % app)),
(T('Layout'), False,
URL(
'admin', 'default', 'edit/%s/views/layout.html' % app)),
(T('Stylesheet'), False,
URL(
'admin', 'default', 'edit/%s/static/css/web2py-bootstrap3.css' % app)),
(T('Database'), False, URL(app, 'appadmin', 'index')),
(T('Errors'), False, URL(
'admin', 'default', 'errors/' + app)),
(T('About'), False, URL(
'admin', 'default', 'about/' + app)),
]),
('web2py.com', False, '#', [
(T('Download'), False,
'http://www.web2py.com/examples/default/download'),
(T('Support'), False,
'http://www.web2py.com/examples/default/support'),
(T('Demo'), False, 'http://web2py.com/demo_admin'),
(T('Quick Examples'), False,
'http://web2py.com/examples/default/examples'),
(T('FAQ'), False, 'http://web2py.com/AlterEgo'),
(T('Videos'), False,
'http://www.web2py.com/examples/default/videos/'),
(T('Free Applications'),
False, 'http://web2py.com/appliances'),
(T('Plugins'), False, 'http://web2py.com/plugins'),
(T('Recipes'), False, 'http://web2pyslices.com/'),
]),
(T('Documentation'), False, '#', [
(T('Online book'), False, 'http://www.web2py.com/book'),
LI(_class="divider"),
(T('Preface'), False,
'http://www.web2py.com/book/default/chapter/00'),
(T('Introduction'), False,
'http://www.web2py.com/book/default/chapter/01'),
(T('Python'), False,
'http://www.web2py.com/book/default/chapter/02'),
(T('Overview'), False,
'http://www.web2py.com/book/default/chapter/03'),
(T('The Core'), False,
'http://www.web2py.com/book/default/chapter/04'),
(T('The Views'), False,
'http://www.web2py.com/book/default/chapter/05'),
(T('Database'), False,
'http://www.web2py.com/book/default/chapter/06'),
(T('Forms and Validators'), False,
'http://www.web2py.com/book/default/chapter/07'),
(T('Email and SMS'), False,
'http://www.web2py.com/book/default/chapter/08'),
(T('Access Control'), False,
'http://www.web2py.com/book/default/chapter/09'),
(T('Services'), False,
'http://www.web2py.com/book/default/chapter/10'),
(T('Ajax Recipes'), False,
'http://www.web2py.com/book/default/chapter/11'),
(T('Components and Plugins'), False,
'http://www.web2py.com/book/default/chapter/12'),
(T('Deployment Recipes'), False,
'http://www.web2py.com/book/default/chapter/13'),
(T('Other Recipes'), False,
'http://www.web2py.com/book/default/chapter/14'),
(T('Helping web2py'), False,
'http://www.web2py.com/book/default/chapter/15'),
(T("Buy web2py's book"), False,
'http://stores.lulu.com/web2py'),
]),
(T('Community'), False, None, [
(T('Groups'), False,
'http://www.web2py.com/examples/default/usergroups'),
(T('Twitter'), False, 'http://twitter.com/web2py'),
(T('Live Chat'), False,
'http://webchat.freenode.net/?channels=web2py'),
]),
]
if "auth" in locals(): auth.wikimenu()
if DEVELOPMENT_MENU:
_()
if "auth" in locals():
auth.wikimenu()

View File

@@ -1,17 +1,28 @@
; App configuration
[app]
name = Welcome
author = Your Name <you@example.com>
description = a cool new app
keywords = web2py, python, framework
generator = Web2py Web Framework
; Host configuration
[host]
names = localhost:*, 127.0.0.1:*, *:*, *
; db configuration
[db]
uri = sqlite://storage.sqlite
migrate = 1
pool_size = 1
migrate = true
pool_size = 10 ; ignored for sqlite
; smtp address and credentials
[smtp]
server = smtp.gmail.com:587
sender = you@gmail.com
login = username:password
tls = true
ssl = true
; form styling
[forms]

View File

@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
# ----------------------------------------------------------------------------------------------------------------------
# This is an app-specific example router
#
# This simple router is used for setting languages from app/languages directory
@@ -7,32 +8,34 @@
# Language from default.py or 'en' (if the file is not found) is used as
# a default_language
#
# See <web2py-root-dir>/router.example.py for parameter's detail
#-------------------------------------------------------------------------------------
# See <web2py-root-dir>/examples/routes.parametric.example.py for parameter's detail
# ----------------------------------------------------------------------------------------------------------------------
# ----------------------------------------------------------------------------------------------------------------------
# To enable this route file you must do the steps:
#
# 1. rename <web2py-root-dir>/router.example.py to routes.py
# 2. rename this APP/routes.example.py to APP/routes.py
# (where APP - is your application directory)
# 3. restart web2py (or reload routes in web2py admin interfase)
# 1. rename <web2py-root-dir>/examples/routes.parametric.example.py to routes.py
# 2. rename this APP/routes.example.py to APP/routes.py (where APP - is your application directory)
# 3. restart web2py (or reload routes in web2py admin interface)
#
# YOU CAN COPY THIS FILE TO ANY APPLICATION'S ROOT DIRECTORY WITHOUT CHANGES!
# ----------------------------------------------------------------------------------------------------------------------
from fileutils import abspath
from languages import read_possible_languages
possible_languages = read_possible_languages(abspath('applications', app))
#NOTE! app - is an application based router's parameter with name of an
# application. E.g.'welcome'
# ----------------------------------------------------------------------------------------------------------------------
# NOTE! app - is an application based router's parameter with name of an application. E.g.'welcome'
# ----------------------------------------------------------------------------------------------------------------------
routers = {
app: dict(
default_language = possible_languages['default'][0],
languages = [lang for lang in possible_languages
if lang != 'default']
default_language=possible_languages['default'][0],
languages=[lang for lang in possible_languages if lang != 'default']
)
}
#NOTE! To change language in your application using these rules add this line
#in one of your models files:
# ----------------------------------------------------------------------------------------------------------------------
# NOTE! To change language in your application using these rules add this line in one of your models files:
# ----------------------------------------------------------------------------------------------------------------------
# if request.uri_language: T.force(request.uri_language)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
div.flash {
div.w2p_flash {
background-image: none;
border-radius: 4px;
-o-border-radius: 4px;
@@ -15,16 +15,18 @@ div.flash {
margin: 0 0 20px;
padding: 15px 35px 15px 15px;
}
div.flash.alert:hover {
div.w2p_flash.alert:hover {
opacity: 1;
}
.ie-lte8 div.flash {
.ie-lte8 div.w2p_flash {
filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0);
}
.ie-lte8 div.flash:hover {
.ie-lte8 div.w2p_flash:hover {
filter: alpha(opacity=25);
}
.main-container {
margin-top: 20px;
}
div.error {
width: auto;
@@ -35,7 +37,7 @@ div.error {
display: inline-block;
padding: 5px;
}
div.flash.alert {
div.w2p_flash.alert {
display: none;
position: fixed;
top: 70px;
@@ -106,7 +108,7 @@ select.autocomplete {
background: url(../images/background.jpg) no-repeat center center;
}
body {
padding-top: 50px;
padding-top: 60px;
margin-bottom: 60px;
}
header {
@@ -134,7 +136,7 @@ header h1 {
header .jumbotron {
background-color: transparent;
}
.flash {
.w2p_flash {
opacity: 0.9!important;
right: 100px;
}
@@ -231,7 +233,7 @@ div.error_wrapper {
line-height: 20px;
margin-right: 2px;
display: inline-block;
padding: 3px 5px;
padding: 6px 12px;
}
.web2py_counter {
margin-top: 5px;
@@ -268,6 +270,7 @@ li.w2p_grid_breadcrumb_elem {
.web2py_console select,
.web2py_console a {
margin: 2px;
padding: 6px 12px;
}
#wiki_page_body {
width: 600px;
@@ -283,6 +286,7 @@ li.w2p_grid_breadcrumb_elem {
.web2py_console .form-control {
width: 20%;
display: inline;
height: 32px;
}
.web2py_console #w2p_keywords {
width: 50%;
@@ -311,6 +315,3 @@ td.w2p_fc,
input[type=checkbox], input[type=radio] {
margin: 4px 4px 0 0;
}
.btn {
margin-right: 4px;
}

View File

@@ -33,7 +33,7 @@ audio {width:200px}
[type="text"], [type="password"], select {
margin-right: 5px; width: 300px;
}
.hidden {display:none;visibility:visible}
.w2p_hidden {display:none;visibility:visible}
.right {float:right; text-align:right}
.left {float:left; text-align:left}
.center {width:100%; text-align:center; vertical-align:middle}
@@ -88,7 +88,7 @@ div.w2p_export_menu a, div.w2p_wiki_tags a, div.w2p_cloud a {margin-left:5px; pa
#web2py_user_form td {vertical-align:top}
/*********** web2py specific ***********/
div.flash {
div.w2p_flash {
font-weight:bold;
display:none;
position:fixed;
@@ -117,11 +117,11 @@ div.flash {
z-index:2000;
}
div.flash #closeflash{color:inherit; float:right; margin-left:15px;}
div.w2p_flash #closeflash{color:inherit; float:right; margin-left:15px;}
.ie-lte7 div.flash #closeflash
{color:expression(this.parentNode.currentStyle['color']);float:none;position:absolute;right:4px;}
div.flash:hover { opacity:0.25; }
div.w2p_flash:hover { opacity:0.25; }
div.error_wrapper {display:block}
div.error {
@@ -304,8 +304,8 @@ li.w2p_grid_breadcrumb_elem {
/* fix some IE problems */
.ie-lte7 .topbar .container {z-index:2}
.ie-lte8 div.flash{ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0 ); }
.ie-lte8 div.flash:hover {filter:alpha(opacity=25);}
.ie-lte8 div.w2p_flash{ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0 ); }
.ie-lte8 div.w2p_flash:hover {filter:alpha(opacity=25);}
.ie9 #w2p_query_panel {padding-bottom:2px}
.web2py_console .form-control {width: 20%; display: inline;}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -6,9 +6,9 @@
* this over and over... all will be bound to the document
*/
/*adds btn class to buttons*/
$('button', target).addClass('btn btn-default');
$('button:not([class^="btn"])', target).addClass('btn btn-default');
$("p.w2p-autocomplete-widget input").addClass('form-control');
$('form input[type="submit"], form input[type="button"]', target).addClass('btn btn-default');
$('form input[type="submit"]:not([class^="btn"]), form input[type="button"]:not([class^="btn"])', target).addClass('btn btn-default');
/* javascript for PasswordWidget*/
$('input[type=password][data-w2p_entropy]', target).each(function() {
web2py.validate_entropy($(this));
@@ -18,9 +18,9 @@
function pe(ul, e) {
var new_line = ml(ul);
rel(ul);
if ($(e.target).parent().is(':visible')) {
if ($(e.target).closest('li').is(':visible')) {
/* make sure we didn't delete the element before we insert after */
new_line.insertAfter($(e.target).parent());
new_line.insertAfter($(e.target).closest('li'));
} else {
/* the line we clicked on was deleted, just add to end of list */
new_line.appendTo(ul);
@@ -30,9 +30,9 @@
}
function rl(ul, e) {
if ($(ul).children().length > 1) {
if ($(ul).find('li').length > 1) {
/* only remove if we have more than 1 item so the list is never empty */
$(e.target).parent().remove();
$(e.target).closest('li').remove();
}
}
@@ -46,13 +46,13 @@
function rel(ul) {
/* keep only as many as needed*/
$(ul).find("li").each(function() {
var trimmed = $.trim($(this.firstChild).val());
var trimmed = $.trim($(this).find(":text").val());
if (trimmed == '') $(this).remove();
else $(this.firstChild).val(trimmed);
else $(this).find(":text").val(trimmed);
});
}
var ul = this;
$(ul).find(":text").after('<a class="btn btn-default" href="#">+</a>&nbsp;<a class="btn btn-default" href="#">-</a>').keypress(function(e) {
$(ul).find(":text").addClass('form-control').wrap("<div class='input-group'></div>").after('<div class="input-group-addon"><i class="glyphicon glyphicon-plus"></i></div><div class="input-group-addon"><i class="glyphicon glyphicon-minus"></i></div>').keypress(function(e) {
return (e.which == 13) ? pe(ul, e) : true;
}).next().click(function(e) {
pe(ul, e);

File diff suppressed because it is too large Load Diff

View File

@@ -137,9 +137,9 @@
<h4>{{=T("Overview")}}</h4>
<p>{{=T.M("Number of entries: **%s**", total['entries'])}}</p>
{{if total['entries'] > 0:}}
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses})",
dict(ratio=total['ratio'], hits=total['hits'], misses=total['misses']))}}
</p>
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})",
dict( ratio=total['ratio'], hits=total['hits'], misses=total['misses']))}}
</p>
<p>
{{=T("Size of cache:")}}
{{if object_stats:}}
@@ -155,8 +155,8 @@
{{=T.M("Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
dict(hours=total['oldest'][0], min=total['oldest'][1], sec=total['oldest'][2]))}}
</p>
{{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle();')}}
<div class="hidden" id="all_keys">
{{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle().toggleClass( "w2p_hidden" );')}}
<div class="w2p_hidden" id="all_keys">
{{=total['keys']}}
</div>
<br />
@@ -183,8 +183,8 @@
{{=T.M("RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
dict(hours=ram['oldest'][0], min=ram['oldest'][1], sec=ram['oldest'][2]))}}
</p>
{{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle();')}}
<div class="hidden" id="ram_keys">
{{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle().toggleClass( "w2p_hidden" );')}}
<div class="w2p_hidden" id="ram_keys">
{{=ram['keys']}}
</div>
<br />
@@ -212,8 +212,8 @@
{{=T.M("DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
dict(hours=disk['oldest'][0], min=disk['oldest'][1], sec=disk['oldest'][2]))}}
</p>
{{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle();')}}
<div class="hidden" id="disk_keys">
{{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle().toggleClass( "w2p_hidden" );')}}
<div class="w2p_hidden" id="disk_keys">
{{=disk['keys']}}
</div>
<br />
@@ -249,8 +249,8 @@
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['png'])}}">png</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['svg'])}}">svg</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['pdf'])}}">pdf</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['ps'])}}">ps</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['dot'])}}">dot</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['ps'])}}">ps</a></li>
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['dot'])}}">dot</a></li>
</ul>
</div>
<br />

View File

@@ -21,7 +21,6 @@
<meta name="google-site-verification" content="">
<!-- include stylesheets -->
<link rel="stylesheet" href="{{=URL('static','css/bootstrap.min.css')}}"/>
<link rel="stylesheet" href="{{=URL('static','css/bootstrap-theme.min.css')}}"/>
<link rel="stylesheet" href="{{=URL('static','css/web2py-bootstrap3.css')}}"/>
<link rel="shortcut icon" href="{{=URL('static','images/favicon.ico')}}" type="image/x-icon">
<link rel="apple-touch-icon" href="{{=URL('static','images/favicon.png')}}">
@@ -47,9 +46,9 @@
</head>
<body>
<!--[if lt IE 8]><p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p><![endif]-->
<div class="flash alert alert-dismissable">{{=response.flash or ''}}</div>
<div class="w2p_flash alert alert-dismissable">{{=response.flash or ''}}</div>
<!-- Navbar ======================================= -->
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
@@ -75,7 +74,7 @@
{{end}}
<!-- Main ========================================= -->
<!-- Begin page content -->
<div class="container-fluid">
<div class="container-fluid main-container">
{{if left_sidebar_enabled:}}
<div class="col-md-3 left-sidebar">
{{block left_sidebar}}

25
appveyor.yml Normal file
View File

@@ -0,0 +1,25 @@
build: false
environment:
matrix:
- PYTHON: "C:/Python27"
COVERAGE_PROCESS_START: gluon/tests/coverage.ini
clone_depth: 50
init:
- "ECHO %PYTHON%"
- set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH%
install:
- ps: Start-FileDownload https://bootstrap.pypa.io/get-pip.py
- python get-pip.py
- pip install codecov
- git submodule update --init --recursive
test_script:
- python web2py.py --run_system_tests --with_coverage
after_test:
- coverage combine
- codecov

View File

@@ -120,7 +120,7 @@ args=()
class=handlers.RotatingFileHandler
level=DEBUG
formatter=simpleFormatter
args=("logs/web2py.log", "a", 1000000, 5)
args=("web2py.log", "a", 1000000, 5)
[handler_osxSysLogHandler]
class=handlers.SysLogHandler

46
examples/web.config Normal file
View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!-- app configuration for web2py on IIS -->
<configuration>
<appSettings>
<add key="WSGI_HANDLER" value="gluon.main.wsgibase" />
<add key="WSGI_RESTART_FILE_REGEX" value=".*((routes\.py)|(\.config))$" />
</appSettings>
<system.webServer>
<rewrite>
<rules>
<clear />
<rule name="static" enabled="true" stopProcessing="true">
<match url="^(\w+)/static(?:/_[\d]+\.[\d]+\.[\d]+)?/(.*)$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="Rewrite" url="applications/{R:1}/static/{R:2}" logRewrittenUrl="false" />
</rule>
<rule name="web2py_app" enabled="true" stopProcessing="true">
<match url="(.*)" ignoreCase="false" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="Rewrite" url="handler.web2py/{R:1}" appendQueryString="true" />
</rule>
</rules>
<outboundRules>
<rule name="static_version_cache_control" preCondition="static_version">
<match serverVariable="RESPONSE_Cache-Control" pattern=".*" />
<action type="Rewrite" value="max-age=315360000" />
<conditions>
</conditions>
</rule>
<rule name="static_version_Expires" preCondition="static_version">
<match serverVariable="RESPONSE_Expires" pattern=".*" />
<action type="Rewrite" value="Thu, 31 Dec 2037 23:59:59 GMT" />
</rule>
<preConditions>
<preCondition name="static_version">
<add input="{REQUEST_URI}" pattern="(\w+)/static(?:/_[\d]+\.[\d]+\.[\d]+)?/(.*)$" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
<handlers>
<!-- replace SCRIPT_PROCESSOR with the configured handler for python -->
<add name="Python_via_FastCGI" path="handler.web2py" verb="*" modules="FastCgiModule" scriptProcessor="SCRIPT_PROCESSOR" resourceType="Unspecified" requireAccess="Script" />
</handlers>
</system.webServer>
</configuration>

158
fabfile.py vendored Normal file
View File

@@ -0,0 +1,158 @@
from fabric.api import *
from fabric.operations import put, get
from fabric.contrib.files import exists
import os
import datetime
import getpass
if os.path.exists('hosts'):
env.hosts = [h.strip() for h in open('hosts').readlines() if h.strip()]
env.hosts = env.hosts or raw_input('hostname (example.com):').split(',')
env.user = env.user or raw_input('username :')
INSTALL_SCRIPT = "setup-web2py-nginx-uwsgi-ubuntu.sh"
now = datetime.datetime.now()
applications = '/home/www-data/web2py/applications'
def create_user(username):
"""fab -H root@host create_user:username"""
password = getpass.getpass(name+' password for %s> ' % username)
run('useradd -m %s' % username)
run('usermod --password %s %s' % (crypt.crypt(password, 'salt'), username))
run('mkdir -p ~%s/.ssh' % username)
run('cp /etc/sudoers /tmp/sudoers.new')
append('/tmp/sudoers.new', '%s ALL=NOPASSWD: ALL' % username, use_sudo=True)
run('visudo -c -f /tmp/sudoers.new')
run('EDITOR="cp /tmp/sudoers.new" visudo')
uncomment('~%s/.bashrc' % username, '#force_color_prompt=yes')
local('ssh-copy-id %s' % env.hosts[0])
def install_web2py():
"""fab -H username@host install_web2py"""
sudo('wget https://raw.githubusercontent.com/web2py/web2py/master/scripts/%s' % INSTALL_SCRIPT)
sudo('chmod +x %s' % INSTALL_SCRIPT)
sudo('./'+INSTALL_SCRIPT)
def start_webserver():
sudo('service nginx start')
sudo('start uwsgi-emperor')
sudo('start web2py-scheduler')
def stop_webserver():
sudo('stop uwsgi-emperor')
sudo('service nginx stop')
sudo('stop web2py-scheduler')
def restart_webserver():
stop_webserver()
start_webserver()
def notify(appname=None):
"""fab -H username@host notify:appname"""
appname = appname or os.path.split(os.getcwd())[-1]
appfolder = applications+'/'+appname
with cd(appfolder):
sudo('echo "response.flash = \'System Going Down For Maintenance\'" > models/flash_goingdown.py')
def down(appname=None):
"""fab -H username@host down:appname"""
appname = appname or os.path.split(os.getcwd())[-1]
appfolder = applications+'/'+appname
with cd(appfolder):
sudo('echo `date` > DISABLED')
sudo('rm -rf sessions/* || true')
def up(appname=None):
"""fab -H username@host up:appname"""
appname = appname or os.path.split(os.getcwd())[-1]
appfolder = applications+'/'+appname
with cd(appfolder):
if exists('modules/flash_goingdown.py'):
sudo('rm modules/flash_goingdown.py')
sudo('rm DISABLED')
def mkdir_or_backup(appname):
appfolder = applications+'/'+appname
if not exists(appfolder):
sudo('mkdir %s' % appfolder)
sudo('chown -R www-data:www-data %s' % appfolder)
backup = None
else:
dt = now.strftime('%y-%m-%d-%h-%m')
backup = '%s.%s.zip' % (appname, dt)
with cd(applications):
sudo('zip -r %s %s' % (backup, appname))
return backup
def git_deploy(appname, repo):
"""fab -H username@host git_deploy:appname,username/remoname"""
appfolder = applications+'/'+appname
backup = mkdir_or_backup(appname)
if exists(appfolder):
with cd(appfolder):
sudo('git pull origin master')
sudo('chown -R www-data:www-data *')
else:
with cd(applications):
sudo('git clone git@github.com/%s %s' % (repo, name))
sudo('chown -R www-data:www-data %s' % name)
def retrieve(appname=None):
"""fab -H username@host retrieve:appname"""
appname = appname or os.path.split(os.getcwd())[-1]
appfolder = applications+'/'+appname
filename = '%s.zip' % appname
with cd(appfolder):
sudo('zip -r /tmp/%s *' % filename)
get('/tmp/%s' % filename, filename)
sudo('rm /tmp/%s' % filename)
local('unzip %s' % filename)
local('rm %s' % filename)
def deploy(appname=None, all=False):
"""fab -H username@host deploy:appname,all"""
appname = appname or os.path.split(os.getcwd())[-1]
appfolder = applications+'/'+appname
zipfile = os.path.join(appfolder, '_update.zip')
if os.path.exists(zipfile):
os.unlink(zipfile)
backup = mkdir_or_backup(appname)
if all=='all' or not backup:
local('zip -r _update.zip * -x *~ -x .* -x \#* -x *.bak -x *.bak2')
else:
local('zip -r _update.zip */*.py views/*.html views/*/*.html static/*')
put('_update.zip','/tmp/_update.zip')
try:
with cd(appfolder):
sudo('unzip -o /tmp/_update.zip')
sudo('chown -R www-data:www-data *')
sudo('echo "%s" > DATE_DEPLOYMENT' % now)
finally:
sudo('rm /tmp/_update.zip')
if backup:
print 'TO RESTORE: fab restore:%s' % backup
def restore(backup):
"""fab -H username@host restore:backupfilename"""
appname = backup.split('/')[-1].split('.')[0]
appfolder = applications + '/' + appname
with cd(appfolder):
sudo('rm -r *')
with cd(applications):
sudo('unzip %s' % backup)
sudo('chown -R www-data:www-data %s' % appname)
def cleanup(appname):
appname = appname or os.path.split(os.getcwd())[-1]
appfolder = applications + '/' + appname
with cd(appfolder):
sudo('rm -rf sessions/* || true')
sudo('rm -rf errors/* || true')
sudo('rm -rf cache/* || true')

View File

@@ -21,6 +21,7 @@ from gluon.fileutils import up, fix_newlines, abspath, recursive_unlink
from gluon.fileutils import read_file, write_file, parse_version
from gluon.restricted import RestrictedError
from gluon.settings import global_settings
from gluon.cache import CacheOnDisk
if not global_settings.web2py_runtime_gae:
@@ -58,6 +59,8 @@ def app_pack(app, request, raise_ex=False, filenames=None):
w2p_pack(filename, apath(app, request), filenames=filenames)
return filename
except Exception, e:
import traceback
print traceback.format_exc()
if raise_ex:
raise
return False
@@ -113,21 +116,22 @@ def app_cleanup(app, request):
for f in os.listdir(path):
try:
if f[:1] != '.': recursive_unlink(os.path.join(path, f))
except IOError:
except (OSError, IOError):
r = False
# Remove cache files
path = apath('%s/cache/' % app, request)
if os.path.exists(path):
CacheOnDisk(folder=path).clear()
for f in os.listdir(path):
try:
if f[:1] != '.': recursive_unlink(os.path.join(path, f))
except IOError:
except (OSError, IOError):
r = False
return r
def app_compile(app, request):
def app_compile(app, request, skip_failed_views=False):
"""Compiles the application
Args:
@@ -141,10 +145,10 @@ def app_compile(app, request):
from compileapp import compile_application, remove_compiled_application
folder = apath(app, request)
try:
compile_application(folder)
return None
failed_views = compile_application(folder, skip_failed_views)
return failed_views
except (Exception, RestrictedError):
tb = traceback.format_exc(sys.exc_info)
tb = traceback.format_exc()
remove_compiled_application(folder)
return tb
@@ -163,7 +167,7 @@ def app_create(app, request, force=False, key=None, info=False):
os.mkdir(path)
except:
if info:
return False, traceback.format_exc(sys.exc_info)
return False, traceback.format_exc()
else:
return False
elif not force:
@@ -193,7 +197,7 @@ def app_create(app, request, force=False, key=None, info=False):
except:
rmtree(path)
if info:
return False, traceback.format_exc(sys.exc_info)
return False, traceback.format_exc()
else:
return False

View File

@@ -44,9 +44,9 @@ except ImportError:
have_settings = False
try:
import cPickle as pickle
import cPickle as pickle
except:
import pickle
import pickle
try:
import psutil
@@ -54,11 +54,12 @@ try:
except ImportError:
HAVE_PSUTIL = False
def remove_oldest_entries(storage, percentage=90):
# compute current memory usage (%)
old_mem = psutil.virtual_memory().percent
# if we have data in storage and utilization exceeds 90%
while storage and old_mem > percentage:
while storage and old_mem > percentage:
# removed oldest entry
storage.popitem(last=False)
# garbage collect
@@ -66,7 +67,8 @@ def remove_oldest_entries(storage, percentage=90):
# comute used memory again
new_mem = psutil.virtual_memory().percent
# if the used memory did not decrease stop
if new_mem >= old_mem: break
if new_mem >= old_mem:
break
# net new measurement for memory usage and loop
old_mem = new_mem
@@ -78,6 +80,7 @@ __all__ = ['Cache', 'lazy_cache']
DEFAULT_TIME_EXPIRE = 300
class CacheAbstract(object):
"""
Abstract class for cache implementations.
@@ -99,7 +102,7 @@ class CacheAbstract(object):
"""
cache_stats_name = 'web2py_cache_statistics'
max_ram_utilization = 90 # percent
max_ram_utilization = None # percent
def __init__(self, request=None):
"""Initializes the object
@@ -182,13 +185,14 @@ class CacheInRam(CacheAbstract):
self.request = request
self.storage = OrderedDict() if HAVE_PSUTIL else {}
self.app = request.application if request else ''
def initialize(self):
if self.initialized:
return
else:
self.initialized = True
self.locker.acquire()
if not self.app in self.meta_storage:
if self.app not in self.meta_storage:
self.storage = self.meta_storage[self.app] = \
OrderedDict() if HAVE_PSUTIL else {}
self.stats[self.app] = {'hit_total': 0, 'misses': 0}
@@ -205,7 +209,7 @@ class CacheInRam(CacheAbstract):
else:
self._clear(storage, regex)
if not self.app in self.stats:
if self.app not in self.stats:
self.stats[self.app] = {'hit_total': 0, 'misses': 0}
self.locker.release()
@@ -251,8 +255,8 @@ class CacheInRam(CacheAbstract):
self.locker.acquire()
self.storage[key] = (now, value)
self.stats[self.app]['misses'] += 1
if HAVE_PSUTIL and self.max_ram_utilization!=None and random.random()<0.10:
remove_oldest_entries(self.storage, percentage = self.max_ram_utilization)
if HAVE_PSUTIL and self.max_ram_utilization is not None and random.random() < 0.10:
remove_oldest_entries(self.storage, percentage=self.max_ram_utilization)
self.locker.release()
return value
@@ -292,14 +296,15 @@ class CacheOnDisk(CacheAbstract):
self.folder = folder
self.key_filter_in = lambda key: key
self.key_filter_out = lambda key: key
self.file_lock_time_wait = file_lock_time_wait # How long we should wait before retrying to lock a file held by another process
self.file_lock_time_wait = file_lock_time_wait
# How long we should wait before retrying to lock a file held by another process
# We still need a mutex for each file as portalocker only blocks other processes
self.file_locks = defaultdict(thread.allocate_lock)
# Make sure we use valid filenames.
if sys.platform == "win32":
import base64
def key_filter_in_windows(key):
"""
Windows doesn't allow \ / : * ? "< > | in filenames.
@@ -316,7 +321,6 @@ class CacheOnDisk(CacheAbstract):
self.key_filter_in = key_filter_in_windows
self.key_filter_out = key_filter_out_windows
def wait_portalock(self, val_file):
"""
Wait for the process file lock.
@@ -328,15 +332,12 @@ class CacheOnDisk(CacheAbstract):
except:
time.sleep(self.file_lock_time_wait)
def acquire(self, key):
self.file_locks[key].acquire()
def release(self, key):
self.file_locks[key].release()
def __setitem__(self, key, value):
key = self.key_filter_in(key)
val_file = recfile.open(key, mode='wb', path=self.folder)
@@ -344,7 +345,6 @@ class CacheOnDisk(CacheAbstract):
pickle.dump(value, val_file, pickle.HIGHEST_PROTOCOL)
val_file.close()
def __getitem__(self, key):
key = self.key_filter_in(key)
try:
@@ -353,16 +353,14 @@ class CacheOnDisk(CacheAbstract):
raise KeyError
self.wait_portalock(val_file)
value = pickle.load(recfile.open(key, 'rb', path=self.folder))
value = pickle.load(val_file)
val_file.close()
return value
def __contains__(self, key):
key = self.key_filter_in(key)
return (key in self.file_locks) or recfile.exists(key, path=self.folder)
def __delitem__(self, key):
key = self.key_filter_in(key)
try:
@@ -370,15 +368,13 @@ class CacheOnDisk(CacheAbstract):
except IOError:
raise KeyError
def __iter__(self):
for dirpath, dirnames, filenames in os.walk(self.folder):
for filename in filenames:
yield self.key_filter_out(filename)
def safe_apply(self, key, function, default_value=None):
"""
"""
Safely apply a function to the value of a key in storage and set
the return value of the function to it.
@@ -403,25 +399,21 @@ class CacheOnDisk(CacheAbstract):
val_file.close()
return new_value
def keys(self):
return list(self.__iter__())
def get(self, key, default=None):
try:
return self[key]
except KeyError:
return default
def __init__(self, request=None, folder=None):
self.initialized = False
self.request = request
self.folder = folder
self.storage = None
def initialize(self):
if self.initialized:
return
@@ -440,7 +432,6 @@ class CacheOnDisk(CacheAbstract):
self.storage = CacheOnDisk.PersistentStorage(folder)
def __call__(self, key, f,
time_expire=DEFAULT_TIME_EXPIRE):
self.initialize()
@@ -473,16 +464,20 @@ class CacheOnDisk(CacheAbstract):
if item and ((dt is None) or (item[0] > now - dt)):
value = item[1]
else:
value = f()
try:
value = f()
except:
self.storage.release(CacheAbstract.cache_stats_name)
self.storage.release(key)
raise
self.storage[key] = (now, value)
self.storage.safe_apply(CacheAbstract.cache_stats_name, inc_misses,
self.storage.safe_apply(CacheAbstract.cache_stats_name, inc_misses,
default_value={'hit_total': 0, 'misses': 0})
self.storage.release(CacheAbstract.cache_stats_name)
self.storage.release(key)
return value
def clear(self, regex=None):
self.initialize()
storage = self.storage
@@ -499,7 +494,6 @@ class CacheOnDisk(CacheAbstract):
pass
storage.release(key)
def increment(self, key, value=1):
self.initialize()
self.storage.acquire(key)
@@ -508,7 +502,6 @@ class CacheOnDisk(CacheAbstract):
return value
class CacheAction(object):
def __init__(self, func, key, time_expire, cache, cache_model):
self.__name__ = func.__name__
@@ -567,9 +560,9 @@ class Cache(object):
logger.warning('no cache.disk (AttributeError)')
def action(self, time_expire=DEFAULT_TIME_EXPIRE, cache_model=None,
prefix=None, session=False, vars=True, lang=True,
user_agent=False, public=True, valid_statuses=None,
quick=None):
prefix=None, session=False, vars=True, lang=True,
user_agent=False, public=True, valid_statuses=None,
quick=None):
"""Better fit for caching an action
Warning:
@@ -597,28 +590,34 @@ class Cache(object):
"""
from gluon import current
from gluon.http import HTTP
def wrap(func):
def wrapped_f():
if current.request.env.request_method != 'GET':
return func()
if quick:
session_ = True if 'S' in quick else False
vars_ = True if 'V' in quick else False
lang_ = True if 'L' in quick else False
user_agent_ = True if 'U' in quick else False
public_ = True if 'P' in quick else False
else:
(session_, vars_, lang_, user_agent_, public_) = \
(session, vars, lang, user_agent, public)
if time_expire:
cache_control = 'max-age=%(time_expire)s, s-maxage=%(time_expire)s' % dict(time_expire=time_expire)
if quick:
session_ = True if 'S' in quick else False
vars_ = True if 'V' in quick else False
lang_ = True if 'L' in quick else False
user_agent_ = True if 'U' in quick else False
public_ = True if 'P' in quick else False
else:
session_, vars_, lang_, user_agent_, public_ = session, vars, lang, user_agent, public
if not session_ and public_:
cache_control += ', public'
expires = (current.request.utcnow + datetime.timedelta(seconds=time_expire)).strftime('%a, %d %b %Y %H:%M:%S GMT')
expires = (current.request.utcnow + datetime.timedelta(seconds=time_expire)
).strftime('%a, %d %b %Y %H:%M:%S GMT')
else:
cache_control += ', private'
expires = 'Fri, 01 Jan 1990 00:00:00 GMT'
if cache_model:
#figure out the correct cache key
# figure out the correct cache key
cache_key = [current.request.env.path_info, current.response.view]
if session_:
cache_key.append(current.response.session_id)
@@ -635,28 +634,28 @@ class Cache(object):
if prefix:
cache_key = prefix + cache_key
try:
#action returns something
rtn = cache_model(cache_key, lambda : func(), time_expire=time_expire)
# action returns something
rtn = cache_model(cache_key, lambda: func(), time_expire=time_expire)
http, status = None, current.response.status
except HTTP, e:
#action raises HTTP (can still be valid)
rtn = cache_model(cache_key, lambda : e.body, time_expire=time_expire)
# action raises HTTP (can still be valid)
rtn = cache_model(cache_key, lambda: e.body, time_expire=time_expire)
http, status = HTTP(e.status, rtn, **e.headers), e.status
else:
#action raised a generic exception
# action raised a generic exception
http = None
else:
#no server-cache side involved
# no server-cache side involved
try:
#action returns something
# action returns something
rtn = func()
http, status = None, current.response.status
except HTTP, e:
#action raises HTTP (can still be valid)
# action raises HTTP (can still be valid)
status = e.status
http = HTTP(e.status, e.body, **e.headers)
else:
#action raised a generic exception
# action raised a generic exception
http = None
send_headers = False
if http and isinstance(valid_statuses, list):
@@ -666,15 +665,13 @@ class Cache(object):
if str(status)[0] in '123':
send_headers = True
if send_headers:
headers = {
'Pragma' : None,
'Expires' : expires,
'Cache-Control' : cache_control
}
headers = {'Pragma': None,
'Expires': expires,
'Cache-Control': cache_control}
current.response.headers.update(headers)
if cache_model and not send_headers:
#we cached already the value, but the status is not valid
#so we need to delete the cached value
# we cached already the value, but the status is not valid
# so we need to delete the cached value
cache_model(cache_key, None)
if http:
if send_headers:
@@ -731,8 +728,7 @@ class Cache(object):
allow replacing cache.ram with cache.with_prefix(cache.ram,'prefix')
it will add prefix to all the cache keys used.
"""
return lambda key, f, time_expire=DEFAULT_TIME_EXPIRE, prefix=prefix:\
cache_model(prefix + key, f, time_expire)
return lambda key, f, time_expire=DEFAULT_TIME_EXPIRE, prefix=prefix: cache_model(prefix + key, f, time_expire)
def lazy_cache(key=None, time_expire=None, cache_model='ram'):

View File

@@ -261,7 +261,7 @@ class LoadFactory(object):
import globals
target = target or 'c' + str(random.random())[2:]
attr['_id'] = target
request = self.environment['request']
request = current.request
if '.' in f:
f, extension = f.rsplit('.', 1)
if url or ajax:
@@ -464,22 +464,28 @@ def read_pyc(filename):
return marshal.loads(data[8:])
def compile_views(folder):
def compile_views(folder, skip_failed_views=False):
"""
Compiles all the views in the application specified by `folder`
"""
path = pjoin(folder, 'views')
failed_views = []
for fname in listdir(path, '^[\w/\-]+(\.\w+)*$'):
try:
data = parse_template(fname, path)
except Exception, e:
raise Exception("%s in %s" % (e, fname))
filename = 'views.%s.py' % fname.replace(os.path.sep, '.')
filename = pjoin(folder, 'compiled', filename)
write_file(filename, data)
save_pyc(filename)
os.unlink(filename)
if skip_failed_views:
failed_views.append(fname)
else:
raise Exception("%s in %s" % (e, fname))
else:
filename = ('views/%s.py' % fname).replace('/', '_').replace('\\', '_')
filename = pjoin(folder, 'compiled', filename)
write_file(filename, data)
save_pyc(filename)
os.unlink(filename)
return failed_views if failed_views else None
def compile_models(folder):
@@ -532,10 +538,11 @@ def run_models_in(environment):
It tries pre-compiled models first before compiling them.
"""
folder = environment['request'].folder
c = environment['request'].controller
request = current.request
folder = request.folder
c = request.controller
#f = environment['request'].function
response = environment['response']
response = current.response
path = pjoin(folder, 'models')
cpath = pjoin(folder, 'compiled')
@@ -577,7 +584,7 @@ def run_controller_in(controller, function, environment):
"""
# if compiled should run compiled!
folder = environment['request'].folder
folder = current.request.folder
path = pjoin(folder, 'compiled')
badc = 'invalid controller (%s/%s)' % (controller, function)
badf = 'invalid function (%s/%s)' % (controller, function)
@@ -631,7 +638,7 @@ def run_controller_in(controller, function, environment):
layer = filename + ':' + function
code = getcfs(layer, filename, lambda: compile2(code, layer))
restricted(code, environment, filename)
response = environment['response']
response = current.response
vars = response._vars
if response.postprocessing:
vars = reduce(lambda vars, p: p(vars), response.postprocessing, vars)
@@ -649,9 +656,9 @@ def run_view_in(environment):
or `view/generic.extension`
It tries the pre-compiled views_controller_function.pyc before compiling it.
"""
request = environment['request']
response = environment['response']
view = response.view
request = current.request
response = current.response
view = environment['response'].view
folder = request.folder
path = pjoin(folder, 'compiled')
badv = 'invalid view (%s)' % view
@@ -666,32 +673,28 @@ def run_view_in(environment):
ccode = parse_template(view, pjoin(folder, 'views'),
context=environment)
restricted(ccode, environment, 'file stream')
elif os.path.exists(path):
x = view.replace('/', '.')
files = ['views.%s.pyc' % x]
if allow_generic:
files.append('views.generic.%s.pyc' % request.extension)
# for backward compatibility
x = view.replace('/', '_')
files.append('views_%s.pyc' % x)
if allow_generic:
files.append('views_generic.%s.pyc' % request.extension)
if request.extension == 'html':
files.append('views_%s.pyc' % x[:-5])
if allow_generic:
files.append('views_generic.pyc')
# end backward compatibility code
for f in files:
filename = pjoin(path, f)
if os.path.exists(filename):
code = read_pyc(filename)
restricted(code, environment, layer=filename)
return
raise HTTP(404,
rewrite.THREAD_LOCAL.routes.error_message % badv,
web2py_error=badv)
else:
filename = pjoin(folder, 'views', view)
if os.path.exists(path): # compiled views
x = view.replace('/', '_')
files = ['views_%s.pyc' % x]
is_compiled = os.path.exists(pjoin(path, files[0]))
# Don't use a generic view if the non-compiled view exists.
if is_compiled or (not is_compiled and not os.path.exists(filename)):
if allow_generic:
files.append('views_generic.%s.pyc' % request.extension)
# for backward compatibility
if request.extension == 'html':
files.append('views_%s.pyc' % x[:-5])
if allow_generic:
files.append('views_generic.pyc')
# end backward compatibility code
for f in files:
compiled = pjoin(path, f)
if os.path.exists(compiled):
code = read_pyc(compiled)
restricted(code, environment, layer=compiled)
return
if not os.path.exists(filename) and allow_generic:
view = 'generic.' + request.extension
filename = pjoin(folder, 'views', view)
@@ -725,7 +728,7 @@ def remove_compiled_application(folder):
pass
def compile_application(folder):
def compile_application(folder, skip_failed_views=False):
"""
Compiles all models, views, controller for the application in `folder`.
"""
@@ -733,7 +736,8 @@ def compile_application(folder):
os.mkdir(pjoin(folder, 'compiled'))
compile_models(folder)
compile_controllers(folder)
compile_views(folder)
failed_views = compile_views(folder, skip_failed_views)
return failed_views
def test():

View File

@@ -35,7 +35,6 @@ from gluon.serializers import json_parser
locker = thread.allocate_lock()
def AppConfig(*args, **vars):
locker.acquire()
@@ -59,6 +58,27 @@ class AppConfigDict(dict):
dict.__init__(self, *args, **kwargs)
self.int_cache = {}
def get(self, path, default=None):
try:
value = self.take(path).strip()
if value.lower() in ('none','null',''):
return None
elif value.lower() == 'true':
return True
elif value.lower() == 'false':
return False
elif value.isdigit() or (value[0]=='-' and value[1:].isdigit()):
return int(value)
elif ',' in value:
return map(lambda x:x.strip(),value.split(','))
else:
try:
return float(value)
except:
return value
except:
return default
def take(self, path, cast=None):
parts = path.split('.')
if path in self.int_cache:

View File

@@ -93,7 +93,7 @@ def video(url):
def googledoc_viewer(url):
return '<iframe src="http://docs.google.com/viewer?url=%s&embedded=true" style="max-width:100%%"></iframe>' % urllib.quote(url)
return '<iframe src="https://docs.google.com/viewer?url=%s&embedded=true" style="max-width:100%%"></iframe>' % urllib.quote(url)
def web2py_component(url):

1494
gluon/contrib/feedparser.py Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,15 +6,17 @@
#
# Given the model
#
# db.define_table("table_name", Field("picture", "upload"), Field("thumbnail", "upload"))
# db.define_table("table_name", Field("picture", "upload"),
# Field("thumbnail", "upload"))
#
# # to resize the picture on upload
# to resize the picture on upload
#
# from images import RESIZE
#
# db.table_name.picture.requires = RESIZE(200, 200)
#
# # to store original image in picture and create a thumbnail in 'thumbnail' field
# to store original image in picture and create a thumbnail
# in 'thumbnail' field
#
# from images import THUMB
# db.table_name.thumbnail.compute = lambda row: THUMB(row.picture, 200, 200)
@@ -24,8 +26,11 @@ from gluon import current
class RESIZE(object):
def __init__(self, nx=160, ny=80, error_message=' image resize'):
(self.nx, self.ny, self.error_message) = (nx, ny, error_message)
def __init__(self, nx=160, ny=80, quality=100, padding = False,
error_message=' image resize'):
(self.nx, self.ny, self.quality, self.error_message, self.padding) = (
nx, ny, quality, error_message, padding)
def __call__(self, value):
if isinstance(value, str) and len(value) == 0:
@@ -36,7 +41,14 @@ class RESIZE(object):
img = Image.open(value.file)
img.thumbnail((self.nx, self.ny), Image.ANTIALIAS)
s = cStringIO.StringIO()
img.save(s, 'JPEG', quality=100)
if self.padding:
background = Image.new('RGBA', (self.nx, self.ny), (255, 255, 255, 0))
background.paste(
img,
((self.nx - img.size[0]) / 2, (self.ny - img.size[1]) / 2))
background.save(s, 'JPEG', quality=self.quality)
else:
img.save(s, 'JPEG', queality=self.quality)
s.seek(0)
value.file = s
except:
@@ -51,7 +63,7 @@ def THUMB(image, nx=120, ny=120, gae=False, name='thumb'):
request = current.request
from PIL import Image
import os
img = Image.open(os.path.join(request.folder,'uploads',image))
img = Image.open(os.path.join(request.folder, 'uploads', image))
img.thumbnail((nx, ny), Image.ANTIALIAS)
root, ext = os.path.splitext(image)
thumb = '%s_%s%s' % (root, name, ext)

View File

@@ -14,12 +14,20 @@ except Exception, e:
raise e
def ldap_auth(server='ldap', port=None,
def ldap_auth(server='ldap',
port=None,
base_dn='ou=users,dc=domain,dc=com',
mode='uid', secure=False,
cert_path=None, cert_file=None,
cacert_path=None, cacert_file=None, key_file=None,
bind_dn=None, bind_pw=None, filterstr='objectClass=*',
mode='uid',
secure=False,
self_signed_certificate=None, # See NOTE below
cert_path=None,
cert_file=None,
cacert_path=None,
cacert_file=None,
key_file=None,
bind_dn=None,
bind_pw=None,
filterstr='objectClass=*',
username_attrib='uid',
custom_scope='subtree',
allowed_groups=None,
@@ -28,11 +36,14 @@ def ldap_auth(server='ldap', port=None,
user_lastname_attrib='cn:2',
user_mail_attrib='mail',
manage_groups=False,
manage_groups_callback=[],
db=None,
group_dn=None,
group_name_attrib='cn',
group_member_attrib='memberUid',
group_filterstr='objectClass=*',
group_mapping={},
tls=False,
logging_level='error'):
"""
@@ -80,6 +91,13 @@ def ldap_auth(server='ldap', port=None,
If ldap is using GnuTLS then you need cert_file="..." instead cert_path
because cert_path isn't implemented in GnuTLS :(
To enable TLS, set tls=True:
auth.settings.login_methods.append(ldap_auth(
server='my.ldap.server',
base_dn='ou=Users,dc=domain,dc=com',
tls=True))
If you need to bind to the directory with an admin account in order to
search it then specify bind_dn & bind_pw to use for this.
- currently only implemented for Active Directory
@@ -151,6 +169,14 @@ def ldap_auth(server='ldap', port=None,
You can set the logging level with the "logging_level" parameter, default
is "error" and can be set to error, warning, info, debug.
"""
if self_signed_certificate:
# NOTE : If you have a self-signed SSL Certificate pointing over "port=686" and "secure=True" alone
# will not work, you need also to set "self_signed_certificate=True".
# Ref1: https://onemoretech.wordpress.com/2015/06/25/connecting-to-ldap-over-self-signed-tls-with-python/
# Ref2: http://bneijt.nl/blog/post/connecting-to-ldaps-with-self-signed-cert-using-python/
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
logger = logging.getLogger('web2py.auth.ldap_auth')
if logging_level == 'error':
logger.setLevel(logging.ERROR)
@@ -183,13 +209,13 @@ def ldap_auth(server='ldap', port=None,
user_mail_attrib=user_mail_attrib,
manage_groups=manage_groups,
allowed_groups=allowed_groups,
group_mapping=group_mapping,
db=db):
if password == '': # http://tools.ietf.org/html/rfc4513#section-5.1.2
logger.warning('blank password not allowed')
return False
logger.debug('mode: [%s] manage_user: [%s] custom_scope: [%s]'
' manage_groups: [%s]' % (str(mode), str(manage_user),
str(custom_scope), str(manage_groups)))
' manage_groups: [%s]' % (str(mode), str(manage_user), str(custom_scope), str(manage_groups)))
if manage_user:
if user_firstname_attrib.count(':') > 0:
(user_firstname_attrib,
@@ -238,14 +264,11 @@ def ldap_auth(server='ldap', port=None,
# in the ldap_basedn
requested_attrs = ['sAMAccountName']
if manage_user:
requested_attrs.extend([user_firstname_attrib,
user_lastname_attrib,
user_mail_attrib])
requested_attrs.extend([user_firstname_attrib, user_lastname_attrib, user_mail_attrib])
result = con.search_ext_s(
ldap_basedn, ldap.SCOPE_SUBTREE,
"(&(sAMAccountName=%s)(%s))" % (
ldap.filter.escape_filter_chars(username_bare),
filterstr),
"(&(sAMAccountName=%s)(%s))" % (ldap.filter.escape_filter_chars(username_bare), filterstr),
requested_attrs)[0][1]
if not isinstance(result, dict):
# result should be a dict in the form
@@ -278,25 +301,21 @@ def ldap_auth(server='ldap', port=None,
if manage_user:
result = con.search_s(dn, ldap.SCOPE_BASE,
"(objectClass=*)",
[user_firstname_attrib,
user_lastname_attrib,
user_mail_attrib])[0][1]
[user_firstname_attrib, user_lastname_attrib, user_mail_attrib])[0][1]
if ldap_mode == 'uid':
# OpenLDAP (UID)
if ldap_binddn and ldap_bindpw:
con.simple_bind_s(ldap_binddn, ldap_bindpw)
dn = "uid=" + username + "," + ldap_basedn
dn = con.search_s(ldap_basedn, ldap.SCOPE_SUBTREE, "(uid=%s)"%username, [''])[0][0]
dn = con.search_s(ldap_basedn, ldap.SCOPE_SUBTREE, "(uid=%s)" % username, [''])[0][0]
else:
dn = "uid=" + username + "," + ldap_basedn
con.simple_bind_s(dn, password)
if manage_user:
result = con.search_s(dn, ldap.SCOPE_BASE,
"(objectClass=*)",
[user_firstname_attrib,
user_lastname_attrib,
user_mail_attrib])[0][1]
[user_firstname_attrib, user_lastname_attrib, user_mail_attrib])[0][1]
if ldap_mode == 'company':
# no DNs or password needed to search directory
@@ -311,9 +330,7 @@ def ldap_auth(server='ldap', port=None,
# find the uid
attrs = ['uid']
if manage_user:
attrs.extend([user_firstname_attrib,
user_lastname_attrib,
user_mail_attrib])
attrs.extend([user_firstname_attrib, user_lastname_attrib, user_mail_attrib])
# perform the actual search
company_search_result = con.search_s(ldap_basedn,
ldap.SCOPE_SUBTREE,
@@ -329,13 +346,11 @@ def ldap_auth(server='ldap', port=None,
basedns = ldap_basedn
else:
basedns = [ldap_basedn]
filter = '(&(uid=%s)(%s))' % (
ldap.filter.escape_filter_chars(username), filterstr)
filter = '(&(uid=%s)(%s))' % (ldap.filter.escape_filter_chars(username), filterstr)
found = False
for basedn in basedns:
try:
result = con.search_s(basedn, ldap.SCOPE_SUBTREE,
filter)
result = con.search_s(basedn, ldap.SCOPE_SUBTREE, filter)
if result:
user_dn = result[0][0]
# Check the password
@@ -344,9 +359,10 @@ def ldap_auth(server='ldap', port=None,
break
except ldap.LDAPError, detail:
(exc_type, exc_value) = sys.exc_info()[:2]
logger.warning(
"ldap_auth: searching %s for %s resulted in %s: %s\n" %
(basedn, filter, exc_type, exc_value)
logger.warning("ldap_auth: searching %s for %s resulted in %s: %s\n" % (basedn,
filter,
exc_type,
exc_value)
)
if not found:
logger.warning('User [%s] not found!' % username)
@@ -359,10 +375,7 @@ def ldap_auth(server='ldap', port=None,
basedns = ldap_basedn
else:
basedns = [ldap_basedn]
filter = '(&(%s=%s)(%s))' % (username_attrib,
ldap.filter.escape_filter_chars(
username),
filterstr)
filter = '(&(%s=%s)(%s))' % (username_attrib, ldap.filter.escape_filter_chars(username), filterstr)
if custom_scope == 'subtree':
ldap_scope = ldap.SCOPE_SUBTREE
elif custom_scope == 'base':
@@ -381,9 +394,10 @@ def ldap_auth(server='ldap', port=None,
break
except ldap.LDAPError, detail:
(exc_type, exc_value) = sys.exc_info()[:2]
logger.warning(
"ldap_auth: searching %s for %s resulted in %s: %s\n" %
(basedn, filter, exc_type, exc_value)
logger.warning("ldap_auth: searching %s for %s resulted in %s: %s\n" % (basedn,
filter,
exc_type,
exc_value)
)
if not found:
logger.warning('User [%s] not found!' % username)
@@ -393,16 +407,14 @@ def ldap_auth(server='ldap', port=None,
logger.info('[%s] Manage user data' % str(username))
try:
if user_firstname_part is not None:
store_user_firstname = result[user_firstname_attrib][
0].split(' ', 1)[user_firstname_part]
store_user_firstname = result[user_firstname_attrib][0].split(' ', 1)[user_firstname_part]
else:
store_user_firstname = result[user_firstname_attrib][0]
except KeyError, e:
store_user_firstname = None
try:
if user_lastname_part is not None:
store_user_lastname = result[user_lastname_attrib][
0].split(' ', 1)[user_lastname_part]
store_user_lastname = result[user_lastname_attrib][0].split(' ', 1)[user_lastname_part]
else:
store_user_lastname = result[user_lastname_attrib][0]
except KeyError, e:
@@ -411,36 +423,32 @@ def ldap_auth(server='ldap', port=None,
store_user_mail = result[user_mail_attrib][0]
except KeyError, e:
store_user_mail = None
try:
#
update_or_insert_values = {'first_name': store_user_firstname,
'last_name': store_user_lastname,
'email': store_user_mail,
'username': username}
if '@' not in username:
# user as username
# #################
# ################
fields = ['first_name', 'last_name', 'email']
user_in_db = db(db.auth_user.username == username)
if user_in_db.count() > 0:
user_in_db.update(first_name=store_user_firstname,
last_name=store_user_lastname,
email=store_user_mail)
else:
db.auth_user.insert(first_name=store_user_firstname,
last_name=store_user_lastname,
email=store_user_mail,
username=username)
except:
#
elif '@' in username:
# user as email
# ##############
# #############
fields = ['first_name', 'last_name']
user_in_db = db(db.auth_user.email == username)
if user_in_db.count() > 0:
user_in_db.update(first_name=store_user_firstname,
last_name=store_user_lastname)
else:
db.auth_user.insert(first_name=store_user_firstname,
last_name=store_user_lastname,
email=username)
update_or_insert_values = dict(((f, update_or_insert_values[f]) for f in fields))
if user_in_db.count() > 0:
actual_values = user_in_db.select(*[db.auth_user[f] for f in fields]).first().as_dict()
if update_or_insert_values != actual_values: # We don't update record if values are the same
user_in_db.update(**update_or_insert_values)
else:
db.auth_user.insert(**update_or_insert_values)
con.unbind()
if manage_groups:
if not do_manage_groups(username, password):
if not do_manage_groups(username, password, group_mapping):
return False
return True
except ldap.INVALID_CREDENTIALS, e:
@@ -478,9 +486,7 @@ def ldap_auth(server='ldap', port=None,
# No match
return False
def do_manage_groups(username,
password=None,
db=db):
def do_manage_groups(username, password=None, group_mapping={}, db=db):
"""
Manage user groups
@@ -496,54 +502,65 @@ def ldap_auth(server='ldap', port=None,
ldap_groups_of_the_user = get_user_groups_from_ldap(
username, password)
if group_mapping != {}:
l = []
for group in ldap_groups_of_the_user:
if group in group_mapping:
l += group_mapping[group]
ldap_groups_of_the_user = l
logging.info("User groups after remapping: %s" % str(l))
#
# Get all group name where the user is in actually in local db
# #############################################################
try:
db_user_id = db(db.auth_user.username == username).select(
db.auth_user.id).first().id
db_user_id = db(db.auth_user.username == username).select(db.auth_user.id).first().id
except:
try:
db_user_id = db(db.auth_user.email == username).select(
db.auth_user.id).first().id
db_user_id = db(db.auth_user.email == username).select(db.auth_user.id).first().id
except AttributeError, e:
#
# There is no user in local db
# We create one
# ##############################
try:
db_user_id = db.auth_user.insert(username=username,
first_name=username)
db_user_id = db.auth_user.insert(username=username, first_name=username)
except AttributeError, e:
db_user_id = db.auth_user.insert(email=username,
first_name=username)
db_user_id = db.auth_user.insert(email=username, first_name=username)
if not db_user_id:
logging.error(
'There is no username or email for %s!' % username)
raise
db_group_search = db((db.auth_membership.user_id == db_user_id) &
(db.auth_user.id == db.auth_membership.user_id) &
(db.auth_group.id == db.auth_membership.group_id))
# if old pydal version, assume this is a relational database which can do joins
db_can_join = db.can_join() if hasattr(db, 'can_join') else True
if db_can_join:
db_group_search = \
db((db.auth_membership.user_id == db_user_id) &
(db.auth_user.id == db.auth_membership.user_id) &
(db.auth_group.id == db.auth_membership.group_id))
else:
# no joins on NoSQL databases, perform two queries
db_group_search = db(db.auth_membership.user_id == db_user_id)
group_ids = [x.group_id for x in db_group_search.select(db.auth_membership.group_id, distinct=True)]
db_group_search = db(db.auth_group.id.belongs(group_ids))
db_groups_of_the_user = list()
db_group_id = dict()
if db_group_search.count() > 0:
for group in db_group_search.select(db.auth_group.id,
db.auth_group.role,
distinct=True):
for group in db_group_search.select(db.auth_group.id, db.auth_group.role, distinct=True):
db_group_id[group.role] = group.id
db_groups_of_the_user.append(group.role)
logging.debug('db groups of user %s: %s' %
(username, str(db_groups_of_the_user)))
logging.debug('db groups of user %s: %s' % (username, str(db_groups_of_the_user)))
auth_membership_changed = False
#
# Delete user membership from groups where user is not anymore
# #############################################################
for group_to_del in db_groups_of_the_user:
if ldap_groups_of_the_user.count(group_to_del) == 0:
db((db.auth_membership.user_id == db_user_id) &
(db.auth_membership.group_id == \
db_group_id[group_to_del])).delete()
(db.auth_membership.group_id == db_group_id[group_to_del])).delete()
auth_membership_changed = True
#
# Create user membership in groups where user is not in already
@@ -551,16 +568,18 @@ def ldap_auth(server='ldap', port=None,
for group_to_add in ldap_groups_of_the_user:
if db_groups_of_the_user.count(group_to_add) == 0:
if db(db.auth_group.role == group_to_add).count() == 0:
gid = db.auth_group.insert(role=group_to_add,
description='Generated from LDAP')
gid = db.auth_group.insert(role=group_to_add, description='Generated from LDAP')
else:
gid = db(db.auth_group.role == group_to_add).select(
db.auth_group.id).first().id
db.auth_membership.insert(user_id=db_user_id,
group_id=gid)
gid = db(db.auth_group.role == group_to_add).select(db.auth_group.id).first().id
db.auth_membership.insert(user_id=db_user_id, group_id=gid)
auth_membership_changed = True
if auth_membership_changed:
for callback in manage_groups_callback:
callback()
except:
logger.warning("[%s] Groups are not managed successfully!" %
str(username))
logger.warning("[%s] Groups are not managed successfully!" % str(username))
import traceback
logger.debug(traceback.format_exc())
return False
@@ -600,6 +619,8 @@ def ldap_auth(server='ldap', port=None,
ldap_port = 389
con = ldap.initialize(
"ldap://" + ldap_server + ":" + str(ldap_port))
if tls:
con.start_tls_s()
return con
def get_user_groups_from_ldap(username,
@@ -649,10 +670,12 @@ def ldap_auth(server='ldap', port=None,
con.simple_bind_s(username, password)
logger.debug('Ldap username connect...')
# We have to use the full string
username = con.search_ext_s(base_dn, ldap.SCOPE_SUBTREE,
"(&(sAMAccountName=%s)(%s))" %
(ldap.filter.escape_filter_chars(username_bare),
filterstr), ["cn"])[0][0]
username = \
con.search_ext_s(base_dn,
ldap.SCOPE_SUBTREE,
"(&(sAMAccountName=%s)(%s))" % (ldap.filter.escape_filter_chars(username_bare),
filterstr),
["cn"])[0][0]
else:
if ldap_binddn:
# need to search directory with an bind_dn account 1st
@@ -665,18 +688,14 @@ def ldap_auth(server='ldap', port=None,
if username is None:
return list()
# search for groups where user is in
filter = '(&(%s=%s)(%s))' % (ldap.filter.escape_filter_chars(
group_member_attrib
),
filter = '(&(%s=%s)(%s))' % (ldap.filter.escape_filter_chars(group_member_attrib),
ldap.filter.escape_filter_chars(username),
group_filterstr)
group_search_result = con.search_s(group_dn,
ldap.SCOPE_SUBTREE,
filter, [group_name_attrib])
group_search_result = con.search_s(group_dn, ldap.SCOPE_SUBTREE, filter, [group_name_attrib])
ldap_groups_of_the_user = list()
for group_row in group_search_result:
group = group_row[1]
if type(group) == dict and group.has_key(group_name_attrib):
if type(group) == dict and group_name_attrib in group:
ldap_groups_of_the_user.extend(group[group_name_attrib])
con.unbind()

View File

@@ -139,24 +139,36 @@ server for requests. It can be used for the optional"scope" parameters for Face
Return the access token generated by the authenticating server.
If token is already in the session that one will be used.
If token has expired refresh_token is used to get another token.
Otherwise the token is fetched from the auth server.
"""
refresh_token = None
if current.session.token and 'expires' in current.session.token:
expires = current.session.token['expires']
# reuse token until expiration
if expires == 0 or expires > time.time():
return current.session.token['access_token']
return current.session.token['access_token']
if 'refresh_token' in current.session.token:
refresh_token = current.session.token['refresh_token']
code = current.request.vars.code
if code:
data = dict(client_id=self.client_id,
client_secret=self.client_secret,
redirect_uri=current.session.redirect_uri,
code=code,
grant_type='authorization_code'
)
if code or refresh_token:
data = dict(
client_id=self.client_id,
client_secret=self.client_secret,
)
if code:
data.update(
redirect_uri=current.session.redirect_uri,
code=code,
grant_type='authorization_code'
)
elif refresh_token:
data.update(
refresh_token=refresh_token,
grant_type='refresh_token'
)
open_url = None
opener = self.__build_url_opener(self.token_url)

View File

@@ -51,7 +51,7 @@ class OneallAccount(object):
reg_id=profile.get('identity_token','')
username=profile.get('preferredUsername',email)
first_name=name.get('givenName', dname.split(' ')[0])
last_name=profile.get('familyName',dname.split(' ')[1])
last_name=profile.get('familyName', dname.split(' ')[1] if(dname.count(' ') > 0) else None)
return dict(registration_id=reg_id,username=username,email=email,
first_name=first_name,last_name=last_name)
self.mappings.default = defaultmapping

View File

@@ -13,6 +13,7 @@ Include in your model (eg db.py)::
auth.define_tables(username=True)
from gluon.contrib.login_methods.saml2_auth import Saml2Auth
import os
auth.settings.login_form=Saml2Auth(
config_file = os.path.join(request.folder,'private','sp_conf'),
maps=dict(
@@ -20,10 +21,59 @@ Include in your model (eg db.py)::
email=lambda v: v['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn'][0],
user_id=lambda v: v['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn'][0]))
you must have private/sp_conf.py, the pysaml2 sp configuration file
you must have private/sp_conf.py, the pysaml2 sp configuration file. For example:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from saml2 import BINDING_HTTP_POST, BINDING_HTTP_REDIRECT
import os.path
import requests
import tempfile
BASEDIR = os.path.abspath(os.path.dirname(__file__))
# Web2py SP url and application name
HOST = 'http://127.0.0.1:8000'
APP = 'sp'
# To load the IDP metadata...
IDP_METADATA = 'http://127.0.0.1:8088/metadata'
def full_path(local_file):
return os.path.join(BASEDIR, local_file)
CONFIG = {
# your entity id, usually your subdomain plus the url to the metadata view.
'entityid': '%s/%s/default/metadata' % (HOST, APP),
'service': {
'sp' : {
'name': 'MYSP',
'endpoints': {
'assertion_consumer_service': [
('%s/%s/default/user/login' % (HOST, APP), BINDING_HTTP_REDIRECT),
('%s/%s/default/user/login' % (HOST, APP), BINDING_HTTP_POST),
],
},
},
},
# Your private and public key.
'key_file': full_path('pki/mykey.pem'),
'cert_file': full_path('pki/mycert.pem'),
# where the remote metadata is stored
'metadata': {
"remote": [{
"url": IDP_METADATA,
"cert":full_path('pki/mycert.pem')
}]
},
}
"""
from saml2 import BINDING_HTTP_REDIRECT
from saml2 import BINDING_HTTP_REDIRECT, BINDING_HTTP_POST
from saml2.client import Saml2Client
from gluon.utils import web2py_uuid
from gluon import current, redirect, URL
@@ -59,10 +109,13 @@ def saml2_handler(session, request, config_filename = None):
client = Saml2Client(config_file = config_filename)
idps = client.metadata.with_descriptor("idpsso")
entityid = idps.keys()[0]
bindings = [BINDING_HTTP_REDIRECT]
bindings = [BINDING_HTTP_REDIRECT, BINDING_HTTP_POST]
binding, destination = client.pick_binding(
"single_sign_on_service", bindings, "idpsso", entity_id=entityid)
binding = BINDING_HTTP_REDIRECT
if request.env.request_method == 'GET':
binding = BINDING_HTTP_REDIRECT
elif request.env.request_method == 'POST':
binding = BINDING_HTTP_POST
if not request.vars.SAMLResponse:
req_id, req = client.create_authn_request(destination, binding=binding)
relay_state = web2py_uuid().replace('-','')

View File

@@ -53,8 +53,9 @@ see <https://github.com/trentm/python-markdown2/wiki/Extras> for details):
* header-ids: Adds "id" attributes to headers. The id value is a slug of
the header text.
* html-classes: Takes a dict mapping html tag names (lowercase) to a
string to use for a "class" tag attribute. Currently only supports
"pre" and "code" tags. Add an issue if you require this for other tags.
string to use for a "class" tag attribute. Currently only supports "img",
"table", "pre" and "code" tags. Add an issue if you require this for other
tags.
* markdown-in-html: Allow the use of `markdown="1"` in a block HTML tag to
have markdown processing be done on its contents. Similar to
<http://michelf.com/projects/php-markdown/extra/#markdown-attr> but with
@@ -70,9 +71,14 @@ see <https://github.com/trentm/python-markdown2/wiki/Extras> for details):
* smarty-pants: Replaces ' and " with curly quotation marks or curly
apostrophes. Replaces --, ---, ..., and . . . with en dashes, em dashes,
and ellipses.
* spoiler: A special kind of blockquote commonly hidden behind a
click on SO. Syntax per <http://meta.stackexchange.com/a/72878>.
* toc: The returned HTML string gets a new "toc_html" attribute which is
a Table of Contents for the document. (experimental)
* xml: Passes one-liner processing instructions and namespaced XML tags.
* tables: Tables using the same format as GFM
<https://help.github.com/articles/github-flavored-markdown#tables> and
PHP-Markdown Extra <https://michelf.ca/projects/php-markdown/extra/#table>.
* wiki-tables: Google Code Wiki-style tables. See
<http://code.google.com/p/support/wiki/WikiSyntax#Tables>.
"""
@@ -82,13 +88,11 @@ see <https://github.com/trentm/python-markdown2/wiki/Extras> for details):
# not yet sure if there implications with this. Compare 'pydoc sre'
# and 'perldoc perlre'.
__version_info__ = (2, 2, 4)
__version_info__ = (2, 3, 1)
__version__ = '.'.join(map(str, __version_info__))
__author__ = "Trent Mick"
import os
import sys
from pprint import pprint
import re
import logging
try:
@@ -102,13 +106,7 @@ import codecs
#---- Python version compat
try:
from urllib.parse import quote # python3
except ImportError:
from urllib import quote # python2
if sys.version_info[:2] < (2,4):
from sets import Set as set
def reversed(sequence):
for i in sequence[::-1]:
yield i
@@ -804,6 +802,8 @@ class Markdown(object):
text = self._prepare_pyshell_blocks(text)
if "wiki-tables" in self.extras:
text = self._do_wiki_tables(text)
if "tables" in self.extras:
text = self._do_tables(text)
text = self._do_code_blocks(text)
@@ -844,6 +844,79 @@ class Markdown(object):
return _pyshell_block_re.sub(self._pyshell_block_sub, text)
def _table_sub(self, match):
trim_space_re = '^[ \t\n]+|[ \t\n]+$'
trim_bar_re = '^\||\|$'
head, underline, body = match.groups()
# Determine aligns for columns.
cols = [cell.strip() for cell in re.sub(trim_bar_re, "", re.sub(trim_space_re, "", underline)).split('|')]
align_from_col_idx = {}
for col_idx, col in enumerate(cols):
if col[0] == ':' and col[-1] == ':':
align_from_col_idx[col_idx] = ' align="center"'
elif col[0] == ':':
align_from_col_idx[col_idx] = ' align="left"'
elif col[-1] == ':':
align_from_col_idx[col_idx] = ' align="right"'
# thead
hlines = ['<table%s>' % self._html_class_str_from_tag('table'), '<thead>', '<tr>']
cols = [cell.strip() for cell in re.sub(trim_bar_re, "", re.sub(trim_space_re, "", head)).split('|')]
for col_idx, col in enumerate(cols):
hlines.append(' <th%s>%s</th>' % (
align_from_col_idx.get(col_idx, ''),
self._run_span_gamut(col)
))
hlines.append('</tr>')
hlines.append('</thead>')
# tbody
hlines.append('<tbody>')
for line in body.strip('\n').split('\n'):
hlines.append('<tr>')
cols = [cell.strip() for cell in re.sub(trim_bar_re, "", re.sub(trim_space_re, "", line)).split('|')]
for col_idx, col in enumerate(cols):
hlines.append(' <td%s>%s</td>' % (
align_from_col_idx.get(col_idx, ''),
self._run_span_gamut(col)
))
hlines.append('</tr>')
hlines.append('</tbody>')
hlines.append('</table>')
return '\n'.join(hlines) + '\n'
def _do_tables(self, text):
"""Copying PHP-Markdown and GFM table syntax. Some regex borrowed from
https://github.com/michelf/php-markdown/blob/lib/Michelf/Markdown.php#L2538
"""
less_than_tab = self.tab_width - 1
table_re = re.compile(r'''
(?:(?<=\n\n)|\A\n?) # leading blank line
^[ ]{0,%d} # allowed whitespace
(.*[|].*) \n # $1: header row (at least one pipe)
^[ ]{0,%d} # allowed whitespace
( # $2: underline row
# underline row with leading bar
(?: \|\ *:?-+:?\ * )+ \|? \n
|
# or, underline row without leading bar
(?: \ *:?-+:?\ *\| )+ (?: \ *:?-+:?\ * )? \n
)
( # $3: data rows
(?:
^[ ]{0,%d}(?!\ ) # ensure line begins with 0 to less_than_tab spaces
.*\|.* \n
)+
)
''' % (less_than_tab, less_than_tab, less_than_tab), re.M | re.X)
return table_re.sub(self._table_sub, text)
def _wiki_table_sub(self, match):
ttext = match.group(0).strip()
#print 'wiki table: %r' % match.group(0)
@@ -853,7 +926,7 @@ class Markdown(object):
row = [c.strip() for c in re.split(r'(?<!\\)\|\|', line)]
rows.append(row)
#pprint(rows)
hlines = ['<table>', '<tbody>']
hlines = ['<table%s>' % self._html_class_str_from_tag('table'), '<tbody>']
for row in rows:
hrow = ['<tr>']
for cell in row:
@@ -899,6 +972,9 @@ class Markdown(object):
text = self._encode_amps_and_angles(text)
if "strike" in self.extras:
text = self._do_strike(text)
text = self._do_italics_and_bold(text)
if "smarty-pants" in self.extras:
@@ -1206,7 +1282,6 @@ class Markdown(object):
.replace('_', self._escape_table['_'])
title = self.titles.get(link_id)
if title:
before = title
title = _xml_escape_attr(title) \
.replace('*', self._escape_table['*']) \
.replace('_', self._escape_table['_'])
@@ -1418,7 +1493,6 @@ class Markdown(object):
def _list_item_sub(self, match):
item = match.group(4)
leading_line = match.group(1)
leading_space = match.group(2)
if leading_line or "\n\n" in item or self._last_li_endswith_two_eols:
item = self._run_block_gamut(self._outdent(item))
else:
@@ -1654,6 +1728,11 @@ class Markdown(object):
self._escape_table[text] = hashed
return hashed
_strike_re = re.compile(r"~~(?=\S)(.+?)(?<=\S)~~", re.S)
def _do_strike(self, text):
text = self._strike_re.sub(r"<strike>\1</strike>", text)
return text
_strong_re = re.compile(r"(\*\*|__)(?=\S)(.+?[*_]*)(?<=\S)\1", re.S)
_em_re = re.compile(r"(\*|_)(?=\S)(.+?)(?<=\S)\1", re.S)
_code_friendly_strong_re = re.compile(r"\*\*(?=\S)(.+?[*_]*)(?<=\S)\*\*", re.S)
@@ -1714,38 +1793,53 @@ class Markdown(object):
text = text.replace(". . .", "&#8230;")
return text
_block_quote_re = re.compile(r'''
_block_quote_base = r'''
( # Wrap whole match in \1
(
^[ \t]*>[ \t]? # '>' at the start of a line
^[ \t]*>%s[ \t]? # '>' at the start of a line
.+\n # rest of the first line
(.+\n)* # subsequent consecutive lines
\n* # blanks
)+
)
''', re.M | re.X)
'''
_block_quote_re = re.compile(_block_quote_base % '', re.M | re.X)
_block_quote_re_spoiler = re.compile(_block_quote_base % '[ \t]*?!?', re.M | re.X)
_bq_one_level_re = re.compile('^[ \t]*>[ \t]?', re.M);
_bq_one_level_re_spoiler = re.compile('^[ \t]*>[ \t]*?![ \t]?', re.M);
_bq_all_lines_spoilers = re.compile(r'\A(?:^[ \t]*>[ \t]*?!.*[\n\r]*)+\Z', re.M)
_html_pre_block_re = re.compile(r'(\s*<pre>.+?</pre>)', re.S)
def _dedent_two_spaces_sub(self, match):
return re.sub(r'(?m)^ ', '', match.group(1))
def _block_quote_sub(self, match):
bq = match.group(1)
bq = self._bq_one_level_re.sub('', bq) # trim one level of quoting
bq = self._ws_only_line_re.sub('', bq) # trim whitespace-only lines
is_spoiler = 'spoiler' in self.extras and self._bq_all_lines_spoilers.match(bq)
# trim one level of quoting
if is_spoiler:
bq = self._bq_one_level_re_spoiler.sub('', bq)
else:
bq = self._bq_one_level_re.sub('', bq)
# trim whitespace-only lines
bq = self._ws_only_line_re.sub('', bq)
bq = self._run_block_gamut(bq) # recurse
bq = re.sub('(?m)^', ' ', bq)
# These leading spaces screw with <pre> content, so we need to fix that:
bq = self._html_pre_block_re.sub(self._dedent_two_spaces_sub, bq)
return "<blockquote>\n%s\n</blockquote>\n\n" % bq
if is_spoiler:
return '<blockquote class="spoiler">\n%s\n</blockquote>\n\n' % bq
else:
return '<blockquote>\n%s\n</blockquote>\n\n' % bq
def _do_block_quotes(self, text):
if '>' not in text:
return text
return self._block_quote_re.sub(self._block_quote_sub, text)
if 'spoiler' in self.extras:
return self._block_quote_re_spoiler.sub(self._block_quote_sub, text)
else:
return self._block_quote_re.sub(self._block_quote_sub, text)
def _form_paragraphs(self, text):
# Strip leading and trailing lines:
@@ -2053,7 +2147,6 @@ def _dedentlines(lines, tabsize=8, skip_first_line=False):
if DEBUG:
print("dedent: dedent(..., tabsize=%d, skip_first_line=%r)"\
% (tabsize, skip_first_line))
indents = []
margin = None
for i, line in enumerate(lines):
if i == 0 and skip_first_line: continue
@@ -2362,4 +2455,4 @@ def main(argv=None):
if __name__ == "__main__":
sys.exit( main(sys.argv) )
sys.exit( main(sys.argv) )

View File

@@ -7,10 +7,11 @@ import re
import urllib
from cgi import escape
from string import maketrans
try:
from ast import parse as ast_parse
import ast
except ImportError: # python 2.5
from ast import parse as ast_parse
import ast
except ImportError: # python 2.5
from compiler import parse
import compiler.ast as ast
@@ -530,41 +531,47 @@ As shown in Ref.!`!`mdipierro`!`!:cite
``<ul/>``, ``<ol/>``, ``<code/>``, ``<table/>``, ``<blockquote/>``, ``<h1/>``, ..., ``<h6/>`` do not have ``<p>...</p>`` around them.
"""
html_colors=['aqua', 'black', 'blue', 'fuchsia', 'gray', 'green',
'lime', 'maroon', 'navy', 'olive', 'purple', 'red',
'silver', 'teal', 'white', 'yellow']
html_colors = ['aqua', 'black', 'blue', 'fuchsia', 'gray', 'green',
'lime', 'maroon', 'navy', 'olive', 'purple', 'red',
'silver', 'teal', 'white', 'yellow']
META = '\x06'
LINK = '\x07'
DISABLED_META = '\x08'
LATEX = '<img src="http://chart.apis.google.com/chart?cht=tx&chl=%s" />'
regex_URL=re.compile(r'@/(?P<a>\w*)/(?P<c>\w*)/(?P<f>\w*(\.\w+)?)(/(?P<args>[\w\.\-/]+))?')
regex_env2=re.compile(r'@\{(?P<a>[\w\-\.]+?)(\:(?P<b>.*?))?\}')
regex_expand_meta = re.compile('('+META+'|'+DISABLED_META+'|````)')
regex_dd=re.compile(r'\$\$(?P<latex>.*?)\$\$')
regex_code = re.compile('('+META+'|'+DISABLED_META+r'|````)|(``(?P<t>.+?)``(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[^\]]*)\])?)?)',re.S)
regex_strong=re.compile(r'\*\*(?P<t>[^\s*]+( +[^\s*]+)*)\*\*')
regex_del=re.compile(r'~~(?P<t>[^\s*]+( +[^\s*]+)*)~~')
regex_em=re.compile(r"''(?P<t>([^\s']| |'(?!'))+)''")
regex_num=re.compile(r"^\s*[+-]?((\d+(\.\d*)?)|\.\d+)([eE][+-]?[0-9]+)?\s*$")
regex_list=re.compile('^(?:(?:(#{1,6})|(?:(\.+|\++|\-+)(\.)?))\s*)?(.*)$')
regex_bq_headline=re.compile('^(?:(\.+|\++|\-+)(\.)?\s+)?(-{3}-*)$')
regex_tq=re.compile('^(-{3}-*)(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[a-zA-Z][_a-zA-Z\-\d]*)\])?)?$')
regex_URL = re.compile(r'@/(?P<a>\w*)/(?P<c>\w*)/(?P<f>\w*(\.\w+)?)(/(?P<args>[\w\.\-/]+))?')
regex_env2 = re.compile(r'@\{(?P<a>[\w\-\.]+?)(\:(?P<b>.*?))?\}')
regex_expand_meta = re.compile('(' + META + '|' + DISABLED_META + '|````)')
regex_dd = re.compile(r'\$\$(?P<latex>.*?)\$\$')
regex_code = re.compile(
'(' + META + '|' + DISABLED_META + r'|````)|(``(?P<t>.+?)``(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[^\]]*)\])?)?)',
re.S)
regex_strong = re.compile(r'\*\*(?P<t>[^\s*]+( +[^\s*]+)*)\*\*')
regex_del = re.compile(r'~~(?P<t>[^\s*]+( +[^\s*]+)*)~~')
regex_em = re.compile(r"''(?P<t>([^\s']| |'(?!'))+)''")
regex_num = re.compile(r"^\s*[+-]?((\d+(\.\d*)?)|\.\d+)([eE][+-]?[0-9]+)?\s*$")
regex_list = re.compile('^(?:(?:(#{1,6})|(?:(\.+|\++|\-+)(\.)?))\s*)?(.*)$')
regex_bq_headline = re.compile('^(?:(\.+|\++|\-+)(\.)?\s+)?(-{3}-*)$')
regex_tq = re.compile('^(-{3}-*)(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[a-zA-Z][_a-zA-Z\-\d]*)\])?)?$')
regex_proto = re.compile(r'(?<!["\w>/=])(?P<p>\w+):(?P<k>\w+://[\w\d\-+=?%&/:.]+)', re.M)
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=?%&/:.,;#]+\w|[\w\-.]+@[\w\-.]+)',re.M)
regex_link=re.compile(r'('+LINK+r')|\[\[(?P<s>.+?)\]\]',re.S)
regex_link_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?(?:\s+(?P<p>popup))?\s*$',re.S)
regex_media_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?\s+(?P<p>img|IMG|left|right|center|video|audio|blockleft|blockright)(?:\s+(?P<w>\d+px))?\s*$',re.S)
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=?%&/:.,;#]+\w|[\w\-.]+@[\w\-.]+)', re.M)
regex_link = re.compile(r'(' + LINK + r')|\[\[(?P<s>.+?)\]\]', re.S)
regex_link_level2 = re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?(?:\s+(?P<p>popup))?\s*$', re.S)
regex_media_level2 = re.compile(
r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?\s+(?P<p>img|IMG|left|right|center|video|audio|blockleft|blockright)(?:\s+(?P<w>\d+px))?\s*$',
re.S)
regex_markmin_escape = re.compile(r"(\\*)(['`:*~\\[\]{}@\$+\-.#\n])")
regex_backslash = re.compile(r"\\(['`:*~\\[\]{}@\$+\-.#\n])")
ttab_in = maketrans("'`:*~\\[]{}@$+-.#\n", '\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05')
ttab_out = maketrans('\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05',"'`:*~\\[]{}@$+-.#\n")
ttab_in = maketrans("'`:*~\\[]{}@$+-.#\n", '\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05')
ttab_out = maketrans('\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05', "'`:*~\\[]{}@$+-.#\n")
regex_quote = re.compile('(?P<name>\w+?)\s*\=\s*')
def make_dict(b):
return '{%s}' % regex_quote.sub("'\g<name>':",b)
return '{%s}' % regex_quote.sub("'\g<name>':", b)
def safe_eval(node_or_string, env):
"""
Safely evaluate an expression node or a string containing a Python
@@ -578,6 +585,7 @@ def safe_eval(node_or_string, env):
node_or_string = ast_parse(node_or_string, mode='eval')
if isinstance(node_or_string, ast.Expression):
node_or_string = node_or_string.body
def _convert(node):
if isinstance(node, ast.Str):
return node.s
@@ -594,11 +602,11 @@ def safe_eval(node_or_string, env):
if node.id in _safe_names:
return _safe_names[node.id]
elif isinstance(node, ast.BinOp) and \
isinstance(node.op, (Add, Sub)) and \
isinstance(node.right, Num) and \
isinstance(node.right.n, complex) and \
isinstance(node.left, Num) and \
isinstance(node.left.n, (int, long, float)):
isinstance(node.op, (Add, Sub)) and \
isinstance(node.right, Num) and \
isinstance(node.right.n, complex) and \
isinstance(node.left, Num) and \
isinstance(node.left.n, (int, long, float)):
left = node.left.n
right = node.right.n
if isinstance(node.op, Add):
@@ -606,57 +614,66 @@ def safe_eval(node_or_string, env):
else:
return left - right
raise ValueError('malformed string')
return _convert(node_or_string)
def markmin_escape(text):
""" insert \\ before markmin control characters: '`:*~[]{}@$ """
return regex_markmin_escape.sub(
lambda m: '\\'+m.group(0).replace('\\','\\\\'), text)
lambda m: '\\' + m.group(0).replace('\\', '\\\\'), text)
def replace_autolinks(text,autolinks):
def replace_autolinks(text, autolinks):
return regex_auto.sub(lambda m: autolinks(m.group('k')), text)
def replace_at_urls(text,url):
# this is experimental @{function/args}
def u1(match,url=url):
a,c,f,args = match.group('a','c','f','args')
return url(a=a or None,c=c or None,f = f or None,
args=(args or '').split('/'), scheme=True, host=True)
return regex_URL.sub(u1,text)
def replace_components(text,env):
def replace_at_urls(text, url):
# this is experimental @{function/args}
def u1(match, url=url):
a, c, f, args = match.group('a', 'c', 'f', 'args')
return url(a=a or None, c=c or None, f=f or None,
args=(args or '').split('/'), scheme=True, host=True)
return regex_URL.sub(u1, text)
def replace_components(text, env):
# not perfect but acceptable
def u2(match, env=env):
f = env.get(match.group('a'), match.group(0))
if callable(f):
b = match.group('b')
try:
b = safe_eval(make_dict(b),env)
b = safe_eval(make_dict(b), env)
except:
pass
try:
f = f(**b) if isinstance(b,dict) else f(b)
f = f(**b) if isinstance(b, dict) else f(b)
except Exception, e:
f = 'ERROR: %s' % e
return str(f)
text = regex_env2.sub(u2, text)
return text
def autolinks_simple(url):
"""
it automatically converts the url to link,
image, video or audio tag
"""
u_url=url.lower()
if '@' in url and not '://' in url:
u_url = url.lower()
if '@' in url and '://' not in url:
return '<a href="mailto:%s">%s</a>' % (url, url)
elif u_url.endswith(('.jpg','.jpeg','.gif','.png')):
elif u_url.endswith(('.jpg', '.jpeg', '.gif', '.png')):
return '<img src="%s" controls />' % url
elif u_url.endswith(('.mp4','.mpeg','.mov','.ogv')):
elif u_url.endswith(('.mp4', '.mpeg', '.mov', '.ogv')):
return '<video src="%s" controls></video>' % url
elif u_url.endswith(('.mp3','.wav','.ogg')):
elif u_url.endswith(('.mp3', '.wav', '.ogg')):
return '<audio src="%s" controls></audio>' % url
return '<a href="%s">%s</a>' % (url,url)
return '<a href="%s">%s</a>' % (url, url)
def protolinks_simple(proto, url):
"""
@@ -667,16 +684,18 @@ def protolinks_simple(proto, url):
proto="iframe"
url="http://www.example.com/path"
"""
if proto in ('iframe','embed'): #== 'iframe':
return '<iframe src="%s" frameborder="0" allowfullscreen></iframe>'%url
#elif proto == 'embed': # NOTE: embed is a synonym to iframe now
if proto in ('iframe', 'embed'): # == 'iframe':
return '<iframe src="%s" frameborder="0" allowfullscreen></iframe>' % url
# elif proto == 'embed': # NOTE: embed is a synonym to iframe now
# return '<a href="%s" class="%sembed">%s></a>'%(url,class_prefix,url)
elif proto == 'qr':
return '<img style="width:100px" src="http://chart.apis.google.com/chart?cht=qr&chs=100x100&chl=%s&choe=UTF-8&chld=H" alt="QR Code" title="QR Code" />'%url
return proto+':'+url
return '<img style="width:100px" src="http://chart.apis.google.com/chart?cht=qr&chs=100x100&chl=%s&choe=UTF-8&chld=H" alt="QR Code" title="QR Code" />' % url
return proto + ':' + url
def email_simple(email):
return '<a href="mailto:%s">%s</a>' % (email, email)
return '<a href="mailto:%s">%s</a>' % (email, email)
def render(text,
extra={},
@@ -925,17 +944,19 @@ def render(text,
>>> render("anchor with name 'NEWLINE': [[NEWLINE [newline] ]]")
'<p>anchor with name \\'NEWLINE\\': <span class="anchor" id="markmin_NEWLINE">newline</span></p>'
"""
if autolinks=="default": autolinks = autolinks_simple
if protolinks=="default": protolinks = protolinks_simple
pp='\n' if pretty_print else ''
if isinstance(text,unicode):
if autolinks == "default":
autolinks = autolinks_simple
if protolinks == "default":
protolinks = protolinks_simple
pp = '\n' if pretty_print else ''
if isinstance(text, unicode):
text = text.encode('utf8')
text = str(text or '')
text = regex_backslash.sub(lambda m: m.group(1).translate(ttab_in), text)
text = text.replace('\x05','').replace('\r\n', '\n') # concatenate strings separeted by \\n
text = text.replace('\x05', '').replace('\r\n', '\n') # concatenate strings separeted by \\n
if URL is not None:
text = replace_at_urls(text,URL)
text = replace_at_urls(text, URL)
if latex == 'google':
text = regex_dd.sub('``\g<latex>``:latex ', text)
@@ -945,9 +966,10 @@ def render(text,
# store them into segments they will be treated as code
#############################################################
segments = []
def mark_code(m):
g = m.group(0)
if g in (META, DISABLED_META ):
if g in (META, DISABLED_META):
segments.append((None, None, None, g))
return m.group()
elif g == '````':
@@ -956,10 +978,12 @@ def render(text,
else:
c = m.group('c') or ''
p = m.group('p') or ''
if 'code' in allowed and not c in allowed['code']: c = ''
code = m.group('t').replace('!`!','`')
if 'code' in allowed and c not in allowed['code']:
c = ''
code = m.group('t').replace('!`!', '`')
segments.append((code, c, p, m.group(0)))
return META
text = regex_code.sub(mark_code, text)
#############################################################
@@ -967,56 +991,58 @@ def render(text,
# store them into links they will be treated as link
#############################################################
links = []
def mark_link(m):
links.append( None if m.group() == LINK
else m.group('s') )
links.append(None if m.group() == LINK
else m.group('s'))
return LINK
text = regex_link.sub(mark_link, text)
text = escape(text)
if protolinks:
text = regex_proto.sub(lambda m: protolinks(*m.group('p','k')), text)
text = regex_proto.sub(lambda m: protolinks(*m.group('p', 'k')), text)
if autolinks:
text = replace_autolinks(text,autolinks)
text = replace_autolinks(text, autolinks)
#############################################################
# normalize spaces
#############################################################
strings=text.split('\n')
strings = text.split('\n')
def parse_title(t, s): #out, lev, etags, tag, s):
hlevel=str(len(t))
def parse_title(t, s): # out, lev, etags, tag, s):
hlevel = str(len(t))
out.extend(etags[::-1])
out.append("<h%s>%s"%(hlevel,s))
etags[:]=["</h%s>%s"%(hlevel,pp)]
lev=0
ltags[:]=[]
tlev[:]=[]
out.append("<h%s>%s" % (hlevel, s))
etags[:] = ["</h%s>%s" % (hlevel, pp)]
lev = 0
ltags[:] = []
tlev[:] = []
return (lev, 'h')
def parse_list(t, p, s, tag, lev, mtag, lineno):
lent=len(t)
if lent<lev: # current item level < previous item level
while ltags[-1]>lent:
lent = len(t)
if lent < lev: # current item level < previous item level
while ltags[-1] > lent:
ltags.pop()
out.append(etags.pop())
lev=lent
tlev[lev:]=[]
lev = lent
tlev[lev:] = []
if lent>lev: # current item level > previous item level
if lev==0: # previous line is not a list (paragraph or title)
if lent > lev: # current item level > previous item level
if lev == 0: # previous line is not a list (paragraph or title)
out.extend(etags[::-1])
ltags[:]=[]
tlev[:]=[]
etags[:]=[]
if pend and mtag == '.': # paragraph in a list:
ltags[:] = []
tlev[:] = []
etags[:] = []
if pend and mtag == '.': # paragraph in a list:
out.append(etags.pop())
ltags.pop()
for i in xrange(lent-lev):
out.append('<'+tag+'>'+pp)
etags.append('</'+tag+'>'+pp)
lev+=1
for i in xrange(lent - lev):
out.append('<' + tag + '>' + pp)
etags.append('</' + tag + '>' + pp)
lev += 1
ltags.append(lev)
tlev.append(tag)
elif lent == lev:
@@ -1025,22 +1051,22 @@ def render(text,
for i in xrange(ltags.count(lent)):
ltags.pop()
out.append(etags.pop())
tlev[-1]=tag
out.append('<'+tag+'>'+pp)
etags.append('</'+tag+'>'+pp)
tlev[-1] = tag
out.append('<' + tag + '>' + pp)
etags.append('</' + tag + '>' + pp)
ltags.append(lev)
else:
if ltags.count(lev)>1:
if ltags.count(lev) > 1:
out.append(etags.pop())
ltags.pop()
mtag='l'
mtag = 'l'
out.append('<li>')
etags.append('</li>'+pp)
etags.append('</li>' + pp)
ltags.append(lev)
if s[:1] == '-':
(s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno)
if p and mtag=='l':
(lev,mtag,lineno)=parse_point(t, s, lev, '', lineno)
if p and mtag == 'l':
(lev, mtag, lineno) = parse_point(t, s, lev, '', lineno)
else:
out.append(s)
@@ -1048,28 +1074,28 @@ def render(text,
def parse_point(t, s, lev, mtag, lineno):
""" paragraphs in lists """
lent=len(t)
if lent>lev:
lent = len(t)
if lent > lev:
return parse_list(t, '.', s, 'ul', lev, mtag, lineno)
elif lent<lev:
while ltags[-1]>lent:
elif lent < lev:
while ltags[-1] > lent:
ltags.pop()
out.append(etags.pop())
lev=lent
tlev[lev:]=[]
mtag=''
elif lent==lev:
lev = lent
tlev[lev:] = []
mtag = ''
elif lent == lev:
if pend and mtag == '.':
out.append(etags.pop())
ltags.pop()
if br and mtag in ('l','.'):
if br and mtag in ('l', '.'):
out.append(br)
if s == META:
mtag = ''
mtag = ''
else:
mtag = '.'
if s[:1] == '-':
(s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno)
(s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno)
if mtag == '.':
out.append(pbeg)
if pend:
@@ -1083,19 +1109,19 @@ def render(text,
# - is empty -> this is an <hr /> tag
# - consists '|' -> table
# - consists other characters -> blockquote
if (lineno+1 >= strings_len or
not(s.count('-') == len(s) and len(s)>3)):
return (s, mtag, lineno)
if (lineno + 1 >= strings_len or
not (s.count('-') == len(s) and len(s) > 3)):
return (s, mtag, lineno)
lineno+=1
lineno += 1
s = strings[lineno].strip()
if s:
if '|' in s:
# table
tout=[]
thead=[]
tbody=[]
rownum=0
tout = []
thead = []
tbody = []
rownum = 0
t_id = ''
t_cls = ''
@@ -1104,14 +1130,14 @@ def render(text,
s = strings[lineno].strip()
if s[:1] == '=':
# header or footer
if s.count('=')==len(s) and len(s)>3:
if not thead: # if thead list is empty:
if s.count('=') == len(s) and len(s) > 3:
if not thead: # if thead list is empty:
thead = tout
else:
tbody.extend(tout)
tout = []
rownum=0
lineno+=1
rownum = 0
lineno += 1
continue
m = regex_tq.match(s)
@@ -1121,36 +1147,36 @@ def render(text,
break
if rownum % 2:
tr = '<tr class="even">'
tr = '<tr class="even">'
else:
tr = '<tr class="first">' if rownum == 0 else '<tr>'
tr = '<tr class="first">' if rownum == 0 else '<tr>'
tout.append(tr + ''.join(['<td%s>%s</td>' % (
' class="num"'
if regex_num.match(f) else '',
f.strip()
) for f in s.split('|')])+'</tr>'+pp)
rownum+=1
lineno+=1
' class="num"'
if regex_num.match(f) else '',
f.strip()
) for f in s.split('|')]) + '</tr>' + pp)
rownum += 1
lineno += 1
t_cls = ' class="%s%s"'%(class_prefix, t_cls) \
t_cls = ' class="%s%s"' % (class_prefix, t_cls) \
if t_cls and t_cls != 'id' else ''
t_id = ' id="%s%s"'%(id_prefix, t_id) if t_id else ''
t_id = ' id="%s%s"' % (id_prefix, t_id) if t_id else ''
s = ''
if thead:
s += '<thead>'+pp+''.join([l for l in thead])+'</thead>'+pp
if not tbody: # tbody strings are in tout list
s += '<thead>' + pp + ''.join([l for l in thead]) + '</thead>' + pp
if not tbody: # tbody strings are in tout list
tbody = tout
tout = []
if tbody: # if tbody list is not empty:
s += '<tbody>'+pp+''.join([l for l in tbody])+'</tbody>'+pp
if tout: # tfoot is not empty:
s += '<tfoot>'+pp+''.join([l for l in tout])+'</tfoot>'+pp
if tbody: # if tbody list is not empty:
s += '<tbody>' + pp + ''.join([l for l in tbody]) + '</tbody>' + pp
if tout: # tfoot is not empty:
s += '<tfoot>' + pp + ''.join([l for l in tout]) + '</tfoot>' + pp
s = '<table%s%s>%s%s</table>%s' % (t_cls, t_id, pp, s, pp)
mtag='t'
mtag = 't'
else:
# parse blockquote:
bq_begin=lineno
t_mode = False # embedded table
bq_begin = lineno
t_mode = False # embedded table
t_cls = ''
t_id = ''
@@ -1160,57 +1186,57 @@ def render(text,
if not t_mode:
m = regex_tq.match(s)
if m:
if (lineno+1 == strings_len or
'|' not in strings[lineno+1]):
t_cls = m.group('c') or ''
t_id = m.group('p') or ''
break
if (lineno + 1 == strings_len or
'|' not in strings[lineno + 1]):
t_cls = m.group('c') or ''
t_id = m.group('p') or ''
break
if regex_bq_headline.match(s):
if (lineno+1 < strings_len and
strings[lineno+1].strip()):
t_mode = True
lineno+=1
if (lineno + 1 < strings_len and
strings[lineno + 1].strip()):
t_mode = True
lineno += 1
continue
elif regex_tq.match(s):
t_mode=False
lineno+=1
t_mode = False
lineno += 1
continue
lineno+=1
lineno += 1
t_cls = ' class="%s%s"'%(class_prefix,t_cls) \
t_cls = ' class="%s%s"' % (class_prefix, t_cls) \
if t_cls and t_cls != 'id' else ''
t_id = ' id="%s%s"'%(id_prefix,t_id) \
t_id = ' id="%s%s"' % (id_prefix, t_id) \
if t_id else ''
s = '<blockquote%s%s>%s</blockquote>%s' \
% (t_cls,
t_id,
'\n'.join(strings[bq_begin:lineno]),pp)
mtag='q'
% (t_cls,
t_id,
'\n'.join(strings[bq_begin:lineno]), pp)
mtag = 'q'
else:
s = '<hr />'
lineno-=1
mtag='q'
lineno -= 1
mtag = 'q'
return (s, 'q', lineno)
if sep == 'p':
pbeg = "<p>"
pend = "</p>"+pp
br = ''
pbeg = "<p>"
pend = "</p>" + pp
br = ''
else:
pbeg = pend = ''
br = "<br />"+pp if sep=='br' else ''
pbeg = pend = ''
br = "<br />" + pp if sep == 'br' else ''
lev = 0 # nesting level of lists
c0 = '' # first character of current line
out = [] # list of processed lines
etags = [] # trailing tags
ltags = [] # level# correspondent to trailing tag
lev = 0 # nesting level of lists
c0 = '' # first character of current line
out = [] # list of processed lines
etags = [] # trailing tags
ltags = [] # level# correspondent to trailing tag
tlev = [] # list of tags for each level ('ul' or 'ol')
mtag = '' # marked tag (~last tag) ('l','.','h','p','t'). Used to set <br/>
# and to avoid <p></p> around tables and blockquotes
# and to avoid <p></p> around tables and blockquotes
lineno = 0
strings_len = len(strings)
while lineno < strings_len:
@@ -1222,65 +1248,67 @@ def render(text,
#### ++++ ---- .... ------- field | field | field <-body
##### +++++ ----- ..... ---------------------:class[id]
"""
pc0=c0 # first character of previous line
c0=s[:1]
if c0: # for non empty strings
if c0 in "#+-.": # first character is one of: # + - .
(t1,t2,p,ss) = regex_list.findall(s)[0]
pc0 = c0 # first character of previous line
c0 = s[:1]
if c0: # for non empty strings
if c0 in "#+-.": # first character is one of: # + - .
(t1, t2, p, ss) = regex_list.findall(s)[0]
# t1 - tag ("###")
# t2 - tag ("+++", "---", "...")
# p - paragraph point ('.')->for "++." or "--."
# ss - other part of string
if t1 or t2:
# headers and lists:
if c0 == '#': # headers
if c0 == '#': # headers
(lev, mtag) = parse_title(t1, ss)
lineno+=1
lineno += 1
continue
elif c0 == '+': # ordered list
(lev, mtag, lineno)= parse_list(t2, p, ss, 'ol', lev, mtag, lineno)
lineno+=1
elif c0 == '+': # ordered list
(lev, mtag, lineno) = parse_list(t2, p, ss, 'ol', lev, mtag, lineno)
lineno += 1
continue
elif c0 == '-': # unordered list, table or blockquote
elif c0 == '-': # unordered list, table or blockquote
if p or ss:
(lev, mtag, lineno) = parse_list(t2, p, ss, 'ul', lev, mtag, lineno)
lineno+=1
lineno += 1
continue
else:
(s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno)
elif lev>0: # and c0 == '.' # paragraph in lists
elif lev > 0: # and c0 == '.' # paragraph in lists
(lev, mtag, lineno) = parse_point(t2, ss, lev, mtag, lineno)
lineno+=1
lineno += 1
continue
if lev == 0 and (mtag == 'q' or s == META):
# new paragraph
pc0=''
pc0 = ''
if pc0 == '' or (mtag != 'p' and s0 not in (' ','\t')):
if pc0 == '' or (mtag != 'p' and s0 not in (' ', '\t')):
# paragraph
out.extend(etags[::-1])
etags=[]
ltags=[]
tlev=[]
lev=0
if br and mtag == 'p': out.append(br)
etags = []
ltags = []
tlev = []
lev = 0
if br and mtag == 'p':
out.append(br)
if mtag != 'q' and s != META:
if pend: etags=[pend]
out.append(pbeg)
mtag = 'p'
if pend:
etags = [pend]
out.append(pbeg)
mtag = 'p'
else:
mtag = ''
mtag = ''
out.append(s)
else:
if lev>0 and mtag=='.' and s == META:
if lev > 0 and mtag == '.' and s == META:
out.append(etags.pop())
ltags.pop()
out.append(s)
mtag = ''
else:
out.append(' '+s)
lineno+=1
out.append(' ' + s)
lineno += 1
out.extend(etags[::-1])
text = ''.join(out)
@@ -1295,7 +1323,7 @@ def render(text,
# deal with images, videos, audios and links
#############################################################
def sub_media(m):
t,a,k,p,w = m.group('t','a','k','p','w')
t, a, k, p, w = m.group('t', 'a', 'k', 'p', 'w')
if not k:
return m.group(0)
k = escape(k)
@@ -1305,40 +1333,40 @@ def render(text,
p_begin = p_end = ''
if p == 'center':
p_begin = '<p style="text-align:center">'
p_end = '</p>'+pp
p_end = '</p>' + pp
elif p == 'blockleft':
p_begin = '<p style="text-align:left">'
p_end = '</p>'+pp
p_end = '</p>' + pp
elif p == 'blockright':
p_begin = '<p style="text-align:right">'
p_end = '</p>'+pp
elif p in ('left','right'):
style = ('float:%s' % p)+(';%s' % style if style else '')
p_end = '</p>' + pp
elif p in ('left', 'right'):
style = ('float:%s' % p) + (';%s' % style if style else '')
if t and regex_auto.match(t):
p_begin = p_begin + '<a href="%s">' % t
p_end = '</a>' + p_end
t = ''
if style:
style = ' style="%s"' % style
if p in ('video','audio'):
if p in ('video', 'audio'):
t = render(t, {}, {}, 'br', URL, environment, latex,
autolinks, protolinks, class_prefix, id_prefix, pretty_print)
return '<%(p)s controls="controls"%(title)s%(style)s><source src="%(k)s" />%(t)s</%(p)s>' \
% dict(p=p, title=title, style=style, k=k, t=t)
alt = ' alt="%s"'%escape(t).replace(META, DISABLED_META) if t else ''
% dict(p=p, title=title, style=style, k=k, t=t)
alt = ' alt="%s"' % escape(t).replace(META, DISABLED_META) if t else ''
return '%(begin)s<img src="%(k)s"%(alt)s%(title)s%(style)s />%(end)s' \
% dict(begin=p_begin, k=k, alt=alt, title=title, style=style, end=p_end)
% dict(begin=p_begin, k=k, alt=alt, title=title, style=style, end=p_end)
def sub_link(m):
t,a,k,p = m.group('t','a','k','p')
t, a, k, p = m.group('t', 'a', 'k', 'p')
if not k and not t:
return m.group(0)
t = t or ''
a = escape(a) if a else ''
if k:
if '#' in k and not ':' in k.split('#')[0]:
if '#' in k and ':' not in k.split('#')[0]:
# wikipage, not external url
k=k.replace('#','#'+id_prefix)
k = k.replace('#', '#' + id_prefix)
k = escape(k)
title = ' title="%s"' % a.replace(META, DISABLED_META) if a else ''
target = ' target="_blank"' if p == 'popup' else ''
@@ -1347,18 +1375,18 @@ def render(text,
return '<a href="%(k)s"%(title)s%(target)s>%(t)s</a>' \
% dict(k=k, title=title, target=target, t=t)
if t == 'NEWLINE' and not a:
return '<br />'+pp
return '<br />' + pp
return '<span class="anchor" id="%s">%s</span>' % (
escape(id_prefix+t),
render(a, {},{},'br', URL,
escape(id_prefix + t),
render(a, {}, {}, 'br', URL,
environment, latex, autolinks,
protolinks, class_prefix,
id_prefix, pretty_print))
parts = text.split(LINK)
text = parts[0]
for i,s in enumerate(links):
if s == None:
for i, s in enumerate(links):
if s is None:
html = LINK
else:
html = regex_media_level2.sub(sub_media, s)
@@ -1366,51 +1394,53 @@ def render(text,
html = regex_link_level2.sub(sub_link, html)
if html == s:
# return unprocessed string as a signal of an error
html = '[[%s]]'%s
text += html + parts[i+1]
html = '[[%s]]' % s
text += html + parts[i + 1]
#############################################################
# process all code text
#############################################################
def expand_meta(m):
code,b,p,s = segments.pop(0)
if code==None or m.group() == DISABLED_META:
code, b, p, s = segments.pop(0)
if code is None or m.group() == DISABLED_META:
return escape(s)
if b in extra:
if code[:1]=='\n': code=code[1:]
if code[-1:]=='\n': code=code[:-1]
if code[:1] == '\n':
code = code[1:]
if code[-1:] == '\n':
code = code[:-1]
if p:
return str(extra[b](code,p))
return str(extra[b](code, p))
else:
return str(extra[b](code))
elif b=='cite':
return '['+','.join('<a href="#%s" class="%s">%s</a>' \
% (id_prefix+d,b,d) \
for d in escape(code).split(','))+']'
elif b=='latex':
elif b == 'cite':
return '[' + ','.join('<a href="#%s" class="%s">%s</a>' %
(id_prefix + d, b, d) for d in escape(code).split(',')) + ']'
elif b == 'latex':
return LATEX % urllib.quote(code)
elif b in html_colors:
return '<span style="color: %s">%s</span>' \
% (b, render(code, {}, {}, 'br', URL, environment, latex,
autolinks, protolinks, class_prefix, id_prefix, pretty_print))
% (b, render(code, {}, {}, 'br', URL, environment, latex,
autolinks, protolinks, class_prefix, id_prefix, pretty_print))
elif b in ('c', 'color') and p:
c=p.split(':')
fg='color: %s;' % c[0] if c[0] else ''
bg='background-color: %s;' % c[1] if len(c)>1 and c[1] else ''
return '<span style="%s%s">%s</span>' \
% (fg, bg, render(code, {}, {}, 'br', URL, environment, latex,
autolinks, protolinks, class_prefix, id_prefix, pretty_print))
cls = ' class="%s%s"'%(class_prefix,b) if b and b != 'id' else ''
id = ' id="%s%s"'%(id_prefix,escape(p)) if p else ''
beg=(code[:1]=='\n')
end=[None,-1][code[-1:]=='\n']
c = p.split(':')
fg = 'color: %s;' % c[0] if c[0] else ''
bg = 'background-color: %s;' % c[1] if len(c) > 1 and c[1] else ''
return '<span style="%s%s">%s</span>' \
% (fg, bg, render(code, {}, {}, 'br', URL, environment, latex,
autolinks, protolinks, class_prefix, id_prefix, pretty_print))
cls = ' class="%s%s"' % (class_prefix, b) if b and b != 'id' else ''
id = ' id="%s%s"' % (id_prefix, escape(p)) if p else ''
beg = (code[:1] == '\n')
end = [None, -1][code[-1:] == '\n']
if beg and end:
return '<pre><code%s%s>%s</code></pre>%s' % (cls, id, escape(code[1:-1]), pp)
return '<code%s%s>%s</code>' % (cls, id, escape(code[beg:end]))
text = regex_expand_meta.sub(expand_meta, text)
if environment:
text = replace_components(text,environment)
text = replace_components(text, environment)
return text.translate(ttab_out)
@@ -1423,16 +1453,18 @@ def markmin2html(text, extra={}, allowed={}, sep='p',
class_prefix=class_prefix, id_prefix=id_prefix,
pretty_print=pretty_print)
def run_doctests():
import doctest
doctest.testmod()
if __name__ == '__main__':
import sys
import doctest
from textwrap import dedent
html=dedent("""
html = dedent("""
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
@@ -1446,7 +1478,7 @@ if __name__ == '__main__':
</html>""")[1:]
if sys.argv[1:2] == ['-h']:
style=dedent("""
style = dedent("""
<style>
blockquote { background-color: #FFFAAE; padding: 7px; }
table { border-collapse: collapse; }
@@ -1467,22 +1499,23 @@ if __name__ == '__main__':
body=markmin2html(__doc__, pretty_print=True))
elif sys.argv[1:2] == ['-t']:
from timeit import Timer
loops=1000
ts = Timer("markmin2html(__doc__)","from markmin2html import markmin2html")
loops = 1000
ts = Timer("markmin2html(__doc__)", "from markmin2html import markmin2html")
print 'timeit "markmin2html(__doc__)":'
t = min([ts.timeit(loops) for i in range(3)])
print "%s loops, best of 3: %.3f ms per loop" % (loops, t/1000*loops)
print "%s loops, best of 3: %.3f ms per loop" % (loops, t / 1000 * loops)
elif len(sys.argv) > 1:
fargv = open(sys.argv[1],'r')
fargv = open(sys.argv[1], 'r')
try:
markmin_text=fargv.read()
markmin_text = fargv.read()
# embed css file from second parameter into html file
if len(sys.argv) > 2:
if sys.argv[2].startswith('@'):
markmin_style = '<link rel="stylesheet" href="'+sys.argv[2][1:]+'"/>'
markmin_style = '<link rel="stylesheet" href="' + sys.argv[2][1:] + '"/>'
else:
fargv2 = open(sys.argv[2],'r')
fargv2 = open(sys.argv[2], 'r')
try:
markmin_style = "<style>\n" + fargv2.read() + "</style>"
finally:
@@ -1496,10 +1529,9 @@ if __name__ == '__main__':
fargv.close()
else:
print "Usage: "+sys.argv[0]+" -h | -t | file.markmin [file.css|@path_to/css]"
print "Usage: " + sys.argv[0] + " -h | -t | file.markmin [file.css|@path_to/css]"
print "where: -h - print __doc__"
print " -t - timeit __doc__ (for testing purpuse only)"
print " file.markmin [file.css] - process file.markmin + built in file.css (optional)"
print " file.markmin [@path_to/css] - process file.markmin + link path_to/css (optional)"
run_doctests()

View File

@@ -7,53 +7,57 @@ import sys
import doctest
from optparse import OptionParser
__all__ = ['render','markmin2latex']
__all__ = ['render', 'markmin2latex']
META = 'META'
regex_newlines = re.compile('(\n\r)|(\r\n)')
regex_dd=re.compile('\$\$(?P<latex>.*?)\$\$')
regex_code = re.compile('('+META+')|(``(?P<t>.*?)``(:(?P<c>\w+))?)',re.S)
regex_title = re.compile('^#{1} (?P<t>[^\n]+)',re.M)
regex_dd = re.compile('\$\$(?P<latex>.*?)\$\$')
regex_code = re.compile('(' + META + ')|(``(?P<t>.*?)``(:(?P<c>\w+))?)', re.S)
regex_title = re.compile('^#{1} (?P<t>[^\n]+)', re.M)
regex_maps = [
(re.compile('[ \t\r]+\n'),'\n'),
(re.compile('\*\*(?P<t>[^\s\*]+( +[^\s\*]+)*)\*\*'),'{\\\\bf \g<t>}'),
(re.compile("''(?P<t>[^\s']+( +[^\s']+)*)''"),'{\\it \g<t>}'),
(re.compile('^#{5,6}\s*(?P<t>[^\n]+)',re.M),'\n\n{\\\\bf \g<t>}\n'),
(re.compile('^#{4}\s*(?P<t>[^\n]+)',re.M),'\n\n\\\\goodbreak\\subsubsection{\g<t>}\n'),
(re.compile('^#{3}\s*(?P<t>[^\n]+)',re.M),'\n\n\\\\goodbreak\\subsection{\g<t>}\n'),
(re.compile('^#{2}\s*(?P<t>[^\n]+)',re.M),'\n\n\\\\goodbreak\\section{\g<t>}\n'),
(re.compile('^#{1}\s*(?P<t>[^\n]+)',re.M),''),
(re.compile('^\- +(?P<t>.*)',re.M),'\\\\begin{itemize}\n\\item \g<t>\n\\end{itemize}'),
(re.compile('^\+ +(?P<t>.*)',re.M),'\\\\begin{itemize}\n\\item \g<t>\n\\end{itemize}'),
(re.compile('\\\\end\{itemize\}\s+\\\\begin\{itemize\}'),'\n'),
(re.compile('\n\s+\n'),'\n\n')]
regex_table = re.compile('^\-{4,}\n(?P<t>.*?)\n\-{4,}(:(?P<c>\w+))?\n',re.M|re.S)
(re.compile('[ \t\r]+\n'), '\n'),
(re.compile('\*\*(?P<t>[^\s\*]+( +[^\s\*]+)*)\*\*'), '{\\\\bf \g<t>}'),
(re.compile("''(?P<t>[^\s']+( +[^\s']+)*)''"), '{\\it \g<t>}'),
(re.compile('^#{5,6}\s*(?P<t>[^\n]+)', re.M), '\n\n{\\\\bf \g<t>}\n'),
(re.compile('^#{4}\s*(?P<t>[^\n]+)', re.M), '\n\n\\\\goodbreak\\subsubsection{\g<t>}\n'),
(re.compile('^#{3}\s*(?P<t>[^\n]+)', re.M), '\n\n\\\\goodbreak\\subsection{\g<t>}\n'),
(re.compile('^#{2}\s*(?P<t>[^\n]+)', re.M), '\n\n\\\\goodbreak\\section{\g<t>}\n'),
(re.compile('^#{1}\s*(?P<t>[^\n]+)', re.M), ''),
(re.compile('^\- +(?P<t>.*)', re.M), '\\\\begin{itemize}\n\\item \g<t>\n\\end{itemize}'),
(re.compile('^\+ +(?P<t>.*)', re.M), '\\\\begin{itemize}\n\\item \g<t>\n\\end{itemize}'),
(re.compile('\\\\end\{itemize\}\s+\\\\begin\{itemize\}'), '\n'),
(re.compile('\n\s+\n'), '\n\n')]
regex_table = re.compile('^\-{4,}\n(?P<t>.*?)\n\-{4,}(:(?P<c>\w+))?\n', re.M | re.S)
regex_anchor = re.compile('\[\[(?P<t>\S+)\]\]')
regex_bibitem = re.compile('\-\s*\[\[(?P<t>\S+)\]\]')
regex_image_width = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +(?P<p>left|right|center) +(?P<w>\d+px)\]\]')
regex_image = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +(?P<p>left|right|center)\]\]')
#regex_video = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +video\]\]')
#regex_audio = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +audio\]\]')
# regex_video = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +video\]\]')
# regex_audio = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +audio\]\]')
regex_link = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+)\]\]')
regex_auto = re.compile('(?<!["\w])(?P<k>\w+://[\w\.\-\?&%\:]+)',re.M)
regex_auto = re.compile('(?<!["\w])(?P<k>\w+://[\w\.\-\?&%\:]+)', re.M)
regex_commas = re.compile('[ ]+(?P<t>[,;\.])')
regex_noindent = re.compile('\n\n(?P<t>[a-z])')
#regex_quote_left = re.compile('"(?=\w)')
#regex_quote_right = re.compile('(?=\w\.)"')
def latex_escape(text,pound=True):
text=text.replace('\\','{\\textbackslash}')
for c in '^_&$%{}': text=text.replace(c,'\\'+c)
text=text.replace('\\{\\textbackslash\\}','{\\textbackslash}')
if pound: text=text.replace('#','\\#')
# regex_quote_left = re.compile('"(?=\w)')
# regex_quote_right = re.compile('(?=\w\.)"')
def latex_escape(text, pound=True):
text = text.replace('\\', '{\\textbackslash}')
for c in '^_&$%{}':
text = text.replace(c, '\\' + c)
text = text.replace('\\{\\textbackslash\\}', '{\\textbackslash}')
if pound: text = text.replace('#', '\\#')
return text
def render(text,
extra={},
allowed={},
sep='p',
image_mapper=lambda x:x,
image_mapper=lambda x: x,
chapters=False):
#############################################################
# replace all blocks marked with ``...``:class with META
@@ -61,62 +65,68 @@ def render(text,
#############################################################
text = str(text or '')
segments, i = [], 0
text = regex_dd.sub('``\g<latex>``:latex ',text)
text = regex_newlines.sub('\n',text)
text = regex_dd.sub('``\g<latex>``:latex ', text)
text = regex_newlines.sub('\n', text)
while True:
item = regex_code.search(text,i)
if not item: break
if item.group()==META:
segments.append((None,None))
text = text[:item.start()]+META+text[item.end():]
item = regex_code.search(text, i)
if not item:
break
if item.group() == META:
segments.append((None, None))
text = text[:item.start()] + META + text[item.end():]
else:
c = item.group('c') or ''
if 'code' in allowed and not c in allowed['code']: c = ''
code = item.group('t').replace('!`!','`')
segments.append((code,c))
text = text[:item.start()]+META+text[item.end():]
i=item.start()+3
if 'code' in allowed and c not in allowed['code']:
c = ''
code = item.group('t').replace('!`!', '`')
segments.append((code, c))
text = text[:item.start()] + META + text[item.end():]
i = item.start() + 3
#############################################################
# do h1,h2,h3,h4,h5,h6,b,i,ol,ul and normalize spaces
#############################################################
title = regex_title.search(text)
if not title: title='Title'
else: title=title.group('t')
if not title:
title = 'Title'
else:
title = title.group('t')
text = latex_escape(text,pound=False)
text = latex_escape(text, pound=False)
texts = text.split('## References',1)
texts = text.split('## References', 1)
text = regex_anchor.sub('\\label{\g<t>}', texts[0])
if len(texts)==2:
if len(texts) == 2:
text += '\n\\begin{thebibliography}{999}\n'
text += regex_bibitem.sub('\n\\\\bibitem{\g<t>}', texts[1])
text += '\n\\end{thebibliography}\n'
text = '\n'.join(t.strip() for t in text.split('\n'))
for regex, sub in regex_maps:
text = regex.sub(sub,text)
text=text.replace('#','\\#')
text=text.replace('`',"'")
text = regex.sub(sub, text)
text = text.replace('#', '\\#')
text = text.replace('`', "'")
#############################################################
# process tables and blockquotes
#############################################################
while True:
item = regex_table.search(text)
if not item: break
if not item:
break
c = item.group('c') or ''
if 'table' in allowed and not c in allowed['table']: c = ''
if 'table' in allowed and c not in allowed['table']:
c = ''
content = item.group('t')
if ' | ' in content:
rows = content.replace('\n','\\\\\n').replace(' | ',' & ')
row0,row2 = rows.split('\\\\\n',1)
cols=row0.count(' & ')+1
cal='{'+''.join('l' for j in range(cols))+'}'
tabular = '\\begin{center}\n{\\begin{tabular}'+cal+'\\hline\n' + row0+'\\\\ \\hline\n'+row2 + ' \\\\ \\hline\n\\end{tabular}}\n\\end{center}'
if row2.count('\n')>20: tabular='\\newpage\n'+tabular
rows = content.replace('\n', '\\\\\n').replace(' | ', ' & ')
row0, row2 = rows.split('\\\\\n', 1)
cols = row0.count(' & ') + 1
cal = '{' + ''.join('l' for j in range(cols)) + '}'
tabular = '\\begin{center}\n{\\begin{tabular}' + cal + '\\hline\n' + row0 + '\\\\ \\hline\n' + row2 + ' \\\\ \\hline\n\\end{tabular}}\n\\end{center}'
if row2.count('\n') > 20:
tabular = '\\newpage\n' + tabular
text = text[:item.start()] + tabular + text[item.end():]
else:
text = text[:item.start()] + '\\begin{quote}' + content + '\\end{quote}' + text[item.end():]
@@ -126,29 +136,32 @@ def render(text,
#############################################################
def sub(x):
f=image_mapper(x.group('k'))
if not f: return None
return '\n\\begin{center}\\includegraphics[width=8cm]{%s}\\end{center}\n' % (f)
text = regex_image_width.sub(sub,text)
text = regex_image.sub(sub,text)
f = image_mapper(x.group('k'))
if not f:
return None
return '\n\\begin{center}\\includegraphics[width=8cm]{%s}\\end{center}\n' % f
text = regex_image_width.sub(sub, text)
text = regex_image.sub(sub, text)
text = regex_link.sub('{\\\\footnotesize\\href{\g<k>}{\g<t>}}', text)
text = regex_commas.sub('\g<t>',text)
text = regex_noindent.sub('\n\\\\noindent \g<t>',text)
text = regex_commas.sub('\g<t>', text)
text = regex_noindent.sub('\n\\\\noindent \g<t>', text)
### fix paths in images
regex=re.compile('\\\\_\w*\.(eps|png|jpg|gif)')
# ## fix paths in images
regex = re.compile('\\\\_\w*\.(eps|png|jpg|gif)')
while True:
match=regex.search(text)
if not match: break
text=text[:match.start()]+text[match.start()+1:]
#text = regex_quote_left.sub('``',text)
#text = regex_quote_right.sub("''",text)
match = regex.search(text)
if not match:
break
text = text[:match.start()] + text[match.start() + 1:]
# text = regex_quote_left.sub('``',text)
# text = regex_quote_right.sub("''",text)
if chapters:
text=text.replace(r'\section*{',r'\chapter*{')
text=text.replace(r'\section{',r'\chapter{')
text=text.replace(r'subsection{',r'section{')
text = text.replace(r'\section*{', r'\chapter*{')
text = text.replace(r'\section{', r'\chapter{')
text = text.replace(r'subsection{', r'section{')
#############################################################
# process all code text
@@ -156,57 +169,64 @@ def render(text,
parts = text.split(META)
text = parts[0]
authors = []
for i,(code,b) in enumerate(segments):
if code==None:
for i, (code, b) in enumerate(segments):
if code is None:
html = META
else:
if b=='hidden':
html=''
elif b=='author':
if b == 'hidden':
html = ''
elif b == 'author':
author = latex_escape(code.strip())
authors.append(author)
html=''
elif b=='inxx':
html='\inxx{%s}' % latex_escape(code)
elif b=='cite':
html='~\cite{%s}' % latex_escape(code.strip())
elif b=='ref':
html='~\ref{%s}' % latex_escape(code.strip())
elif b=='latex':
html = ''
elif b == 'inxx':
html = '\inxx{%s}' % latex_escape(code)
elif b == 'cite':
html = '~\cite{%s}' % latex_escape(code.strip())
elif b == 'ref':
html = '~\ref{%s}' % latex_escape(code.strip())
elif b == 'latex':
if '\n' in code:
html='\n\\begin{equation}\n%s\n\\end{equation}\n' % code.strip()
html = '\n\\begin{equation}\n%s\n\\end{equation}\n' % code.strip()
else:
html='$%s$' % code.strip()
elif b=='latex_eqnarray':
code=code.strip()
code='\\\\'.join(x.replace('=','&=&',1) for x in code.split('\\\\'))
html='\n\\begin{eqnarray}\n%s\n\\end{eqnarray}\n' % code
html = '$%s$' % code.strip()
elif b == 'latex_eqnarray':
code = code.strip()
code = '\\\\'.join(x.replace('=', '&=&', 1) for x in code.split('\\\\'))
html = '\n\\begin{eqnarray}\n%s\n\\end{eqnarray}\n' % code
elif b.startswith('latex_'):
key=b[6:]
html='\\begin{%s}%s\\end{%s}' % (key,code,key)
key = b[6:]
html = '\\begin{%s}%s\\end{%s}' % (key, code, key)
elif b in extra:
if code[:1]=='\n': code=code[1:]
if code[-1:]=='\n': code=code[:-1]
if code[:1] == '\n':
code = code[1:]
if code[-1:] == '\n':
code = code[:-1]
html = extra[b](code)
elif code[:1]=='\n' or code[:-1]=='\n':
if code[:1]=='\n': code=code[1:]
if code[-1:]=='\n': code=code[:-1]
elif code[:1] == '\n' or code[:-1] == '\n':
if code[:1] == '\n':
code = code[1:]
if code[-1:] == '\n':
code = code[:-1]
if code.startswith('<') or code.startswith('{{') or code.startswith('http'):
html = '\\begin{lstlisting}[keywords={}]\n%s\n\\end{lstlisting}' % code
else:
html = '\\begin{lstlisting}\n%s\n\\end{lstlisting}' % code
else:
if code[:1]=='\n': code=code[1:]
if code[-1:]=='\n': code=code[:-1]
if code[:1] == '\n':
code = code[1:]
if code[-1:] == '\n':
code = code[:-1]
html = '{\\ft %s}' % latex_escape(code)
try:
text = text+html+parts[i+1]
text = text + html + parts[i + 1]
except:
text = text + '... WIKI PROCESSING ERROR ...'
break
text = text.replace(' ~\\cite','~\\cite')
text = text.replace(' ~\\cite', '~\\cite')
return text, title, authors
WRAPPER = """
\\documentclass[12pt]{article}
\\usepackage{hyperref}
@@ -239,12 +259,14 @@ WRAPPER = """
\\end{document}
"""
def markmin2latex(data, image_mapper=lambda x:x, extra={},
def markmin2latex(data, image_mapper=lambda x: x, extra={},
wrapper=WRAPPER):
body, title, authors = render(data, extra=extra, image_mapper=image_mapper)
author = '\n\\and\n'.join(a.replace('\n','\\\\\n\\footnotesize ') for a in authors)
author = '\n\\and\n'.join(a.replace('\n', '\\\\\n\\footnotesize ') for a in authors)
return wrapper % dict(title=title, author=author, body=body)
if __name__ == '__main__':
parser = OptionParser()
parser.add_option("-i", "--info", dest="info",
@@ -252,40 +274,39 @@ if __name__ == '__main__':
parser.add_option("-t", "--test", dest="test", action="store_true",
default=False)
parser.add_option("-n", "--no_wrapper", dest="no_wrapper",
action="store_true",default=False)
parser.add_option("-c", "--chapters", dest="chapters",action="store_true",
default=False,help="switch section for chapter")
action="store_true", default=False)
parser.add_option("-c", "--chapters", dest="chapters", action="store_true",
default=False, help="switch section for chapter")
parser.add_option("-w", "--wrapper", dest="wrapper", default=False,
help="latex file containing header and footer")
(options, args) = parser.parse_args()
if options.info:
import markmin2html
markmin2latex(markmin2html.__doc__)
elif options.test:
doctest.testmod()
else:
if options.wrapper:
fwrapper = open(options.wrapper,'rb')
fwrapper = open(options.wrapper, 'rb')
try:
wrapper = fwrapper.read()
finally:
fwrapper.close()
elif options.no_wrapper:
wrapper = '%(body)s'
wrapper = '%(body)s'
else:
wrapper = WRAPPER
for f in args:
fargs = open(f,'r')
fargs = open(f, 'r')
content_data = []
try:
content_data.append(fargs.read())
finally:
fargs.close()
content = '\n'.join(content_data)
output= markmin2latex(content,
wrapper=wrapper,
chapters=options.chapters)
output = markmin2latex(content,
wrapper=wrapper,
chapters=options.chapters)
print output

Some files were not shown because too many files have changed in this diff Show More