Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9d80fcdc7 | ||
|
|
3f7d085f73 | ||
|
|
d57dd72780 | ||
|
|
a8d1d5cfcf | ||
|
|
8857e3d521 | ||
|
|
3b1a5be1be | ||
|
|
c9a63a8524 | ||
|
|
cd967d2551 | ||
|
|
92b5247f9f | ||
|
|
45a5b436c8 | ||
|
|
bfd385f969 | ||
|
|
f693fe6b2a | ||
|
|
b040159a9b | ||
|
|
f3af2a1999 | ||
|
|
f613a4cc99 | ||
|
|
e4a96125a6 | ||
|
|
e48074ff54 | ||
|
|
2ed122a534 | ||
|
|
65c0d9b18b | ||
|
|
6702694590 | ||
|
|
6f0d4d039e | ||
|
|
1325b0e48f | ||
|
|
7421eb8068 | ||
|
|
6c7a9a4030 | ||
|
|
ba0a143717 | ||
|
|
28bcb5ed6c |
+25
@@ -0,0 +1,25 @@
|
|||||||
|
language: python
|
||||||
|
|
||||||
|
python:
|
||||||
|
- '2.5'
|
||||||
|
- '2.6'
|
||||||
|
- '2.7'
|
||||||
|
env:
|
||||||
|
- DB=sqlite:memory
|
||||||
|
- DB=mysql://root:@localhost/test_w2p
|
||||||
|
- DB=postgres://postgres:@localhost/test_w2p
|
||||||
|
before_script:
|
||||||
|
- pip install unittest2
|
||||||
|
- if [[ $DB == postgres* ]]; then pip install --use-mirrors psycopg2; fi
|
||||||
|
- if [[ $TRAVIS_PYTHON_VERSION == '2.5' ]]; then pip install --use-mirrors pysqlite; fi
|
||||||
|
- if [[ $DB == mysql* ]]; then mysql -e 'create database test_w2p;'; fi
|
||||||
|
- if [[ $DB == postgres* ]]; then psql -c 'create database test_w2p;' -U postgres; fi
|
||||||
|
#Temporal solution to travis issue #155
|
||||||
|
- sudo chmod 777 /dev/shm
|
||||||
|
- sudo rm -rf /dev/shm && sudo ln -s /run/shm /dev/shm
|
||||||
|
script: PYTHONPATH=. unit2 -v gluon.tests
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
||||||
|
irc:
|
||||||
|
channels: "irc.freenode.org#web2py"
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
|
## 2.4.5
|
||||||
|
|
||||||
|
- travis.ci integration (thanks Marc Abramowitz and Niphlod). Passes all tests (thanks Niplod).
|
||||||
|
- IS_DATE and IS_DATETIME can specify timezone
|
||||||
|
|
||||||
## 2.4.1- 2.4.3
|
## 2.4.1- 2.4.3
|
||||||
|
|
||||||
- 2D GEO API: geoPoint, getLine, geoPolygon
|
- 2D GEO API: geoPoint, getLine, geoPolygon
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ all:
|
|||||||
clean:
|
clean:
|
||||||
rm -f httpserver.log
|
rm -f httpserver.log
|
||||||
rm -f parameters*.py
|
rm -f parameters*.py
|
||||||
rm -f -r applications/*/compiled
|
rm -f -r applications/*/compiled
|
||||||
find ./ -name '*~' -exec rm -f {} \;
|
find ./ -name '*~' -exec rm -f {} \;
|
||||||
find ./ -name '*.orig' -exec rm -f {} \;
|
find ./ -name '*.orig' -exec rm -f {} \;
|
||||||
find ./ -name '*.rej' -exec rm -f {} \;
|
find ./ -name '*.rej' -exec rm -f {} \;
|
||||||
@@ -30,7 +30,7 @@ update:
|
|||||||
echo "remember that pymysql was tweaked"
|
echo "remember that pymysql was tweaked"
|
||||||
src:
|
src:
|
||||||
### Use semantic versioning
|
### Use semantic versioning
|
||||||
echo 'Version 2.4.4-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
echo 'Version 2.4.5-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
||||||
### rm -f all junk files
|
### rm -f all junk files
|
||||||
make clean
|
make clean
|
||||||
### clean up baisc apps
|
### clean up baisc apps
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ It is written and programmable in Python. LGPLv3 License
|
|||||||
|
|
||||||
Learn more at http://web2py.com
|
Learn more at http://web2py.com
|
||||||
|
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
[](https://travis-ci.org/web2py/web2py)
|
||||||
|
|
||||||
## Installation Instructions
|
## Installation Instructions
|
||||||
|
|
||||||
To start web2py there is NO NEED to install it. Just unzip and do:
|
To start web2py there is NO NEED to install it. Just unzip and do:
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Version 2.4.4-stable+timestamp.2013.03.11.15.25.57
|
Version 2.4.5-stable+timestamp.2013.03.18.17.37.19
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ td.w2p_fl,td.w2p_fc {padding:0;}
|
|||||||
==============================================================*/
|
==============================================================*/
|
||||||
|
|
||||||
/* because web2py handles this via js */
|
/* because web2py handles this via js */
|
||||||
|
textarea { width:90%}
|
||||||
.hidden{visibility:visible;}
|
.hidden{visibility:visible;}
|
||||||
/* right folder for bootstrap black images/icons */
|
/* right folder for bootstrap black images/icons */
|
||||||
[class^="icon-"],[class*=" icon-"]{
|
[class^="icon-"],[class*=" icon-"]{
|
||||||
|
|||||||
@@ -1,69 +1,69 @@
|
|||||||
{{extend 'layout.html'}}
|
{{extend 'layout.html'}}
|
||||||
{{
|
{{
|
||||||
def all(items):
|
def all(items):
|
||||||
return reduce(lambda a,b:a and b,items,True)
|
return reduce(lambda a,b:a and b,items,True)
|
||||||
def peekfile(path,file,vars={},title=None):
|
def peekfile(path,file,vars={},title=None):
|
||||||
args=(path,file) if 'app' in vars else (app,path,file)
|
args=(path,file) if 'app' in vars else (app,path,file)
|
||||||
return A(file.replace('\\\\','/'),_title=title,_href=URL('peek', args=args, vars=vars))
|
return A(file.replace('\\\\','/'),_title=title,_href=URL('peek', args=args, vars=vars))
|
||||||
def editfile(path,file,vars={}):
|
def editfile(path,file,vars={}):
|
||||||
args=(path,file) if 'app' in vars else (app,path,file)
|
args=(path,file) if 'app' in vars else (app,path,file)
|
||||||
return A(SPAN(T('Edit')),_class='button editbutton btn btn-mini',_href=URL('edit', args=args, vars=vars))
|
return A(SPAN(T('Edit')),_class='button editbutton btn btn-mini',_href=URL('edit', args=args, vars=vars))
|
||||||
def testfile(path,file):
|
def testfile(path,file):
|
||||||
return A(TAG[''](IMG(_src=URL('static', 'images/test_icon.png'), _alt=T('test')),
|
return A(TAG[''](IMG(_src=URL('static', 'images/test_icon.png'), _alt=T('test')),
|
||||||
SPAN(T("Run tests in this file (to run all files, you may also use the button labelled 'test')"))),
|
SPAN(T("Run tests in this file (to run all files, you may also use the button labelled 'test')"))),
|
||||||
_class='icon test',
|
_class='icon test',
|
||||||
_href=URL('test', args=(app, file)),
|
_href=URL('test', args=(app, file)),
|
||||||
_rel="tooltip",
|
_rel="tooltip",
|
||||||
**{'_data-placement':'right',
|
**{'_data-placement':'right',
|
||||||
'_data-original-title':T("Run tests in this file (to run all files, you may also use the button labelled 'test')")})
|
'_data-original-title':T("Run tests in this file (to run all files, you may also use the button labelled 'test')")})
|
||||||
def editlanguagefile(path,file,vars={}):
|
def editlanguagefile(path,file,vars={}):
|
||||||
return A(SPAN(T('Edit')),_class='button editbutton btn btn-mini',_href=URL('edit_language', args=(app, path, file), vars=vars))
|
return A(SPAN(T('Edit')),_class='button editbutton btn btn-mini',_href=URL('edit_language', args=(app, path, file), vars=vars))
|
||||||
def editpluralsfile(path,file,vars={}):
|
def editpluralsfile(path,file,vars={}):
|
||||||
return A(SPAN(T('Edit')),_class='button editbutton btn btn-mini',_href=URL('edit_plurals', args=(app, path, file), vars=vars))
|
return A(SPAN(T('Edit')),_class='button editbutton btn btn-mini',_href=URL('edit_plurals', args=(app, path, file), vars=vars))
|
||||||
def file_upload_form(location, anchor=None):
|
def file_upload_form(location, anchor=None):
|
||||||
form=FORM(
|
form=FORM(
|
||||||
LABEL(T("upload file:")),
|
LABEL(T("upload file:")),
|
||||||
INPUT(_type="file",_name="file"),
|
INPUT(_type="file",_name="file"),
|
||||||
LABEL(T("and rename it:")),
|
LABEL(T("and rename it:")),
|
||||||
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY,_class=""),
|
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY,_class=""),
|
||||||
DIV(TAG['BUTTON'](T("Upload"),_type="submit",_class="btn"),_class="controls"),
|
DIV(TAG['BUTTON'](T("Upload"),_type="submit",_class="btn"),_class="controls"),
|
||||||
INPUT(_type="hidden",_name="location",_value=location),
|
INPUT(_type="hidden",_name="location",_value=location),
|
||||||
INPUT(_type="hidden",_name="token",_value=session.token),
|
INPUT(_type="hidden",_name="token",_value=session.token),
|
||||||
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app, anchor=anchor)),
|
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app, anchor=anchor)),
|
||||||
_action=URL('upload_file'),
|
_action=URL('upload_file'),
|
||||||
_class="generatedbyw2p well well-small")
|
_class="generatedbyw2p well well-small")
|
||||||
return form
|
return form
|
||||||
def file_create_form(location, anchor=None, helptext=""):
|
def file_create_form(location, anchor=None, helptext=""):
|
||||||
form=FORM(
|
form=FORM(
|
||||||
LABEL(T("create file with filename:")),
|
LABEL(T("create file with filename:")),
|
||||||
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY,_class=''),
|
INPUT(_type="text",_name="filename",requires=IS_NOT_EMPTY,_class=''),
|
||||||
TAG['SMALL'](helptext,_class="help-block"),
|
TAG['SMALL'](helptext,_class="help-block"),
|
||||||
DIV(TAG['BUTTON'](T("Create"),_type="submit",_class="btn"),_class="controls"),
|
DIV(TAG['BUTTON'](T("Create"),_type="submit",_class="btn"),_class="controls"),
|
||||||
INPUT(_type="hidden",_name="location",_value=location),
|
INPUT(_type="hidden",_name="location",_value=location),
|
||||||
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app)),
|
INPUT(_type="hidden",_name="sender",_value=URL('design',args=app)),
|
||||||
INPUT(_type="hidden",_name="token",_value=session.token),
|
INPUT(_type="hidden",_name="token",_value=session.token),
|
||||||
INPUT(_type="hidden",_name="id",_value=anchor),
|
INPUT(_type="hidden",_name="id",_value=anchor),
|
||||||
_action=URL('create_file'),
|
_action=URL('create_file'),
|
||||||
_class="generatedbyw2p well well-small")
|
_class="generatedbyw2p well well-small")
|
||||||
return form
|
return form
|
||||||
def upload_plugin_form(app, anchor=None):
|
def upload_plugin_form(app, anchor=None):
|
||||||
form=FORM(
|
form=FORM(
|
||||||
LABEL(T("upload plugin file:")),
|
LABEL(T("upload plugin file:")),
|
||||||
INPUT(_type="file",_name="pluginfile"),
|
INPUT(_type="file",_name="pluginfile"),
|
||||||
INPUT(_type="hidden",_name="id",_value=anchor),
|
INPUT(_type="hidden",_name="id",_value=anchor),
|
||||||
INPUT(_type="hidden",_name="token",_value=session.token),
|
INPUT(_type="hidden",_name="token",_value=session.token),
|
||||||
DIV(TAG['BUTTON'](T("Upload"),_type="submit",_class="btn"),_class="controls"),
|
DIV(TAG['BUTTON'](T("Upload"),_type="submit",_class="btn"),_class="controls"),
|
||||||
_class="generatedbyw2p well well-small")
|
_class="generatedbyw2p well well-small")
|
||||||
return form
|
return form
|
||||||
def deletefile(arglist, vars={}):
|
def deletefile(arglist, vars={}):
|
||||||
vars.update({'sender':request.function+'/'+app})
|
vars.update({'sender':request.function+'/'+app})
|
||||||
return A(TAG[''](IMG(_src=URL('static', 'images/delete_icon.png')),
|
return A(TAG[''](IMG(_src=URL('static', 'images/delete_icon.png')),
|
||||||
SPAN(T('Delete this file (you will be asked to confirm deletion)'))),
|
SPAN(T('Delete this file (you will be asked to confirm deletion)'))),
|
||||||
_href=URL('delete',args=arglist,vars=vars),
|
_href=URL('delete',args=arglist,vars=vars),
|
||||||
_class='icon delete',
|
_class='icon delete',
|
||||||
_rel="tooltip",
|
_rel="tooltip",
|
||||||
**{'_data-placement':'right',
|
**{'_data-placement':'right',
|
||||||
'_data-original-title':T('Delete this file (you will be asked to confirm deletion)')})
|
'_data-original-title':T('Delete this file (you will be asked to confirm deletion)')})
|
||||||
}}
|
}}
|
||||||
|
|
||||||
{{block sectionclass}}design{{end}}
|
{{block sectionclass}}design{{end}}
|
||||||
@@ -91,45 +91,45 @@ def deletefile(arglist, vars={}):
|
|||||||
|
|
||||||
<!-- MODELS -->
|
<!-- MODELS -->
|
||||||
<h3 id="_models" rel="pagebookmark">
|
<h3 id="_models" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('models_inner');">{{=T("Models")}}</span>
|
<span class="component" onclick="collapse('models_inner');">{{=T("Models")}}</span>
|
||||||
<a href="#models" rel="tooltip" data-placement="right" data-original-title="{{=T('The data representation, define database tables and sets')}}">
|
<a href="#models" rel="tooltip" data-placement="right" data-original-title="{{=T('The data representation, define database tables and sets')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("The data representation, define database tables and sets")}}</span>
|
<span>{{=T("The data representation, define database tables and sets")}}</span>
|
||||||
</a><span id="models" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
</a><span id="models" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="models_inner" class="component_contents">
|
<div id="models_inner" class="component_contents">
|
||||||
{{if not models:}}<p><strong>{{=T("There are no models")}}</strong></p>{{else:}}
|
{{if not models:}}<p><strong>{{=T("There are no models")}}</strong></p>{{else:}}
|
||||||
<div class="controls comptools">
|
<div class="controls comptools">
|
||||||
{{=button(URL(a=app,c='appadmin',f='index'), T('database administration'))}}
|
{{=button(URL(a=app,c='appadmin',f='index'), T('database administration'))}}
|
||||||
{{if os.access(os.path.join(request.folder,'..',app,'databases','sql.log'),os.R_OK):}}
|
{{if os.access(os.path.join(request.folder,'..',app,'databases','sql.log'),os.R_OK):}}
|
||||||
{{=button(URL('peek/%s/databases/sql.log'%app), 'sql.log')}}
|
{{=button(URL('peek/%s/databases/sql.log'%app), 'sql.log')}}
|
||||||
{{pass}}
|
{{pass}}
|
||||||
{{=button(URL(a=app, c='appadmin',f='graph_model'), T('graph model'))}}
|
{{=button(URL(a=app, c='appadmin',f='graph_model'), T('graph model'))}}
|
||||||
</div>
|
</div>
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{for m in models:}}
|
{{for m in models:}}
|
||||||
{{id="models__"+m.replace('.','__')}}
|
{{id="models__"+m.replace('.','__')}}
|
||||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editfile('models',m, dict(id=id))}}
|
{{=editfile('models',m, dict(id=id))}}
|
||||||
{{=deletefile([app, 'models', m], dict(id=id, id2='models'))}}
|
{{=deletefile([app, 'models', m], dict(id=id, id2='models'))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
{{=peekfile('models',m, dict(id=id))}}
|
{{=peekfile('models',m, dict(id=id))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="extras">
|
<span class="extras">
|
||||||
{{if len(defines[m]):}}{{=T("defines tables")}} {{pass}}{{=XML(', '.join([B(table).xml() for table in defines[m]]))}}
|
{{if len(defines[m]):}}{{=T("defines tables")}} {{pass}}{{=XML(', '.join([B(table).xml() for table in defines[m]]))}}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<button onclick="jQuery('#form1').slideToggle()" class="btn btn-mini">Create</button>
|
<button onclick="jQuery('#form1').slideToggle()" class="btn btn-mini">Create</button>
|
||||||
<div id="form1" class="row-fluid" style="display:none">
|
<div id="form1" class="row-fluid" style="display:none">
|
||||||
<div class="span3">{{=file_create_form('%s/models/' % app, 'models')}}</div>
|
<div class="span3">{{=file_create_form('%s/models/' % app, 'models')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- FIND CONTROLLER FUNCTIONS -->
|
<!-- FIND CONTROLLER FUNCTIONS -->
|
||||||
@@ -140,330 +140,330 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
|||||||
|
|
||||||
<!-- CONTROLLERS -->
|
<!-- CONTROLLERS -->
|
||||||
<h3 id="_controllers" rel="pagebookmark">
|
<h3 id="_controllers" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('controllers_inner');">{{=T("Controllers")}}</span>
|
<span class="component" onclick="collapse('controllers_inner');">{{=T("Controllers")}}</span>
|
||||||
<a href="#controllers" rel="tooltip" data-placement="right" data-original-title="{{=T('The application logic, each URL path is mapped in one exposed function in the controller')}}">
|
<a href="#controllers" rel="tooltip" data-placement="right" data-original-title="{{=T('The application logic, each URL path is mapped in one exposed function in the controller')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("The application logic, each URL path is mapped in one exposed function in the controller")}}</span>
|
<span>{{=T("The application logic, each URL path is mapped in one exposed function in the controller")}}</span>
|
||||||
</a><span id="controllers" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
</a><span id="controllers" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="controllers_inner" class="component_contents">
|
<div id="controllers_inner" class="component_contents">
|
||||||
{{if not controllers:}}<p><strong>{{=T("There are no controllers")}}</strong></p>{{else:}}
|
{{if not controllers:}}<p><strong>{{=T("There are no controllers")}}</strong></p>{{else:}}
|
||||||
<div class="controls comptools">
|
<div class="controls comptools">
|
||||||
{{=button(URL(r=request,c='shell',f='index',args=app), T("shell"))}}
|
{{=button(URL(r=request,c='shell',f='index',args=app), T("shell"))}}
|
||||||
{{=button(URL('test',args=app), T("test"))}}
|
{{=button(URL('test',args=app), T("test"))}}
|
||||||
{{=button(URL('edit',args=[app,'cron','crontab']), T("crontab"))}}
|
{{=button(URL('edit',args=[app,'cron','crontab']), T("crontab"))}}
|
||||||
</div>
|
</div>
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{for c in controllers:}}
|
{{for c in controllers:}}
|
||||||
{{id="controllers__"+c.replace('.','__')}}
|
{{id="controllers__"+c.replace('.','__')}}
|
||||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editfile('controllers',c, dict(id=id))}}
|
{{=editfile('controllers',c, dict(id=id))}}
|
||||||
{{=deletefile([app, 'controllers', c], dict(id=id, id2='controllers'))}}
|
{{=deletefile([app, 'controllers', c], dict(id=id, id2='controllers'))}}
|
||||||
{{=testfile('controllers',c)}}
|
{{=testfile('controllers',c)}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
{{=peekfile('controllers',c, dict(id=id))}}
|
{{=peekfile('controllers',c, dict(id=id))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="extras celled">
|
<span class="extras celled">
|
||||||
{{if functions[c]:}}{{=T("exposes")}}{{pass}} {{=XML(', '.join([A(f,_href=URL(a=app,c=c[:-3],f=f)).xml() for f in functions[c]]))}}
|
{{if functions[c]:}}{{=T("exposes")}}{{pass}} {{=XML(', '.join([A(f,_href=URL(a=app,c=c[:-3],f=f)).xml() for f in functions[c]]))}}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<button onclick="jQuery('#form2').slideToggle()" class="btn btn-mini">Create</button>
|
<button onclick="jQuery('#form2').slideToggle()" class="btn btn-mini">Create</button>
|
||||||
<div id="form2" class="row-fluid" style="display:none">
|
<div id="form2" class="row-fluid" style="display:none">
|
||||||
<div class="span3">{{=file_create_form('%s/controllers/' % app, 'controllers')}}</div>
|
<div class="span3">{{=file_create_form('%s/controllers/' % app, 'controllers')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- VIEWS -->
|
<!-- VIEWS -->
|
||||||
<h3 id="_views" rel="pagebookmark">
|
<h3 id="_views" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('views_inner');">{{=T("Views")}}</span>
|
<span class="component" onclick="collapse('views_inner');">{{=T("Views")}}</span>
|
||||||
<a href="#views" rel="tooltip" data-placement="right" data-original-title="{{=T('The presentations layer, views are also known as templates')}}">
|
<a href="#views" rel="tooltip" data-placement="right" data-original-title="{{=T('The presentations layer, views are also known as templates')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("The presentations layer, views are also known as templates")}}</span>
|
<span>{{=T("The presentations layer, views are also known as templates")}}</span>
|
||||||
</a><span id="views" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
</a><span id="views" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="views_inner" class="component_contents">
|
<div id="views_inner" class="component_contents">
|
||||||
{{if not views:}}<p><strong>{{=T("There are no views")}}</strong></p>{{else:}}
|
{{if not views:}}<p><strong>{{=T("There are no views")}}</strong></p>{{else:}}
|
||||||
<div class="controls comptools">
|
<div class="controls comptools">
|
||||||
{{=button(LAYOUTS_APP, T("download layouts"))}}
|
{{=button(LAYOUTS_APP, T("download layouts"))}}
|
||||||
</div>
|
</div>
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{for c in views:}}
|
{{for c in views:}}
|
||||||
{{id="views__"+c.replace('/','__').replace('.','__')}}
|
{{id="views__"+c.replace('/','__').replace('.','__')}}
|
||||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editfile('views',c, dict(id=id))}}
|
{{=editfile('views',c, dict(id=id))}}
|
||||||
{{=deletefile([app, 'views', c], dict(id=id, id2='views'))}}
|
{{=deletefile([app, 'views', c], dict(id=id, id2='views'))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
{{=peekfile('views',c, dict(id=id))}}
|
{{=peekfile('views',c, dict(id=id))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="extras celled celled-one">
|
<span class="extras celled celled-one">
|
||||||
{{if extend.has_key(c):}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
|
{{if extend.has_key(c):}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
|
||||||
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
|
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<button onclick="jQuery('#form3').slideToggle()" class="btn btn-mini">Create</button>
|
<button onclick="jQuery('#form3').slideToggle()" class="btn btn-mini">Create</button>
|
||||||
<div id="form3" class="row-fluid" style="display:none">
|
<div id="form3" class="row-fluid" style="display:none">
|
||||||
<div class="span3">{{=file_create_form('%s/views/' % app, 'views')}}</div>
|
<div class="span3">{{=file_create_form('%s/views/' % app, 'views')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- LANGUAGES -->
|
<!-- LANGUAGES -->
|
||||||
<h3 id="_languages" rel="pagebookmark">
|
<h3 id="_languages" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('languages_inner');">{{=T("Languages")}}</span>
|
<span class="component" onclick="collapse('languages_inner');">{{=T("Languages")}}</span>
|
||||||
<a href="#languages" rel="tooltip" data-placement="right" data-original-title="{{=T('Translation strings for the application')}}">
|
<a href="#languages" rel="tooltip" data-placement="right" data-original-title="{{=T('Translation strings for the application')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("Translation strings for the application")}}</span>
|
<span>{{=T("Translation strings for the application")}}</span>
|
||||||
</a><span id="languages" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
</a><span id="languages" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="languages_inner" class="component_contents">
|
<div id="languages_inner" class="component_contents">
|
||||||
{{if not languages:}}<p><strong>{{=T("There are no translators, only default language is supported")}}</strong></p>{{else:}}
|
{{if not languages:}}<p><strong>{{=T("There are no translators, only default language is supported")}}</strong></p>{{else:}}
|
||||||
<div class="controls comptools">
|
<div class="controls comptools">
|
||||||
{{=button(URL('update_languages/'+app), T('update all languages'))}}
|
{{=button(URL('update_languages/'+app), T('update all languages'))}}
|
||||||
</div>
|
</div>
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{for lang in sorted(languages):
|
{{for lang in sorted(languages):
|
||||||
file = lang+'.py'
|
file = lang+'.py'
|
||||||
id = "languages__"+file.replace('.','__')}}
|
id = "languages__"+file.replace('.','__')}}
|
||||||
<li id="{{='_'+id}}" rel="pagebookmark" class="li-row"><span id="{{=id}}" class="hashstick"> </span>
|
<li id="{{='_'+id}}" rel="pagebookmark" class="li-row"><span id="{{=id}}" class="hashstick"> </span>
|
||||||
<span class="li-controls">
|
<span class="li-controls">
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editlanguagefile('languages',file)}}
|
{{=editlanguagefile('languages',file)}}
|
||||||
{{=deletefile([app, 'languages', file], dict(id=id, id2='languages'))}}
|
{{=deletefile([app, 'languages', file], dict(id=id, id2='languages'))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="">
|
<span class="">
|
||||||
{{=peekfile('languages',file, dict(id=id))}}
|
{{=peekfile('languages',file, dict(id=id))}}
|
||||||
</span>
|
</span>
|
||||||
</span> <!-- /li-row -->
|
</span> <!-- /li-row -->
|
||||||
<span class="extras celled">
|
<span class="extras celled">
|
||||||
(
|
(
|
||||||
{{=T("Plural-Forms:")}}
|
{{=T("Plural-Forms:")}}
|
||||||
{{p=languages[lang][3:7]}}
|
{{p=languages[lang][3:7]}}
|
||||||
{{if p[2] == 'default':}}
|
{{if p[2] == 'default':}}
|
||||||
<span class='error text-error'>{{=T("rules are not defined")}}</span> {{=T.M("(file **gluon/contrib/plural_rules/%s.py** is not found)",lang[:2])}}
|
<span class='error text-error'>{{=T("rules are not defined")}}</span> {{=T.M("(file **gluon/contrib/plural_rules/%s.py** is not found)",lang[:2])}}
|
||||||
{{else:}}
|
{{else:}}
|
||||||
{{if p[3] == 1:}}
|
{{if p[3] == 1:}}
|
||||||
{{=B(T("are not used"))}}
|
{{=B(T("are not used"))}}
|
||||||
{{else:}}
|
{{else:}}
|
||||||
{{pfile=p[0]}}
|
{{pfile=p[0]}}
|
||||||
{{if p[1]!=0:}}<span style="display:inline-block;margin-top:-10px;">
|
{{if p[1]!=0:}}<span style="display:inline-block;margin-top:-10px;">
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editpluralsfile('languages',pfile,dict(nplurals=p[3]))}}
|
{{=editpluralsfile('languages',pfile,dict(nplurals=p[3]))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
{{=peekfile('languages',pfile,dict(id=id))}}
|
{{=peekfile('languages',pfile,dict(id=id))}}
|
||||||
</span></span>
|
</span></span>
|
||||||
{{else:}}
|
{{else:}}
|
||||||
<b>{{=T("are not used yet")}}</b>
|
<b>{{=T("are not used yet")}}</b>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
{{pass}}
|
{{pass}}
|
||||||
{{pass}}
|
{{pass}}
|
||||||
)
|
)
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<button onclick="jQuery('#form4').slideToggle()" class="btn btn-mini">Create</button>
|
<button onclick="jQuery('#form4').slideToggle()" class="btn btn-mini">Create</button>
|
||||||
<div id="form4" class="row-fluid" style="display:none">
|
<div id="form4" class="row-fluid" style="display:none">
|
||||||
<div class="span3">{{=file_create_form('%s/languages/' % app, 'languages', T('(something like "it-it")'))}}</div>
|
<div class="span3">{{=file_create_form('%s/languages/' % app, 'languages', T('(something like "it-it")'))}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- STATIC -->
|
<!-- STATIC -->
|
||||||
<h3 id="_static" rel="pagebookmark">
|
<h3 id="_static" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('static_inner');">{{=T("Static")}}</span>
|
<span class="component" onclick="collapse('static_inner');">{{=T("Static")}}</span>
|
||||||
<a href="#static" rel="tooltip" data-placement="right" data-original-title="{{=T('These files are served without processing, your images go here')}}">
|
<a href="#static" rel="tooltip" data-placement="right" data-original-title="{{=T('These files are served without processing, your images go here')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("These files are served without processing, your images go here")}}</span>
|
<span>{{=T("These files are served without processing, your images go here")}}</span>
|
||||||
</a><span id="static" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
</a><span id="static" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="static_inner" class="component_contents">
|
<div id="static_inner" class="component_contents">
|
||||||
{{if not statics:}}<p><strong>{{=T("There are no static files")}}</strong></p>{{else:}}
|
{{if not statics:}}<p><strong>{{=T("There are no static files")}}</strong></p>{{else:}}
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{
|
{{
|
||||||
path=[]
|
path=[]
|
||||||
for file in statics+['']:
|
for file in statics+['']:
|
||||||
items=file.split('/')
|
items=file.split('/')
|
||||||
file_path=items[:-1]
|
file_path=items[:-1]
|
||||||
filename=items[-1]
|
filename=items[-1]
|
||||||
while path!=file_path:
|
while path!=file_path:
|
||||||
if len(file_path)>=len(path) and all([v==file_path[k] for k,v in enumerate(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)])
|
path.append(file_path[len(path)])
|
||||||
thispath='static__'+'__'.join(path)
|
thispath='static__'+'__'.join(path)
|
||||||
}}
|
}}
|
||||||
<li class="folder"><i> </i>
|
<li class="folder"><i> </i>
|
||||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
||||||
else:
|
else:
|
||||||
path = path[:-1]
|
path = path[:-1]
|
||||||
}}
|
}}
|
||||||
</ul></li>
|
</ul></li>
|
||||||
{{
|
{{
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
if filename:
|
if filename:
|
||||||
}}
|
}}
|
||||||
<li>
|
<li>
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editfile('static',file, dict(id="static"))}} {{=deletefile([app,'static',file], dict(id="static",id2="static"))}}
|
{{=editfile('static',file, dict(id="static"))}} {{=deletefile([app,'static',file], dict(id="static",id2="static"))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
<a href="{{=URL(a=app,c='static',f=file)}}">{{=filename}}</a>
|
<a href="{{=URL(a=app,c='static',f=file)}}">{{=filename}}</a>
|
||||||
</span>
|
</span>
|
||||||
</li>{{
|
</li>{{
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
}}
|
}}
|
||||||
</ul>
|
</ul>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<button onclick="jQuery('#form5').slideToggle()" class="btn btn-mini">Create/Upload</button>
|
<button onclick="jQuery('#form5').slideToggle()" class="btn btn-mini">Create/Upload</button>
|
||||||
<div id="form5" class="row-fluid" style="display:none">
|
<div id="form5" class="row-fluid" style="display:none">
|
||||||
<div class="span3">{{=file_create_form('%s/static/' % app, 'static')}}<em>{{=T('or alternatively')}}</em></div>
|
<div class="span3">{{=file_create_form('%s/static/' % app, 'static')}}<em>{{=T('or alternatively')}}</em></div>
|
||||||
<div class="span3">{{=file_upload_form('%s/static/' % app, 'static')}}</div>
|
<div class="span3">{{=file_upload_form('%s/static/' % app, 'static')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- MODULES -->
|
<!-- MODULES -->
|
||||||
<h3 id="_modules" rel="pagebookmark">
|
<h3 id="_modules" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('modules_inner');">{{=T("Modules")}}</span>
|
<span class="component" onclick="collapse('modules_inner');">{{=T("Modules")}}</span>
|
||||||
<a href="#modules" rel="tooltip" data-placement="right" data-original-title="{{=T('Additional code for your application')}}">
|
<a href="#modules" rel="tooltip" data-placement="right" data-original-title="{{=T('Additional code for your application')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("Additional code for your application")}}</span>
|
<span>{{=T("Additional code for your application")}}</span>
|
||||||
</a><span id="modules" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
</a><span id="modules" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="modules_inner" class="component_contents">
|
<div id="modules_inner" class="component_contents">
|
||||||
{{if not modules:}}<p><strong>{{=T("There are no modules")}}</strong></p>{{else:}}
|
{{if not modules:}}<p><strong>{{=T("There are no modules")}}</strong></p>{{else:}}
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{for m in modules:}}
|
{{for m in modules:}}
|
||||||
{{id="modules__"+m.replace('/','__').replace('.','__')}}
|
{{id="modules__"+m.replace('/','__').replace('.','__')}}
|
||||||
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
<li id="{{='_'+id}}" rel="pagebookmark"><span id="{{=id}}" class="hashstick"> </span>
|
||||||
<span class="filetols controls">
|
<span class="filetols controls">
|
||||||
{{=editfile('modules',m,dict(id=id))}}
|
{{=editfile('modules',m,dict(id=id))}}
|
||||||
{{if m!='__init__.py':}}
|
{{if m!='__init__.py':}}
|
||||||
{{=deletefile([app, 'modules', m], dict(id=id, id2='modules'))}}
|
{{=deletefile([app, 'modules', m], dict(id=id, id2='modules'))}}
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
{{=peekfile('modules',m, dict(id=id))}}
|
{{=peekfile('modules',m, dict(id=id))}}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<button onclick="jQuery('#form5').slideToggle()" class="btn btn-mini">Create/Upload</button>
|
<button onclick="jQuery('#form6').slideToggle()" class="btn btn-mini">Create/Upload</button>
|
||||||
<div id="form5" class="row-fluid" style="display:none">
|
<div id="form6" class="row-fluid" style="display:none">
|
||||||
<div class="span3">{{=file_create_form('%s/modules/' % app, 'modules')}}<em>{{=T('or alternatively')}}</em></div>
|
<div class="span3">{{=file_create_form('%s/modules/' % app, 'modules')}}<em>{{=T('or alternatively')}}</em></div>
|
||||||
<div class="span3">{{=file_upload_form('%s/modules/' % app, 'modules')}}</div>
|
<div class="span3">{{=file_upload_form('%s/modules/' % app, 'modules')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- PRIVATE -->
|
<!-- PRIVATE -->
|
||||||
<h3 id="_private" rel="pagebookmark">
|
<h3 id="_private" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('private_inner');">{{=T("Private files")}}</span>
|
<span class="component" onclick="collapse('private_inner');">{{=T("Private files")}}</span>
|
||||||
<a href="#private" rel="tooltip" data-placement="right" data-original-title="{{=T('These files are not served, they are only available from within your app')}}">
|
<a href="#private" rel="tooltip" data-placement="right" data-original-title="{{=T('These files are not served, they are only available from within your app')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("These files are not served, they are only available from within your app")}}</span>
|
<span>{{=T("These files are not served, they are only available from within your app")}}</span>
|
||||||
</a><span id="private" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
</a><span id="private" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="private_inner" class="component_contents">
|
<div id="private_inner" class="component_contents">
|
||||||
{{if not privates:}}<p><strong>{{=T("There are no private files")}}</strong></p>{{else:}}
|
{{if not privates:}}<p><strong>{{=T("There are no private files")}}</strong></p>{{else:}}
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{
|
{{
|
||||||
path=[]
|
path=[]
|
||||||
for file in privates+['']:
|
for file in privates+['']:
|
||||||
items=file.split('/')
|
items=file.split('/')
|
||||||
file_path=items[:-1]
|
file_path=items[:-1]
|
||||||
filename=items[-1]
|
filename=items[-1]
|
||||||
while path!=file_path:
|
while path!=file_path:
|
||||||
if len(file_path)>=len(path) and all([v==file_path[k] for k,v in enumerate(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)])
|
path.append(file_path[len(path)])
|
||||||
thispath='private__'+'__'.join(path)
|
thispath='private__'+'__'.join(path)
|
||||||
}}
|
}}
|
||||||
<li class="folder">
|
<li class="folder">
|
||||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||||
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
<ul id="{{=thispath}}" style="display: none;" class="sublist">{{
|
||||||
else:
|
else:
|
||||||
path = path[:-1]
|
path = path[:-1]
|
||||||
}}
|
}}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{{
|
{{
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
if filename:
|
if filename:
|
||||||
}}
|
}}
|
||||||
<li>
|
<li>
|
||||||
<span class="filetools controls">
|
<span class="filetools controls">
|
||||||
{{=editfile('private',file, dict(id="private"))}} {{=deletefile([app,'private',file], dict(id="private",id2="private"))}}
|
{{=editfile('private',file, dict(id="private"))}} {{=deletefile([app,'private',file], dict(id="private",id2="private"))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="file">
|
<span class="file">
|
||||||
{{=peekfile('private',file, dict(id="private"))}}
|
{{=peekfile('private',file, dict(id="private"))}}
|
||||||
</span>
|
</span>
|
||||||
</li>{{
|
</li>{{
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
}}
|
}}
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<button onclick="jQuery('#form6').slideToggle()" class="btn btn-mini">Create/Upload</button>
|
<button onclick="jQuery('#form7').slideToggle()" class="btn btn-mini">Create/Upload</button>
|
||||||
<div id="form6" class="row-fluid" style="display:none">
|
<div id="form7" class="row-fluid" style="display:none">
|
||||||
<div class="span3">{{=file_create_form('%s/private/' % app, 'private')}}<em>{{=T('or alternatively')}}</em></div>
|
<div class="span3">{{=file_create_form('%s/private/' % app, 'private')}}<em>{{=T('or alternatively')}}</em></div>
|
||||||
<div class="span3">{{=file_upload_form('%s/private/' % app, 'private')}}</div>
|
<div class="span3">{{=file_upload_form('%s/private/' % app, 'private')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- PLUGINS -->
|
<!-- PLUGINS -->
|
||||||
<h3 id="_plugins" rel="pagebookmark">
|
<h3 id="_plugins" rel="pagebookmark">
|
||||||
<span class="component" onclick="collapse('plugins_inner');">{{=T("Plugins")}}</span>
|
<span class="component" onclick="collapse('plugins_inner');">{{=T("Plugins")}}</span>
|
||||||
<a href="#plugins" rel="tooltip" data-placement="right" data-original-title="{{=T('To create a plugin, name a file/folder plugin_[name]')}}">
|
<a href="#plugins" rel="tooltip" data-placement="right" data-original-title="{{=T('To create a plugin, name a file/folder plugin_[name]')}}">
|
||||||
{{=helpicon()}}
|
{{=helpicon()}}
|
||||||
<span>{{=T("To create a plugin, name a file/folder plugin_[name]")}}</span>
|
<span>{{=T("To create a plugin, name a file/folder plugin_[name]")}}</span>
|
||||||
</a><span id="plugins" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
</a><span id="plugins" class="hashstick"> </span><a href="#" class="tophashlink btn btn-mini btn-warning"><span>top</span></a>
|
||||||
</h3>
|
</h3>
|
||||||
<div id="plugins_inner" class="component_contents">
|
<div id="plugins_inner" class="component_contents">
|
||||||
<div class="controls comptools">
|
<div class="controls comptools">
|
||||||
{{=button(PLUGINS_APP, T('download plugins'))}}
|
{{=button(PLUGINS_APP, T('download plugins'))}}
|
||||||
</div>
|
</div>
|
||||||
{{if plugins:}}
|
{{if plugins:}}
|
||||||
<ul class="unstyled act_edit">
|
<ul class="unstyled act_edit">
|
||||||
{{for plugin in plugins:}}
|
{{for plugin in plugins:}}
|
||||||
{{id="plugins__"+plugin.replace('/','__').replace('.','__')}}
|
{{id="plugins__"+plugin.replace('/','__').replace('.','__')}}
|
||||||
<li id="{{=id}}">
|
<li id="{{=id}}">
|
||||||
{{=A('plugin_%s' % plugin, _class='file', _href=URL('plugin', args=[app, plugin], vars=dict(id=id, id2='plugins')))}}
|
{{=A('plugin_%s' % plugin, _class='file', _href=URL('plugin', args=[app, plugin], vars=dict(id=id, id2='plugins')))}}
|
||||||
</li>
|
</li>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
{{else:}}
|
{{else:}}
|
||||||
<p><strong>{{=T('There are no plugins')}}</strong></p>
|
<p><strong>{{=T('There are no plugins')}}</strong></p>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<div class="controls formfield">
|
<div class="controls formfield">
|
||||||
<button onclick="jQuery('#form7').slideToggle()" class="btn btn-mini">Upload</button>
|
<button onclick="jQuery('#form8').slideToggle()" class="btn btn-mini">Upload</button>
|
||||||
<div id="form7" class="row-fluid" style="display:none">
|
<div id="form8" class="row-fluid" style="display:none">
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<div class="span3">{{=upload_plugin_form(app, 'plugins')}}</div>
|
<div class="span3">{{=upload_plugin_form(app, 'plugins')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
session.connect(request,response,cookie_key='yoursecret')
|
||||||
@@ -102,6 +102,7 @@ td.w2p_fl,td.w2p_fc {padding:0;}
|
|||||||
==============================================================*/
|
==============================================================*/
|
||||||
|
|
||||||
/* because web2py handles this via js */
|
/* because web2py handles this via js */
|
||||||
|
textarea { width:90%}
|
||||||
.hidden{visibility:visible;}
|
.hidden{visibility:visible;}
|
||||||
/* right folder for bootstrap black images/icons */
|
/* right folder for bootstrap black images/icons */
|
||||||
[class^="icon-"],[class*=" icon-"]{
|
[class^="icon-"],[class*=" icon-"]{
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ random.shuffle(quotes)
|
|||||||
<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 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="{{=URL('download')}}" style="margin-top:10px; width:180px; color:white">Download Now</a><br/>
|
||||||
<a class="btn btn-danger" href="http://web2py.com/demo_admin" style="margin-top:10px; width:180px; color:white">Online Demo</a><br/>
|
<a class="btn btn-danger" href="http://web2py.com/demo_admin" style="margin-top:10px; width:180px; color:white">Online Demo</a><br/>
|
||||||
<a class="btn btn-danger" href="http://web2py.com/poweredby" style="margin-top:10px; width:180px; color:white">Sites Powereb by web2py</a>
|
<a class="btn btn-danger" href="http://web2py.com/poweredby" style="margin-top:10px; width:180px; color:white">Sites Powered by web2py</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
'!langcode!': 'it',
|
'!langcode!': 'it',
|
||||||
'!langname!': 'Italiano',
|
'!langname!': 'Italiano',
|
||||||
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" è un\'espressione opzionale come "campo1=\'nuovo valore\'". Non si può fare "update" o "delete" dei risultati di un JOIN ',
|
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" è un\'espressione opzionale come "campo1=\'nuovo valore\'". Non si può fare "update" o "delete" dei risultati di un JOIN ',
|
||||||
'%(nrows)s records found': '%(nrows)s records found',
|
'%(nrows)s records found': '%(nrows)s record trovati',
|
||||||
'%d seconds ago': '%d seconds ago',
|
'%d seconds ago': '%d secondi fa',
|
||||||
'%s %%{row} deleted': '%s righe ("record") cancellate',
|
'%s %%{row} deleted': '%s righe ("record") cancellate',
|
||||||
'%s %%{row} updated': '%s righe ("record") modificate',
|
'%s %%{row} updated': '%s righe ("record") modificate',
|
||||||
'%s selected': '%s selezionato',
|
'%s selected': '%s selezionato',
|
||||||
@@ -16,40 +16,41 @@
|
|||||||
'=': '=',
|
'=': '=',
|
||||||
'>': '>',
|
'>': '>',
|
||||||
'>=': '>=',
|
'>=': '>=',
|
||||||
'@markmin\x01Number of entries: **%s**': 'Number of entries: **%s**',
|
'@markmin\x01Number of entries: **%s**': 'Numero di entità: **%s**',
|
||||||
'About': 'About',
|
'About': 'About',
|
||||||
'Access Control': 'Access Control',
|
'Access Control': 'Controllo Accessi',
|
||||||
'Add': 'Add',
|
'Add': 'Aggiungi',
|
||||||
'Administrative Interface': 'Administrative Interface',
|
'Administrative Interface': 'Interfaccia Amministrativa',
|
||||||
'Administrative interface': 'Interfaccia amministrativa',
|
'Administrative interface': 'Interfaccia amministrativa',
|
||||||
'Ajax Recipes': 'Ajax Recipes',
|
'Ajax Recipes': 'Ajax Recipes',
|
||||||
'And': 'And',
|
'An error occured, please %s the page': "E' stato rilevato un errore, prego %s la pagina",
|
||||||
|
'And': 'E',
|
||||||
'appadmin is disabled because insecure channel': 'Amministrazione (appadmin) disabilitata: comunicazione non sicura',
|
'appadmin is disabled because insecure channel': 'Amministrazione (appadmin) disabilitata: comunicazione non sicura',
|
||||||
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
|
'Are you sure you want to delete this object?': 'Sicuro di voler cancellare questo oggetto ?',
|
||||||
'Available Databases and Tables': 'Database e tabelle disponibili',
|
'Available Databases and Tables': 'Database e tabelle disponibili',
|
||||||
'Back': 'Back',
|
'Back': 'Indietro',
|
||||||
'Buy this book': 'Buy this book',
|
'Buy this book': 'Compra questo libro',
|
||||||
'cache': 'cache',
|
'cache': 'cache',
|
||||||
'Cache': 'Cache',
|
'Cache': 'Cache',
|
||||||
'Cache Keys': 'Cache Keys',
|
'Cache Keys': 'Cache Keys',
|
||||||
'Cannot be empty': 'Non può essere vuoto',
|
'Cannot be empty': 'Non può essere vuoto',
|
||||||
'Change password': 'Change password',
|
'Change password': 'Cambia Password',
|
||||||
'change password': 'Cambia password',
|
'change password': 'Cambia password',
|
||||||
'Check to delete': 'Seleziona per cancellare',
|
'Check to delete': 'Seleziona per cancellare',
|
||||||
'Clear': 'Clear',
|
'Clear': 'Resetta',
|
||||||
'Clear CACHE?': 'Clear CACHE?',
|
'Clear CACHE?': 'Resetta CACHE?',
|
||||||
'Clear DISK': 'Clear DISK',
|
'Clear DISK': 'Resetta DISK',
|
||||||
'Clear RAM': 'Clear RAM',
|
'Clear RAM': 'Resetta RAM',
|
||||||
'Client IP': 'Client IP',
|
'Client IP': 'Client IP',
|
||||||
'Close': 'Close',
|
'Close': 'Chiudi',
|
||||||
'Cognome': 'Cognome',
|
'Cognome': 'Cognome',
|
||||||
'Community': 'Community',
|
'Community': 'Community',
|
||||||
'Components and Plugins': 'Components and Plugins',
|
'Components and Plugins': 'Componenti and Plugin',
|
||||||
'contains': 'contains',
|
'contains': 'contiene',
|
||||||
'Controller': 'Controller',
|
'Controller': 'Controller',
|
||||||
'Copyright': 'Copyright',
|
'Copyright': 'Copyright',
|
||||||
'Created By': 'Created By',
|
'Created By': 'Creato Da',
|
||||||
'Created On': 'Created On',
|
'Created On': 'Creato Il',
|
||||||
'CSV': 'CSV',
|
'CSV': 'CSV',
|
||||||
'CSV (hidden cols)': 'CSV (hidden cols)',
|
'CSV (hidden cols)': 'CSV (hidden cols)',
|
||||||
'Current request': 'Richiesta (request) corrente',
|
'Current request': 'Richiesta (request) corrente',
|
||||||
@@ -61,7 +62,7 @@
|
|||||||
'Database %s select': 'Database %s select',
|
'Database %s select': 'Database %s select',
|
||||||
'db': 'db',
|
'db': 'db',
|
||||||
'DB Model': 'Modello di DB',
|
'DB Model': 'Modello di DB',
|
||||||
'Delete': 'Delete',
|
'Delete': 'Cancella',
|
||||||
'Delete:': 'Cancella:',
|
'Delete:': 'Cancella:',
|
||||||
'Demo': 'Demo',
|
'Demo': 'Demo',
|
||||||
'Deployment Recipes': 'Deployment Recipes',
|
'Deployment Recipes': 'Deployment Recipes',
|
||||||
@@ -71,7 +72,7 @@
|
|||||||
'Disk Cache Keys': 'Disk Cache Keys',
|
'Disk Cache Keys': 'Disk Cache Keys',
|
||||||
'Disk Cleared': 'Disk Cleared',
|
'Disk Cleared': 'Disk Cleared',
|
||||||
'Documentation': 'Documentazione',
|
'Documentation': 'Documentazione',
|
||||||
"Don't know what to do?": "Don't know what to do?",
|
"Don't know what to do?": 'Non sai cosa fare?',
|
||||||
'done!': 'fatto!',
|
'done!': 'fatto!',
|
||||||
'Download': 'Download',
|
'Download': 'Download',
|
||||||
'E-mail': 'E-mail',
|
'E-mail': 'E-mail',
|
||||||
@@ -79,18 +80,19 @@
|
|||||||
'Edit current record': 'Modifica record corrente',
|
'Edit current record': 'Modifica record corrente',
|
||||||
'edit profile': 'modifica profilo',
|
'edit profile': 'modifica profilo',
|
||||||
'Edit This App': 'Modifica questa applicazione',
|
'Edit This App': 'Modifica questa applicazione',
|
||||||
'Email and SMS': 'Email and SMS',
|
'Email and SMS': 'Email e SMS',
|
||||||
'Email non valida': 'Email non valida',
|
'Email non valida': 'Email non valida',
|
||||||
'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': 'inserisci un intero tra %(min)g e %(max)g',
|
||||||
'Errors': 'Errors',
|
'Errors': 'Errori',
|
||||||
'Errors in form, please check it out.': 'Errors in form, please check it out.',
|
'Errors in form, please check it out.': 'Errori nel form, ricontrollalo',
|
||||||
'export as csv file': 'esporta come file CSV',
|
'export as csv file': 'esporta come file CSV',
|
||||||
'Export:': 'Export:',
|
'Export:': 'Esporta:',
|
||||||
'FAQ': 'FAQ',
|
'FAQ': 'FAQ',
|
||||||
'First name': 'Nome',
|
'First name': 'Nome',
|
||||||
'Forgot username?': 'Forgot username?',
|
'Forgot username?': 'Dimenticato lo username?',
|
||||||
'Forms and Validators': 'Forms and Validators',
|
'Forms and Validators': 'Forms and Validators',
|
||||||
'Free Applications': 'Free Applications',
|
'Free Applications': 'Free Applications',
|
||||||
|
'Graph Model': 'Graph Model',
|
||||||
'Group %(group_id)s created': 'Group %(group_id)s created',
|
'Group %(group_id)s created': 'Group %(group_id)s created',
|
||||||
'Group ID': 'ID Gruppo',
|
'Group ID': 'ID Gruppo',
|
||||||
'Group uniquely assigned to user %(id)s': 'Group uniquely assigned to user %(id)s',
|
'Group uniquely assigned to user %(id)s': 'Group uniquely assigned to user %(id)s',
|
||||||
@@ -100,69 +102,70 @@
|
|||||||
'Hello World': 'Salve Mondo',
|
'Hello World': 'Salve Mondo',
|
||||||
'Hello World in a flash!': 'Salve Mondo in un flash!',
|
'Hello World in a flash!': 'Salve Mondo in un flash!',
|
||||||
'Home': 'Home',
|
'Home': 'Home',
|
||||||
'How did you get here?': 'How did you get here?',
|
'How did you get here?': 'Come sei arrivato qui?',
|
||||||
'HTML': 'HTML',
|
'HTML': 'HTML',
|
||||||
'import': 'import',
|
'import': 'importa',
|
||||||
'Import/Export': 'Importa/Esporta',
|
'Import/Export': 'Importa/Esporta',
|
||||||
'Index': 'Indice',
|
'Index': 'Indice',
|
||||||
'insert new': 'inserisci nuovo',
|
'insert new': 'inserisci nuovo',
|
||||||
'insert new %s': 'inserisci nuovo %s',
|
'insert new %s': 'inserisci nuovo %s',
|
||||||
'Internal State': 'Stato interno',
|
'Internal State': 'Stato interno',
|
||||||
'Introduction': 'Introduction',
|
'Introduction': 'Introduzione',
|
||||||
'Invalid email': 'Email non valida',
|
'Invalid email': 'Email non valida',
|
||||||
'Invalid login': 'Invalid login',
|
'Invalid login': 'Login non valido',
|
||||||
'Invalid Query': 'Richiesta (query) non valida',
|
'Invalid Query': 'Richiesta (query) non valida',
|
||||||
'invalid request': 'richiesta non valida',
|
'invalid request': 'richiesta non valida',
|
||||||
'Is Active': 'Is Active',
|
'Is Active': "E' attivo",
|
||||||
'Key': 'Key',
|
'Key': 'Chiave',
|
||||||
'Last name': 'Cognome',
|
'Last name': 'Cognome',
|
||||||
'Layout': 'Layout',
|
'Layout': 'Layout',
|
||||||
'Layout Plugins': 'Layout Plugins',
|
'Layout Plugins': 'Layout Plugins',
|
||||||
'Layouts': 'Layouts',
|
'Layouts': 'Layouts',
|
||||||
'Live Chat': 'Live Chat',
|
'Live Chat': 'Live Chat',
|
||||||
'Logged in': 'Logged in',
|
'Logged in': 'Loggato',
|
||||||
'Logged out': 'Logged out',
|
'Logged out': 'Disconnesso',
|
||||||
'login': 'accesso',
|
'login': 'accesso',
|
||||||
'Login': 'Login',
|
'Login': 'Login',
|
||||||
'logout': 'uscita',
|
'logout': 'uscita',
|
||||||
'Logout': 'Logout',
|
'Logout': 'Logout',
|
||||||
'Lost Password': 'Lost Password',
|
'Lost Password': 'Password Smarrita',
|
||||||
'Lost password?': 'Lost password?',
|
'Lost password?': 'Password smarrita?',
|
||||||
'lost password?': 'dimenticato la password?',
|
'lost password?': 'dimenticato la password?',
|
||||||
'Main Menu': 'Menu principale',
|
'Main Menu': 'Menu principale',
|
||||||
'Manage Cache': 'Manage Cache',
|
'Manage Cache': 'Manage Cache',
|
||||||
'Menu Model': 'Menu Modelli',
|
'Menu Model': 'Menu Modelli',
|
||||||
'Modified By': 'Modified By',
|
'Modified By': 'Modificato da',
|
||||||
'Modified On': 'Modified On',
|
'Modified On': 'Modificato il',
|
||||||
'My Sites': 'My Sites',
|
'My Sites': 'My Sites',
|
||||||
'Name': 'Nome',
|
'Name': 'Nome',
|
||||||
'New': 'New',
|
'New': 'Nuovo',
|
||||||
'New password': 'New password',
|
'New password': 'Nuova password',
|
||||||
'New Record': 'Nuovo elemento (record)',
|
'New Record': 'Nuovo elemento (record)',
|
||||||
'new record inserted': 'nuovo record inserito',
|
'new record inserted': 'nuovo record inserito',
|
||||||
'next 100 rows': 'prossime 100 righe',
|
'next 100 rows': 'prossime 100 righe',
|
||||||
'No databases in this application': 'Nessun database presente in questa applicazione',
|
'No databases in this application': 'Nessun database presente in questa applicazione',
|
||||||
'No records found': 'No records found',
|
'No records found': 'Nessun record trovato',
|
||||||
'Nome': 'Nome',
|
'Nome': 'Nome',
|
||||||
'Non può essere vuoto': 'Non può essere vuoto',
|
'Non può essere vuoto': 'Non può essere vuoto',
|
||||||
'not authorized': 'non autorizzato',
|
'not authorized': 'non autorizzato',
|
||||||
'Object or table name': 'Object or table name',
|
'Object or table name': 'Oggeto o nome tabella',
|
||||||
'Old password': 'Old password',
|
'Old password': 'Vecchia password',
|
||||||
'Online examples': 'Vedere gli esempi',
|
'Online examples': 'Vedere gli esempi',
|
||||||
'Or': 'Or',
|
'Or': 'O',
|
||||||
'or import from csv file': 'oppure importa da file CSV',
|
'or import from csv file': 'oppure importa da file CSV',
|
||||||
'Origin': 'Origine',
|
'Origin': 'Origine',
|
||||||
'Other Plugins': 'Other Plugins',
|
'Other Plugins': 'Other Plugins',
|
||||||
'Other Recipes': 'Other Recipes',
|
'Other Recipes': 'Other Recipes',
|
||||||
'Overview': 'Overview',
|
'Overview': 'Overview',
|
||||||
'Password': 'Password',
|
'Password': 'Password',
|
||||||
"Password fields don't match": "Password fields don't match",
|
"Password fields don't match": 'I campi password non sono uguali',
|
||||||
'please input your password again': 'please input your password again',
|
'please input your password again': 'perfavore reimmeti la tua password',
|
||||||
'Plugins': 'Plugins',
|
'Plugins': 'Plugins',
|
||||||
'Powered by': 'Powered by',
|
'Powered by': 'Powered by',
|
||||||
'Preface': 'Preface',
|
'Preface': 'Preface',
|
||||||
'previous 100 rows': '100 righe precedenti',
|
'previous 100 rows': '100 righe precedenti',
|
||||||
'Profile': 'Profile',
|
'Profile': 'Profilo',
|
||||||
|
'pygraphviz library not found': 'pygraphviz library not found',
|
||||||
'Python': 'Python',
|
'Python': 'Python',
|
||||||
'Query:': 'Richiesta (query):',
|
'Query:': 'Richiesta (query):',
|
||||||
'Quick Examples': 'Quick Examples',
|
'Quick Examples': 'Quick Examples',
|
||||||
@@ -174,28 +177,30 @@
|
|||||||
'record does not exist': 'il record non esiste',
|
'record does not exist': 'il record non esiste',
|
||||||
'Record ID': 'Record ID',
|
'Record ID': 'Record ID',
|
||||||
'Record id': 'Record id',
|
'Record id': 'Record id',
|
||||||
'Register': 'Register',
|
'Register': 'Registrati',
|
||||||
'register': 'registrazione',
|
'register': 'registrazione',
|
||||||
'Registration identifier': 'Registration identifier',
|
'Registration identifier': 'Registration identifier',
|
||||||
'Registration key': 'Chiave di Registazione',
|
'Registration key': 'Chiave di Registazione',
|
||||||
'Registration successful': 'Registration successful',
|
'Registration successful': 'Registrazione avvenuta',
|
||||||
'Remember me (for 30 days)': 'Remember me (for 30 days)',
|
'reload': 'reload',
|
||||||
'Request reset password': 'Request reset password',
|
'Remember me (for 30 days)': 'Ricordami (per 30 giorni)',
|
||||||
|
'Request reset password': 'Richiedi il reset della password',
|
||||||
'Reset Password key': 'Resetta chiave Password ',
|
'Reset Password key': 'Resetta chiave Password ',
|
||||||
'Role': 'Ruolo',
|
'Role': 'Ruolo',
|
||||||
'Rows in Table': 'Righe nella tabella',
|
'Rows in Table': 'Righe nella tabella',
|
||||||
'Rows selected': 'Righe selezionate',
|
'Rows selected': 'Righe selezionate',
|
||||||
'Save profile': 'Save profile',
|
'Save model as...': 'Salva modello come...',
|
||||||
'Search': 'Search',
|
'Save profile': 'Salva profilo',
|
||||||
|
'Search': 'Ricerca',
|
||||||
'Semantic': 'Semantic',
|
'Semantic': 'Semantic',
|
||||||
'Services': 'Services',
|
'Services': 'Servizi',
|
||||||
'Size of cache:': 'Size of cache:',
|
'Size of cache:': 'Size of cache:',
|
||||||
'starts with': 'starts with',
|
'starts with': 'comincia con',
|
||||||
'state': 'stato',
|
'state': 'stato',
|
||||||
'Statistics': 'Statistics',
|
'Statistics': 'Statistics',
|
||||||
'Stylesheet': 'Foglio di stile (stylesheet)',
|
'Stylesheet': 'Foglio di stile (stylesheet)',
|
||||||
'submit': 'submit',
|
'submit': 'Inviai',
|
||||||
'Submit': 'Submit',
|
'Submit': 'Invia',
|
||||||
'Support': 'Support',
|
'Support': 'Support',
|
||||||
'Sure you want to delete this object?': 'Vuoi veramente cancellare questo oggetto?',
|
'Sure you want to delete this object?': 'Vuoi veramente cancellare questo oggetto?',
|
||||||
'Table': 'tabella',
|
'Table': 'tabella',
|
||||||
@@ -208,12 +213,13 @@
|
|||||||
'This is a copy of the scaffolding application': "Questa è una copia dell'applicazione di base (scaffold)",
|
'This is a copy of the scaffolding application': "Questa è una copia dell'applicazione di base (scaffold)",
|
||||||
'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)',
|
'Time in Cache (h:m:s)': 'Time in Cache (h:m:s)',
|
||||||
'Timestamp': 'Ora (timestamp)',
|
'Timestamp': 'Ora (timestamp)',
|
||||||
'too short': 'too short',
|
'too short': 'troppo corto',
|
||||||
'TSV (Excel compatible)': 'TSV (Excel compatible)',
|
'Traceback': 'Traceback',
|
||||||
'TSV (Excel compatible, hidden cols)': 'TSV (Excel compatible, hidden cols)',
|
'TSV (Excel compatible)': 'TSV (Excel compatibile)',
|
||||||
|
'TSV (Excel compatible, hidden cols)': 'TSV (Excel compatibile, hidden cols)',
|
||||||
'Twitter': 'Twitter',
|
'Twitter': 'Twitter',
|
||||||
'unable to parse csv file': 'non riesco a decodificare questo file CSV',
|
'unable to parse csv file': 'non riesco a decodificare questo file CSV',
|
||||||
'Update': 'Update',
|
'Update': 'Aggiorna',
|
||||||
'Update:': 'Aggiorna:',
|
'Update:': 'Aggiorna:',
|
||||||
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Per costruire richieste (query) più complesse si usano (...)&(...) come "e" (AND), (...)|(...) come "o" (OR), e ~(...) come negazione (NOT).',
|
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Per costruire richieste (query) più complesse si usano (...)&(...) come "e" (AND), (...)|(...) come "o" (OR), e ~(...) come negazione (NOT).',
|
||||||
'User %(id)s Logged-in': 'User %(id)s Logged-in',
|
'User %(id)s Logged-in': 'User %(id)s Logged-in',
|
||||||
@@ -223,14 +229,14 @@
|
|||||||
'User %(id)s Profile updated': 'User %(id)s Profile updated',
|
'User %(id)s Profile updated': 'User %(id)s Profile updated',
|
||||||
'User %(id)s Registered': 'User %(id)s Registered',
|
'User %(id)s Registered': 'User %(id)s Registered',
|
||||||
'User ID': 'ID Utente',
|
'User ID': 'ID Utente',
|
||||||
'value already in database or empty': 'value already in database or empty',
|
'value already in database or empty': 'valore già presente nel database o vuoto',
|
||||||
'Verify Password': 'Verify Password',
|
'Verify Password': 'Verifica Password',
|
||||||
'Videos': 'Videos',
|
'Videos': 'Videos',
|
||||||
'View': 'Vista',
|
'View': 'Vista',
|
||||||
'Welcome': 'Welcome',
|
'Welcome': 'Welcome',
|
||||||
'Welcome %s': 'Benvenuto %s',
|
'Welcome %s': 'Benvenuto %s',
|
||||||
'Welcome to web2py': 'Benvenuto su web2py',
|
'Welcome to web2py': 'Benvenuto su web2py',
|
||||||
'Welcome to web2py!': 'Welcome to web2py!',
|
'Welcome to web2py!': 'Benvenuto in web2py!',
|
||||||
'Which called the function %s located in the file %s': 'che ha chiamato la funzione %s presente nel file %s',
|
'Which called the function %s located in the file %s': 'che ha chiamato la funzione %s presente nel file %s',
|
||||||
'XML': 'XML',
|
'XML': 'XML',
|
||||||
'You are successfully running web2py': 'Stai eseguendo web2py con successo',
|
'You are successfully running web2py': 'Stai eseguendo web2py con successo',
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ td.w2p_fl,td.w2p_fc {padding:0;}
|
|||||||
==============================================================*/
|
==============================================================*/
|
||||||
|
|
||||||
/* because web2py handles this via js */
|
/* because web2py handles this via js */
|
||||||
|
textarea { width:90%}
|
||||||
.hidden{visibility:visible;}
|
.hidden{visibility:visible;}
|
||||||
/* right folder for bootstrap black images/icons */
|
/* right folder for bootstrap black images/icons */
|
||||||
[class^="icon-"],[class*=" icon-"]{
|
[class^="icon-"],[class*=" icon-"]{
|
||||||
|
|||||||
+63
-30
@@ -52,7 +52,7 @@ def set_global(var, val):
|
|||||||
|
|
||||||
class FPDF(object):
|
class FPDF(object):
|
||||||
"PDF Generation class"
|
"PDF Generation class"
|
||||||
|
|
||||||
def __init__(self, orientation='P',unit='mm',format='A4'):
|
def __init__(self, orientation='P',unit='mm',format='A4'):
|
||||||
# Some checks
|
# Some checks
|
||||||
self._dochecks()
|
self._dochecks()
|
||||||
@@ -356,7 +356,7 @@ class FPDF(object):
|
|||||||
elif (self.current_font['desc']['MissingWidth']) :
|
elif (self.current_font['desc']['MissingWidth']) :
|
||||||
w += self.current_font['desc']['MissingWidth']
|
w += self.current_font['desc']['MissingWidth']
|
||||||
#elif (isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; }
|
#elif (isset($this->CurrentFont['MissingWidth'])) { $w += $this->CurrentFont['MissingWidth']; }
|
||||||
else:
|
else:
|
||||||
w += 500
|
w += 500
|
||||||
else:
|
else:
|
||||||
for i in xrange(0, l):
|
for i in xrange(0, l):
|
||||||
@@ -373,6 +373,21 @@ class FPDF(object):
|
|||||||
"Draw a line"
|
"Draw a line"
|
||||||
self._out(sprintf('%.2f %.2f m %.2f %.2f l S',x1*self.k,(self.h-y1)*self.k,x2*self.k,(self.h-y2)*self.k))
|
self._out(sprintf('%.2f %.2f m %.2f %.2f l S',x1*self.k,(self.h-y1)*self.k,x2*self.k,(self.h-y2)*self.k))
|
||||||
|
|
||||||
|
def _set_dash(self, dash_length=False, space_length=False):
|
||||||
|
if(dash_length and space_length):
|
||||||
|
s = sprintf('[%.3f %.3f] 0 d', dash_length*self.k, space_length*self.k)
|
||||||
|
else:
|
||||||
|
s = '[] 0 d'
|
||||||
|
self._out(s)
|
||||||
|
|
||||||
|
def dashed_line(self, x1,y1,x2,y2, dash_length=1, space_length=1):
|
||||||
|
"""Draw a dashed line. Same interface as line() except:
|
||||||
|
- dash_length: Length of the dash
|
||||||
|
- space_length: Length of the space between dashes"""
|
||||||
|
self._set_dash(dash_length, space_length)
|
||||||
|
self.line(x1, y1, x2, y2)
|
||||||
|
self._set_dash()
|
||||||
|
|
||||||
def rect(self, x,y,w,h,style=''):
|
def rect(self, x,y,w,h,style=''):
|
||||||
"Draw a rectangle"
|
"Draw a rectangle"
|
||||||
if(style=='F'):
|
if(style=='F'):
|
||||||
@@ -401,10 +416,10 @@ class FPDF(object):
|
|||||||
global SYSTEM_TTFONTS
|
global SYSTEM_TTFONTS
|
||||||
if os.path.exists(fname):
|
if os.path.exists(fname):
|
||||||
ttffilename = fname
|
ttffilename = fname
|
||||||
elif (FPDF_FONT_DIR and
|
elif (FPDF_FONT_DIR and
|
||||||
os.path.exists(os.path.join(FPDF_FONT_DIR, fname))):
|
os.path.exists(os.path.join(FPDF_FONT_DIR, fname))):
|
||||||
ttffilename = os.path.join(FPDF_FONT_DIR, fname)
|
ttffilename = os.path.join(FPDF_FONT_DIR, fname)
|
||||||
elif (SYSTEM_TTFONTS and
|
elif (SYSTEM_TTFONTS and
|
||||||
os.path.exists(os.path.join(SYSTEM_TTFONTS, fname))):
|
os.path.exists(os.path.join(SYSTEM_TTFONTS, fname))):
|
||||||
ttffilename = os.path.join(SYSTEM_TTFONTS, fname)
|
ttffilename = os.path.join(SYSTEM_TTFONTS, fname)
|
||||||
else:
|
else:
|
||||||
@@ -450,7 +465,7 @@ class FPDF(object):
|
|||||||
fh = open(unifilename, "w")
|
fh = open(unifilename, "w")
|
||||||
pickle.dump(font_dict, fh)
|
pickle.dump(font_dict, fh)
|
||||||
fh.close()
|
fh.close()
|
||||||
except IOError as e:
|
except IOError, e:
|
||||||
if not e.errno == errno.EACCES:
|
if not e.errno == errno.EACCES:
|
||||||
raise # Not a permission error.
|
raise # Not a permission error.
|
||||||
del ttf
|
del ttf
|
||||||
@@ -459,11 +474,11 @@ class FPDF(object):
|
|||||||
else:
|
else:
|
||||||
sbarr = range(0,32)
|
sbarr = range(0,32)
|
||||||
self.fonts[fontkey] = {
|
self.fonts[fontkey] = {
|
||||||
'i': len(self.fonts)+1, 'type': font_dict['type'],
|
'i': len(self.fonts)+1, 'type': font_dict['type'],
|
||||||
'name': font_dict['name'], 'desc': font_dict['desc'],
|
'name': font_dict['name'], 'desc': font_dict['desc'],
|
||||||
'up': font_dict['up'], 'ut': font_dict['ut'],
|
'up': font_dict['up'], 'ut': font_dict['ut'],
|
||||||
'cw': font_dict['cw'],
|
'cw': font_dict['cw'],
|
||||||
'ttffile': font_dict['ttffile'], 'fontkey': fontkey,
|
'ttffile': font_dict['ttffile'], 'fontkey': fontkey,
|
||||||
'subset': sbarr, 'unifilename': unifilename,
|
'subset': sbarr, 'unifilename': unifilename,
|
||||||
}
|
}
|
||||||
self.font_files[fontkey] = {'length1': font_dict['originalsize'],
|
self.font_files[fontkey] = {'length1': font_dict['originalsize'],
|
||||||
@@ -494,7 +509,7 @@ class FPDF(object):
|
|||||||
if (type == 'TrueType'):
|
if (type == 'TrueType'):
|
||||||
self.font_files[filename]={'length1': originalsize}
|
self.font_files[filename]={'length1': originalsize}
|
||||||
else:
|
else:
|
||||||
self.font_files[filename]={'length1': size1,
|
self.font_files[filename]={'length1': size1,
|
||||||
'length2': size2}
|
'length2': size2}
|
||||||
|
|
||||||
def set_font(self, family,style='',size=0):
|
def set_font(self, family,style='',size=0):
|
||||||
@@ -660,7 +675,7 @@ class FPDF(object):
|
|||||||
dx=self.c_margin
|
dx=self.c_margin
|
||||||
if(self.color_flag):
|
if(self.color_flag):
|
||||||
s+='q '+self.text_color+' '
|
s+='q '+self.text_color+' '
|
||||||
|
|
||||||
# If multibyte, Tw has no effect - do word spacing using an adjustment before each space
|
# If multibyte, Tw has no effect - do word spacing using an adjustment before each space
|
||||||
if (self.ws and self.unifontsubset):
|
if (self.ws and self.unifontsubset):
|
||||||
for uni in UTF8StringToArray(txt):
|
for uni in UTF8StringToArray(txt):
|
||||||
@@ -686,7 +701,7 @@ class FPDF(object):
|
|||||||
else:
|
else:
|
||||||
txt2 = self._escape(txt)
|
txt2 = self._escape(txt)
|
||||||
s += sprintf('BT %.2f %.2f Td (%s) Tj ET',(self.x+dx)*k,(self.h-(self.y+.5*h+.3*self.font_size))*k,txt2)
|
s += sprintf('BT %.2f %.2f Td (%s) Tj ET',(self.x+dx)*k,(self.h-(self.y+.5*h+.3*self.font_size))*k,txt2)
|
||||||
|
|
||||||
if(self.underline):
|
if(self.underline):
|
||||||
s+=' '+self._dounderline(self.x+dx,self.y+.5*h+.3*self.font_size,txt)
|
s+=' '+self._dounderline(self.x+dx,self.y+.5*h+.3*self.font_size,txt)
|
||||||
if(self.color_flag):
|
if(self.color_flag):
|
||||||
@@ -764,7 +779,7 @@ class FPDF(object):
|
|||||||
sep=i
|
sep=i
|
||||||
ls=l
|
ls=l
|
||||||
ns+=1
|
ns+=1
|
||||||
if self.unifontsubset:
|
if self.unifontsubset:
|
||||||
l += self.get_string_width(c) / self.font_size*1000.0
|
l += self.get_string_width(c) / self.font_size*1000.0
|
||||||
else:
|
else:
|
||||||
l += cw.get(c,0)
|
l += cw.get(c,0)
|
||||||
@@ -848,7 +863,7 @@ class FPDF(object):
|
|||||||
continue
|
continue
|
||||||
if(c==' '):
|
if(c==' '):
|
||||||
sep=i
|
sep=i
|
||||||
if self.unifontsubset:
|
if self.unifontsubset:
|
||||||
l += self.get_string_width(c) / self.font_size*1000.0
|
l += self.get_string_width(c) / self.font_size*1000.0
|
||||||
else:
|
else:
|
||||||
l += cw.get(c,0)
|
l += cw.get(c,0)
|
||||||
@@ -900,6 +915,24 @@ class FPDF(object):
|
|||||||
info=self._parsepng(name)
|
info=self._parsepng(name)
|
||||||
else:
|
else:
|
||||||
#Allow for additional formats
|
#Allow for additional formats
|
||||||
|
#maybe the image is not showing the correct extension,
|
||||||
|
#but the header is OK,
|
||||||
|
succeed_parsing = False
|
||||||
|
#try all the parsing functions
|
||||||
|
parsing_functions = [self._parsejpg,self._parsepng,self._parsegif]
|
||||||
|
for pf in parsing_functions:
|
||||||
|
try:
|
||||||
|
info = pf(name)
|
||||||
|
succeed_parsing = True
|
||||||
|
break;
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
#last resource
|
||||||
|
if not succeed_parsing:
|
||||||
|
mtd='_parse'+type
|
||||||
|
if not hasattr(self,mtd):
|
||||||
|
self.error('Unsupported image type: '+type)
|
||||||
|
info=getattr(self, mtd)(name)
|
||||||
mtd='_parse'+type
|
mtd='_parse'+type
|
||||||
if not hasattr(self,mtd):
|
if not hasattr(self,mtd):
|
||||||
self.error('Unsupported image type: '+type)
|
self.error('Unsupported image type: '+type)
|
||||||
@@ -1202,7 +1235,7 @@ class FPDF(object):
|
|||||||
self._out('<</Type /Font');
|
self._out('<</Type /Font');
|
||||||
self._out('/Subtype /Type0');
|
self._out('/Subtype /Type0');
|
||||||
self._out('/BaseFont /' + fontname + '');
|
self._out('/BaseFont /' + fontname + '');
|
||||||
self._out('/Encoding /Identity-H');
|
self._out('/Encoding /Identity-H');
|
||||||
self._out('/DescendantFonts [' + str(self.n + 1) + ' 0 R]')
|
self._out('/DescendantFonts [' + str(self.n + 1) + ' 0 R]')
|
||||||
self._out('/ToUnicode ' + str(self.n + 2) + ' 0 R')
|
self._out('/ToUnicode ' + str(self.n + 2) + ' 0 R')
|
||||||
self._out('>>')
|
self._out('>>')
|
||||||
@@ -1264,7 +1297,7 @@ class FPDF(object):
|
|||||||
for kd in ('Ascent', 'Descent', 'CapHeight', 'Flags', 'FontBBox', 'ItalicAngle', 'StemV', 'MissingWidth'):
|
for kd in ('Ascent', 'Descent', 'CapHeight', 'Flags', 'FontBBox', 'ItalicAngle', 'StemV', 'MissingWidth'):
|
||||||
v = font['desc'][kd]
|
v = font['desc'][kd]
|
||||||
if (kd == 'Flags'):
|
if (kd == 'Flags'):
|
||||||
v = v | 4;
|
v = v | 4;
|
||||||
v = v & ~32; # SYMBOLIC font flag
|
v = v & ~32; # SYMBOLIC font flag
|
||||||
self._out(' /%s %s' % (kd, v))
|
self._out(' /%s %s' % (kd, v))
|
||||||
self._out('/FontFile2 ' + str(self.n + 2) + ' 0 R')
|
self._out('/FontFile2 ' + str(self.n + 2) + ' 0 R')
|
||||||
@@ -1286,7 +1319,7 @@ class FPDF(object):
|
|||||||
self._putstream(cidtogidmap)
|
self._putstream(cidtogidmap)
|
||||||
self._out('endobj')
|
self._out('endobj')
|
||||||
|
|
||||||
#Font file
|
#Font file
|
||||||
self._newobj()
|
self._newobj()
|
||||||
self._out('<</Length ' + str(len(fontstream)))
|
self._out('<</Length ' + str(len(fontstream)))
|
||||||
self._out('/Filter /FlateDecode')
|
self._out('/Filter /FlateDecode')
|
||||||
@@ -1341,14 +1374,14 @@ class FPDF(object):
|
|||||||
font_dict['range'] = range_
|
font_dict['range'] = range_
|
||||||
pickle.dump(font_dict, fh)
|
pickle.dump(font_dict, fh)
|
||||||
fh.close()
|
fh.close()
|
||||||
except IOError as e:
|
except IOError, e:
|
||||||
if not e.errno == errno.EACCES:
|
if not e.errno == errno.EACCES:
|
||||||
raise # Not a permission error.
|
raise # Not a permission error.
|
||||||
if (font['cw'][cid] == 0):
|
if (font['cw'][cid] == 0):
|
||||||
continue
|
continue
|
||||||
width = font['cw'][cid]
|
width = font['cw'][cid]
|
||||||
if (width == 65535): width = 0
|
if (width == 65535): width = 0
|
||||||
if (cid > 255 and (cid not in font['subset']) or not cid): #
|
if (cid > 255 and (cid not in font['subset']) or not cid): #
|
||||||
continue
|
continue
|
||||||
if ('dw' not in font or (font['dw'] and width != font['dw'])):
|
if ('dw' not in font or (font['dw'] and width != font['dw'])):
|
||||||
if (cid == (prevcid + 1)):
|
if (cid == (prevcid + 1)):
|
||||||
@@ -1400,7 +1433,7 @@ class FPDF(object):
|
|||||||
if (len(set(ws)) == 1):
|
if (len(set(ws)) == 1):
|
||||||
w.append(' %s %s %s' % (k, k + len(ws) - 1, ws[0]))
|
w.append(' %s %s %s' % (k, k + len(ws) - 1, ws[0]))
|
||||||
else:
|
else:
|
||||||
w.append(' %s [ %s ]\n' % (k, ' '.join([str(int(h)) for h in ws]))) ##
|
w.append(' %s [ %s ]\n' % (k, ' '.join([str(int(h)) for h in ws]))) ##
|
||||||
self._out('/W [%s]' % ''.join(w))
|
self._out('/W [%s]' % ''.join(w))
|
||||||
|
|
||||||
def _putimages(self):
|
def _putimages(self):
|
||||||
@@ -1412,7 +1445,7 @@ class FPDF(object):
|
|||||||
del info['data']
|
del info['data']
|
||||||
if 'smask' in info:
|
if 'smask' in info:
|
||||||
del info['smask']
|
del info['smask']
|
||||||
|
|
||||||
def _putimage(self, info):
|
def _putimage(self, info):
|
||||||
if 'data' in info:
|
if 'data' in info:
|
||||||
self._newobj()
|
self._newobj()
|
||||||
@@ -1791,20 +1824,20 @@ class FPDF(object):
|
|||||||
|
|
||||||
def interleaved2of5(self, txt, x, y, w=1.0, h=10.0):
|
def interleaved2of5(self, txt, x, y, w=1.0, h=10.0):
|
||||||
"Barcode I2of5 (numeric), adds a 0 if odd lenght"
|
"Barcode I2of5 (numeric), adds a 0 if odd lenght"
|
||||||
narrow = w / 3.0
|
narrow = w / 3.0
|
||||||
wide = w
|
wide = w
|
||||||
|
|
||||||
# wide/narrow codes for the digits
|
# wide/narrow codes for the digits
|
||||||
bar_char={'0': 'nnwwn', '1': 'wnnnw', '2': 'nwnnw', '3': 'wwnnn',
|
bar_char={'0': 'nnwwn', '1': 'wnnnw', '2': 'nwnnw', '3': 'wwnnn',
|
||||||
'4': 'nnwnw', '5': 'wnwnn', '6': 'nwwnn', '7': 'nnnww',
|
'4': 'nnwnw', '5': 'wnwnn', '6': 'nwwnn', '7': 'nnnww',
|
||||||
'8': 'wnnwn', '9': 'nwnwn', 'A': 'nn', 'Z': 'wn'}
|
'8': 'wnnwn', '9': 'nwnwn', 'A': 'nn', 'Z': 'wn'}
|
||||||
|
|
||||||
self.set_fill_color(0)
|
self.set_fill_color(0)
|
||||||
code = txt
|
code = txt
|
||||||
# add leading zero if code-length is odd
|
# add leading zero if code-length is odd
|
||||||
if len(code) % 2 != 0:
|
if len(code) % 2 != 0:
|
||||||
code = '0' + code
|
code = '0' + code
|
||||||
|
|
||||||
# add start and stop codes
|
# add start and stop codes
|
||||||
code = 'AA' + code.lower() + 'ZA'
|
code = 'AA' + code.lower() + 'ZA'
|
||||||
|
|
||||||
@@ -1843,7 +1876,7 @@ class FPDF(object):
|
|||||||
narrow = w / 3.0
|
narrow = w / 3.0
|
||||||
gap = narrow
|
gap = narrow
|
||||||
|
|
||||||
bar_char={'0': 'nnnwwnwnn', '1': 'wnnwnnnnw', '2': 'nnwwnnnnw',
|
bar_char={'0': 'nnnwwnwnn', '1': 'wnnwnnnnw', '2': 'nnwwnnnnw',
|
||||||
'3': 'wnwwnnnnn', '4': 'nnnwwnnnw', '5': 'wnnwwnnnn',
|
'3': 'wnwwnnnnn', '4': 'nnnwwnnnw', '5': 'wnnwwnnnn',
|
||||||
'6': 'nnwwwnnnn', '7': 'nnnwnnwnw', '8': 'wnnwnnwnn',
|
'6': 'nnwwwnnnn', '7': 'nnnwnnwnw', '8': 'wnnwnnwnn',
|
||||||
'9': 'nnwwnnwnn', 'A': 'wnnnnwnnw', 'B': 'nnwnnwnnw',
|
'9': 'nnwwnnwnn', 'A': 'wnnnnwnnw', 'B': 'nnwnnwnnw',
|
||||||
@@ -1860,8 +1893,8 @@ class FPDF(object):
|
|||||||
'+': 'nwnnnwnwn', '%': 'nnnwnwnwn'}
|
'+': 'nwnnnwnwn', '%': 'nnnwnwnwn'}
|
||||||
|
|
||||||
self.set_fill_color(0)
|
self.set_fill_color(0)
|
||||||
code = txt
|
code = txt
|
||||||
|
|
||||||
code = code.upper()
|
code = code.upper()
|
||||||
for i in xrange (0, len(code), 2):
|
for i in xrange (0, len(code), 2):
|
||||||
char_bar = code[i]
|
char_bar = code[i]
|
||||||
@@ -1871,7 +1904,7 @@ class FPDF(object):
|
|||||||
|
|
||||||
seq= ''
|
seq= ''
|
||||||
for s in xrange(0, len(bar_char[char_bar])):
|
for s in xrange(0, len(bar_char[char_bar])):
|
||||||
seq += bar_char[char_bar][s]
|
seq += bar_char[char_bar][s]
|
||||||
|
|
||||||
for bar in xrange(0, len(seq)):
|
for bar in xrange(0, len(seq)):
|
||||||
if seq[bar] == 'n':
|
if seq[bar] == 'n':
|
||||||
|
|||||||
+41
-14
@@ -370,7 +370,7 @@ if not 'google' in DRIVERS:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
import fdb
|
import fdb
|
||||||
DRIVERS.append('Firbird(fdb)')
|
DRIVERS.append('Firebird(fdb)')
|
||||||
except ImportError:
|
except ImportError:
|
||||||
LOGGER.debug('no Firebird driver fdb')
|
LOGGER.debug('no Firebird driver fdb')
|
||||||
#####
|
#####
|
||||||
@@ -633,6 +633,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
|
|
||||||
TRUE = 'T'
|
TRUE = 'T'
|
||||||
FALSE = 'F'
|
FALSE = 'F'
|
||||||
|
T_SEP = ' '
|
||||||
types = {
|
types = {
|
||||||
'boolean': 'CHAR(1)',
|
'boolean': 'CHAR(1)',
|
||||||
'string': 'CHAR(%(length)s)',
|
'string': 'CHAR(%(length)s)',
|
||||||
@@ -1810,7 +1811,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
obj = str(obj)
|
obj = str(obj)
|
||||||
elif fieldtype == 'datetime':
|
elif fieldtype == 'datetime':
|
||||||
if isinstance(obj, datetime.datetime):
|
if isinstance(obj, datetime.datetime):
|
||||||
obj = obj.isoformat()[:19].replace('T',' ')
|
obj = obj.isoformat(self.T_SEP)[:19]
|
||||||
elif isinstance(obj, datetime.date):
|
elif isinstance(obj, datetime.date):
|
||||||
obj = obj.isoformat()[:10]+' 00:00:00'
|
obj = obj.isoformat()[:10]+' 00:00:00'
|
||||||
else:
|
else:
|
||||||
@@ -2418,6 +2419,9 @@ class MySQLAdapter(BaseAdapter):
|
|||||||
return ['SET FOREIGN_KEY_CHECKS=0;','DROP TABLE %s;' % table,
|
return ['SET FOREIGN_KEY_CHECKS=0;','DROP TABLE %s;' % table,
|
||||||
'SET FOREIGN_KEY_CHECKS=1;']
|
'SET FOREIGN_KEY_CHECKS=1;']
|
||||||
|
|
||||||
|
def _insert_empty(self, table):
|
||||||
|
return 'INSERT INTO %s VALUES (DEFAULT);' % table
|
||||||
|
|
||||||
def distributed_transaction_begin(self,key):
|
def distributed_transaction_begin(self,key):
|
||||||
self.execute('XA START;')
|
self.execute('XA START;')
|
||||||
|
|
||||||
@@ -3033,6 +3037,7 @@ class OracleAdapter(BaseAdapter):
|
|||||||
|
|
||||||
class MSSQLAdapter(BaseAdapter):
|
class MSSQLAdapter(BaseAdapter):
|
||||||
drivers = ('pyodbc',)
|
drivers = ('pyodbc',)
|
||||||
|
T_SEP = 'T'
|
||||||
|
|
||||||
types = {
|
types = {
|
||||||
'boolean': 'BIT',
|
'boolean': 'BIT',
|
||||||
@@ -3935,7 +3940,7 @@ class IngresAdapter(BaseAdapter):
|
|||||||
return self.driver.connect(cnxn,**driver_args)
|
return self.driver.connect(cnxn,**driver_args)
|
||||||
|
|
||||||
self.connector = connector
|
self.connector = connector
|
||||||
|
|
||||||
# TODO if version is >= 10, set types['id'] to Identity column, see http://community.actian.com/wiki/Using_Ingres_Identity_Columns
|
# TODO if version is >= 10, set types['id'] to Identity column, see http://community.actian.com/wiki/Using_Ingres_Identity_Columns
|
||||||
if do_connect: self.reconnect()
|
if do_connect: self.reconnect()
|
||||||
|
|
||||||
@@ -4654,7 +4659,7 @@ class GoogleDatastoreAdapter(NoSQLAdapter):
|
|||||||
return self.expand(first)
|
return self.expand(first)
|
||||||
|
|
||||||
def truncate(self,table,mode):
|
def truncate(self,table,mode):
|
||||||
self.db(table._id).delete()
|
self.db(self.db._adapter.id_query(table)).delete()
|
||||||
|
|
||||||
def select_raw(self,query,fields=None,attributes=None):
|
def select_raw(self,query,fields=None,attributes=None):
|
||||||
db = self.db
|
db = self.db
|
||||||
@@ -7052,15 +7057,13 @@ class DAL(object):
|
|||||||
Example::
|
Example::
|
||||||
|
|
||||||
db = DAL('sqlite://test.db')
|
db = DAL('sqlite://test.db')
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
db = DAL({"uri": ..., "items": ...}) # experimental
|
||||||
|
|
||||||
db.define_table('tablename', Field('fieldname1'),
|
db.define_table('tablename', Field('fieldname1'),
|
||||||
Field('fieldname2'))
|
Field('fieldname2'))
|
||||||
|
|
||||||
(experimental)
|
|
||||||
you can pass a dict object as uri with the uri string
|
|
||||||
and table/field definitions. For an example of valid data check
|
|
||||||
the output of:
|
|
||||||
|
|
||||||
>>> db.as_dict(flat=True, sanitize=False)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __new__(cls, uri='sqlite://dummy.db', *args, **kwargs):
|
def __new__(cls, uri='sqlite://dummy.db', *args, **kwargs):
|
||||||
@@ -7181,6 +7184,28 @@ class DAL(object):
|
|||||||
|
|
||||||
:uri: string that contains information for connecting to a database.
|
:uri: string that contains information for connecting to a database.
|
||||||
(default: 'sqlite://dummy.db')
|
(default: 'sqlite://dummy.db')
|
||||||
|
|
||||||
|
experimental: you can specify a dictionary as uri
|
||||||
|
parameter i.e. with
|
||||||
|
db = DAL({"uri": "sqlite://storage.sqlite",
|
||||||
|
"items": {...}, ...})
|
||||||
|
|
||||||
|
for an example of dict input you can check the output
|
||||||
|
of the scaffolding db model with
|
||||||
|
|
||||||
|
db.as_dict()
|
||||||
|
|
||||||
|
Note that for compatibility with Python older than
|
||||||
|
version 2.6.5 you should cast your dict input keys
|
||||||
|
to str due to a syntax limitation on kwarg names.
|
||||||
|
for proper DAL dictionary input you can use one of:
|
||||||
|
|
||||||
|
obj = serializers.cast_keys(dict, [encoding="utf-8"])
|
||||||
|
|
||||||
|
or else (for parsing json input)
|
||||||
|
|
||||||
|
obj = serializers.loads_json(data, unicode_keys=False)
|
||||||
|
|
||||||
:pool_size: How many open connections to make to the database object.
|
:pool_size: How many open connections to make to the database object.
|
||||||
:folder: where .table files will be created.
|
:folder: where .table files will be created.
|
||||||
automatically set within web2py
|
automatically set within web2py
|
||||||
@@ -8817,6 +8842,8 @@ class Expression(object):
|
|||||||
result_type = 'integer'
|
result_type = 'integer'
|
||||||
elif self.type in ['date','time','datetime','double','float']:
|
elif self.type in ['date','time','datetime','double','float']:
|
||||||
result_type = 'double'
|
result_type = 'double'
|
||||||
|
elif self.type.startswith('decimal('):
|
||||||
|
result_type = self.type
|
||||||
else:
|
else:
|
||||||
raise SyntaxError("subtraction operation not supported for type")
|
raise SyntaxError("subtraction operation not supported for type")
|
||||||
return Expression(db,db._adapter.SUB,self,other,result_type)
|
return Expression(db,db._adapter.SUB,self,other,result_type)
|
||||||
@@ -9037,7 +9064,7 @@ class FieldVirtual(object):
|
|||||||
(self.name, self.f) = (name, f) if f else ('unkown', name)
|
(self.name, self.f) = (name, f) if f else ('unkown', name)
|
||||||
self.type = ftype
|
self.type = ftype
|
||||||
self.label = label or self.name.capitalize().replace('_',' ')
|
self.label = label or self.name.capitalize().replace('_',' ')
|
||||||
self.represent = IDENTITY
|
self.represent = IDENTITY
|
||||||
self.formatter = IDENTITY
|
self.formatter = IDENTITY
|
||||||
self.comment = None
|
self.comment = None
|
||||||
self.readable = True
|
self.readable = True
|
||||||
@@ -9237,7 +9264,7 @@ class Field(Expression):
|
|||||||
|
|
||||||
def retrieve(self, name, path=None, nameonly=False):
|
def retrieve(self, name, path=None, nameonly=False):
|
||||||
"""
|
"""
|
||||||
if nameonly==True return (filename, fullfilename) instead of
|
if nameonly==True return (filename, fullfilename) instead of
|
||||||
(filename, stream)
|
(filename, stream)
|
||||||
"""
|
"""
|
||||||
self_uploadfield = self.uploadfield
|
self_uploadfield = self.uploadfield
|
||||||
@@ -9399,7 +9426,7 @@ class Field(Expression):
|
|||||||
if k == "other":
|
if k == "other":
|
||||||
if isinstance(v, dict):
|
if isinstance(v, dict):
|
||||||
otype, other = v.popitem()
|
otype, other = v.popitem()
|
||||||
else:
|
else:
|
||||||
otype = flatten(type(v))
|
otype = flatten(type(v))
|
||||||
other = v
|
other = v
|
||||||
newr[k] = {otype: filter_requires(otype, other,
|
newr[k] = {otype: filter_requires(otype, other,
|
||||||
|
|||||||
+1
-1
@@ -131,7 +131,7 @@ def get_client(env):
|
|||||||
"""
|
"""
|
||||||
g = regex_client.search(env.get('http_x_forwarded_for', ''))
|
g = regex_client.search(env.get('http_x_forwarded_for', ''))
|
||||||
client = (g.group() or '').split(',')[0] if g else None
|
client = (g.group() or '').split(',')[0] if g else None
|
||||||
if client in (None, '', 'unkown'):
|
if client in (None, '', 'unknown'):
|
||||||
g = regex_client.search(env.get('remote_addr', ''))
|
g = regex_client.search(env.get('remote_addr', ''))
|
||||||
if g:
|
if g:
|
||||||
client = g.group()
|
client = g.group()
|
||||||
|
|||||||
+3
-2
@@ -66,7 +66,7 @@ class XssCleaner(HTMLParser):
|
|||||||
# The only schemes allowed in URLs (for href and src attributes).
|
# The only schemes allowed in URLs (for href and src attributes).
|
||||||
# Adding "javascript" or "vbscript" to this list would not be smart.
|
# Adding "javascript" or "vbscript" to this list would not be smart.
|
||||||
|
|
||||||
self.allowed_schemes = ['http', 'https', 'ftp']
|
self.allowed_schemes = ['http', 'https', 'ftp', 'mailto']
|
||||||
|
|
||||||
#to strip or escape disallowed tags?
|
#to strip or escape disallowed tags?
|
||||||
self.strip_disallowed = strip_disallowed
|
self.strip_disallowed = strip_disallowed
|
||||||
@@ -151,11 +151,12 @@ class XssCleaner(HTMLParser):
|
|||||||
|
|
||||||
def url_is_acceptable(self, url):
|
def url_is_acceptable(self, url):
|
||||||
"""
|
"""
|
||||||
Accepts relative and absolute urls
|
Accepts relative, absolute, and mailto urls
|
||||||
"""
|
"""
|
||||||
|
|
||||||
parsed = urlparse(url)
|
parsed = urlparse(url)
|
||||||
return (parsed[0] in self.allowed_schemes and '.' in parsed[1]) \
|
return (parsed[0] in self.allowed_schemes and '.' in parsed[1]) \
|
||||||
|
or (parsed[0] in self.allowed_schemes and '@' in parsed[2]) \
|
||||||
or (parsed[0] == '' and parsed[2].startswith('/'))
|
or (parsed[0] == '' and parsed[2].startswith('/'))
|
||||||
|
|
||||||
def strip(self, rawstring, escape=True):
|
def strip(self, rawstring, escape=True):
|
||||||
|
|||||||
+40
-2
@@ -107,6 +107,7 @@ TERMINATE = 'TERMINATE'
|
|||||||
DISABLED = 'DISABLED'
|
DISABLED = 'DISABLED'
|
||||||
KILL = 'KILL'
|
KILL = 'KILL'
|
||||||
PICK = 'PICK'
|
PICK = 'PICK'
|
||||||
|
STOP_TASK = 'STOP_TASK'
|
||||||
EXPIRED = 'EXPIRED'
|
EXPIRED = 'EXPIRED'
|
||||||
SECONDS = 1
|
SECONDS = 1
|
||||||
HEARTBEAT = 3 * SECONDS
|
HEARTBEAT = 3 * SECONDS
|
||||||
@@ -398,7 +399,7 @@ class MetaScheduler(threading.Thread):
|
|||||||
|
|
||||||
TASK_STATUS = (QUEUED, RUNNING, COMPLETED, FAILED, TIMEOUT, STOPPED, EXPIRED)
|
TASK_STATUS = (QUEUED, RUNNING, COMPLETED, FAILED, TIMEOUT, STOPPED, EXPIRED)
|
||||||
RUN_STATUS = (RUNNING, COMPLETED, FAILED, TIMEOUT, STOPPED)
|
RUN_STATUS = (RUNNING, COMPLETED, FAILED, TIMEOUT, STOPPED)
|
||||||
WORKER_STATUS = (ACTIVE, PICK, DISABLED, TERMINATE, KILL)
|
WORKER_STATUS = (ACTIVE, PICK, DISABLED, TERMINATE, KILL, STOP_TASK)
|
||||||
|
|
||||||
|
|
||||||
class TYPE(object):
|
class TYPE(object):
|
||||||
@@ -746,7 +747,7 @@ class Scheduler(MetaScheduler):
|
|||||||
# keep sleeping
|
# keep sleeping
|
||||||
self.worker_status[0] = DISABLED
|
self.worker_status[0] = DISABLED
|
||||||
if self.worker_status[1] == MAXHIBERNATION:
|
if self.worker_status[1] == MAXHIBERNATION:
|
||||||
logger.debug('........recording heartbeat')
|
logger.debug('........recording heartbeat (%s)', self.worker_status[0])
|
||||||
db(sw.worker_name == self.worker_name).update(
|
db(sw.worker_name == self.worker_name).update(
|
||||||
last_heartbeat=now)
|
last_heartbeat=now)
|
||||||
elif mybackedstatus == TERMINATE:
|
elif mybackedstatus == TERMINATE:
|
||||||
@@ -758,6 +759,9 @@ class Scheduler(MetaScheduler):
|
|||||||
self.worker_status[0] = KILL
|
self.worker_status[0] = KILL
|
||||||
self.die()
|
self.die()
|
||||||
else:
|
else:
|
||||||
|
if mybackedstatus == STOP_TASK:
|
||||||
|
logger.info('Asked to kill the current task')
|
||||||
|
self.terminate_process()
|
||||||
logger.debug('........recording heartbeat (%s)', self.worker_status[0])
|
logger.debug('........recording heartbeat (%s)', self.worker_status[0])
|
||||||
db(sw.worker_name == self.worker_name).update(
|
db(sw.worker_name == self.worker_name).update(
|
||||||
last_heartbeat=now, status=ACTIVE)
|
last_heartbeat=now, status=ACTIVE)
|
||||||
@@ -1007,6 +1011,40 @@ class Scheduler(MetaScheduler):
|
|||||||
object_hook=_decode_dict) or None
|
object_hook=_decode_dict) or None
|
||||||
return row
|
return row
|
||||||
|
|
||||||
|
def stop_task(self, ref):
|
||||||
|
"""
|
||||||
|
Experimental!!!
|
||||||
|
Shortcut for task termination.
|
||||||
|
If the task is RUNNING it will terminate it --> execution will be set as FAILED
|
||||||
|
If the task is QUEUED, its stop_time will be set as to "now",
|
||||||
|
the enabled flag will be set to False, status to STOPPED
|
||||||
|
|
||||||
|
:param ref: can be
|
||||||
|
- integer --> lookup will be done by scheduler_task.id
|
||||||
|
- string --> lookup will be done by scheduler_task.uuid
|
||||||
|
Returns:
|
||||||
|
- 1 if task was stopped (meaning an update has been done)
|
||||||
|
- None if task was not found, or if task was not RUNNING or QUEUED
|
||||||
|
"""
|
||||||
|
from gluon.dal import Query
|
||||||
|
st, sw = self.db.scheduler_task, self.db.scheduler_worker
|
||||||
|
if isinstance(ref, int):
|
||||||
|
q = st.id == ref
|
||||||
|
elif isinstance(ref, str):
|
||||||
|
q = st.uuid == ref
|
||||||
|
else:
|
||||||
|
raise SyntaxError(
|
||||||
|
"You can retrieve results only by id or uuid")
|
||||||
|
task = self.db(q).select(st.id, st.status, st.assigned_worker_name).first()
|
||||||
|
rtn = None
|
||||||
|
if not task:
|
||||||
|
return rtn
|
||||||
|
if task.status == 'RUNNING':
|
||||||
|
rtn = self.db(sw.worker_name == task.assigned_worker_name).update(status=STOP_TASK)
|
||||||
|
elif task.status == 'QUEUED':
|
||||||
|
rtn = self.db(q).update(stop_time=self.now(), enabled=False, status=STOPPED)
|
||||||
|
return rtn
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""
|
"""
|
||||||
|
|||||||
+45
-2
@@ -25,9 +25,52 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
have_yaml = False
|
have_yaml = False
|
||||||
|
|
||||||
def loads_json(o):
|
def cast_keys(o, cast=str, encoding="utf-8"):
|
||||||
|
""" Builds a new object with <cast> type keys
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
o is the object input
|
||||||
|
cast (defaults to str) is an object type or function
|
||||||
|
which supports conversion such as:
|
||||||
|
|
||||||
|
>>> converted = cast(o)
|
||||||
|
|
||||||
|
encoding (defaults to utf-8) is the encoding for unicode
|
||||||
|
keys. This is not used for custom cast functions
|
||||||
|
|
||||||
|
Use this funcion if you are in Python < 2.6.5
|
||||||
|
This avoids syntax errors when unpacking dictionary arguments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if isinstance(o, (dict, Storage)):
|
||||||
|
if isinstance(o, dict):
|
||||||
|
newobj = dict()
|
||||||
|
else:
|
||||||
|
newobj = Storage()
|
||||||
|
|
||||||
|
for k, v in o.items():
|
||||||
|
if (cast == str) and isinstance(k, unicode):
|
||||||
|
key = k.encode(encoding)
|
||||||
|
else:
|
||||||
|
key = cast(k)
|
||||||
|
if isinstance(v, (dict, Storage)):
|
||||||
|
value = cast_keys(v, cast=cast, encoding=encoding)
|
||||||
|
else:
|
||||||
|
value = v
|
||||||
|
newobj[key] = value
|
||||||
|
else:
|
||||||
|
raise TypeError("Cannot cast keys: %s is not supported" % \
|
||||||
|
type(o))
|
||||||
|
return newobj
|
||||||
|
|
||||||
|
def loads_json(o, unicode_keys=True, **kwargs):
|
||||||
# deserialize a json string
|
# deserialize a json string
|
||||||
return json_parser.loads(o)
|
result = json_parser.loads(o, **kwargs)
|
||||||
|
if not unicode_keys:
|
||||||
|
# filter non-str keys in dictionary objects
|
||||||
|
result = cast_keys(result,
|
||||||
|
encoding=kwargs.get("encoding", "utf-8"))
|
||||||
|
return result
|
||||||
|
|
||||||
def custom_json(o):
|
def custom_json(o):
|
||||||
if hasattr(o, 'custom_json') and callable(o.custom_json):
|
if hasattr(o, 'custom_json') and callable(o.custom_json):
|
||||||
|
|||||||
+2
-1
@@ -1440,7 +1440,8 @@ class SQLFORM(FORM):
|
|||||||
f = self.table[fieldname].default or ''
|
f = self.table[fieldname].default or ''
|
||||||
fields[fieldname] = f
|
fields[fieldname] = f
|
||||||
else:
|
else:
|
||||||
fields[fieldname] = ''
|
f = self.table[fieldname].default or ''
|
||||||
|
fields[fieldname] = f
|
||||||
self.vars[fieldname] = fields[fieldname]
|
self.vars[fieldname] = fields[fieldname]
|
||||||
if not f:
|
if not f:
|
||||||
continue
|
continue
|
||||||
|
|||||||
+304
-282
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import glob
|
||||||
|
|
||||||
if os.path.isdir('gluon'):
|
if os.path.isdir('gluon'):
|
||||||
sys.path.append(os.path.realpath('gluon'))
|
sys.path.append(os.path.realpath('gluon'))
|
||||||
else:
|
else:
|
||||||
@@ -19,6 +21,11 @@ except:
|
|||||||
from io import StringIO
|
from io import StringIO
|
||||||
from dal import DAL, Field, Table, SQLALL
|
from dal import DAL, Field, Table, SQLALL
|
||||||
|
|
||||||
|
#for travis-ci
|
||||||
|
DEFAULT_URI = os.environ.get('DB', 'sqlite:memory')
|
||||||
|
print 'Testing against %s engine (%s)' % (DEFAULT_URI.partition(':')[0], DEFAULT_URI)
|
||||||
|
|
||||||
|
|
||||||
ALLOWED_DATATYPES = [
|
ALLOWED_DATATYPES = [
|
||||||
'string',
|
'string',
|
||||||
'text',
|
'text',
|
||||||
@@ -41,6 +48,8 @@ def setUpModule():
|
|||||||
def tearDownModule():
|
def tearDownModule():
|
||||||
if os.path.isfile('sql.log'):
|
if os.path.isfile('sql.log'):
|
||||||
os.unlink('sql.log')
|
os.unlink('sql.log')
|
||||||
|
for a in glob.glob('*.table'):
|
||||||
|
os.unlink(a)
|
||||||
|
|
||||||
|
|
||||||
class TestFields(unittest.TestCase):
|
class TestFields(unittest.TestCase):
|
||||||
@@ -96,35 +105,35 @@ class TestFields(unittest.TestCase):
|
|||||||
isinstance(f.formatter(datetime.datetime.now()), str)
|
isinstance(f.formatter(datetime.datetime.now()), str)
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
for ft in ['string', 'text', 'password', 'upload', 'blob']:
|
for ft in ['string', 'text', 'password', 'upload', 'blob']:
|
||||||
db.define_table('t', Field('a', ft, default=''))
|
db.define_table('tt', Field('aa', ft, default=''))
|
||||||
self.assertEqual(db.t.insert(a='x'), 1)
|
self.assertEqual(db.tt.insert(aa='x'), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, 'x')
|
self.assertEqual(db().select(db.tt.aa)[0].aa, 'x')
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'integer', default=1))
|
db.define_table('tt', Field('aa', 'integer', default=1))
|
||||||
self.assertEqual(db.t.insert(a=3), 1)
|
self.assertEqual(db.tt.insert(aa=3), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, 3)
|
self.assertEqual(db().select(db.tt.aa)[0].aa, 3)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'double', default=1))
|
db.define_table('tt', Field('aa', 'double', default=1))
|
||||||
self.assertEqual(db.t.insert(a=3.1), 1)
|
self.assertEqual(db.tt.insert(aa=3.1), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, 3.1)
|
self.assertEqual(db().select(db.tt.aa)[0].aa, 3.1)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'boolean', default=True))
|
db.define_table('tt', Field('aa', 'boolean', default=True))
|
||||||
self.assertEqual(db.t.insert(a=True), 1)
|
self.assertEqual(db.tt.insert(aa=True), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, True)
|
self.assertEqual(db().select(db.tt.aa)[0].aa, True)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'json', default={}))
|
db.define_table('tt', Field('aa', 'json', default={}))
|
||||||
self.assertEqual(db.t.insert(a={}), 1)
|
self.assertEqual(db.tt.insert(aa={}), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, {})
|
self.assertEqual(db().select(db.tt.aa)[0].aa, {})
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'date',
|
db.define_table('tt', Field('aa', 'date',
|
||||||
default=datetime.date.today()))
|
default=datetime.date.today()))
|
||||||
t0 = datetime.date.today()
|
t0 = datetime.date.today()
|
||||||
self.assertEqual(db.t.insert(a=t0), 1)
|
self.assertEqual(db.tt.insert(aa=t0), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, t0)
|
self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'datetime',
|
db.define_table('tt', Field('aa', 'datetime',
|
||||||
default=datetime.datetime.today()))
|
default=datetime.datetime.today()))
|
||||||
t0 = datetime.datetime(
|
t0 = datetime.datetime(
|
||||||
1971,
|
1971,
|
||||||
@@ -135,34 +144,34 @@ class TestFields(unittest.TestCase):
|
|||||||
55,
|
55,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
self.assertEqual(db.t.insert(a=t0), 1)
|
self.assertEqual(db.tt.insert(aa=t0), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, t0)
|
self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
|
||||||
|
|
||||||
## Row APIs
|
## Row APIs
|
||||||
row = db().select(db.t.a)[0]
|
row = db().select(db.tt.aa)[0]
|
||||||
self.assertEqual(db.t[1].a,t0)
|
self.assertEqual(db.tt[1].aa,t0)
|
||||||
self.assertEqual(db.t['a'],db.t.a)
|
self.assertEqual(db.tt['aa'],db.tt.aa)
|
||||||
self.assertEqual(db.t(1).a,t0)
|
self.assertEqual(db.tt(1).aa,t0)
|
||||||
self.assertTrue(db.t(1,a=None)==None)
|
self.assertTrue(db.tt(1,aa=None)==None)
|
||||||
self.assertFalse(db.t(1,a=t0)==None)
|
self.assertFalse(db.tt(1,aa=t0)==None)
|
||||||
self.assertEqual(row.a,t0)
|
self.assertEqual(row.aa,t0)
|
||||||
self.assertEqual(row['a'],t0)
|
self.assertEqual(row['aa'],t0)
|
||||||
self.assertEqual(row['t.a'],t0)
|
self.assertEqual(row['tt.aa'],t0)
|
||||||
self.assertEqual(row('t.a'),t0)
|
self.assertEqual(row('tt.aa'),t0)
|
||||||
|
|
||||||
## Lazy and Virtual fields
|
## Lazy and Virtual fields
|
||||||
db.t.b = Field.Virtual(lambda row: row.t.a)
|
db.tt.b = Field.Virtual(lambda row: row.tt.aa)
|
||||||
db.t.c = Field.Lazy(lambda row: row.t.a)
|
db.tt.c = Field.Lazy(lambda row: row.tt.aa)
|
||||||
row = db().select(db.t.a)[0]
|
row = db().select(db.tt.aa)[0]
|
||||||
self.assertEqual(row.b,t0)
|
self.assertEqual(row.b,t0)
|
||||||
self.assertEqual(row.c(),t0)
|
self.assertEqual(row.c(),t0)
|
||||||
|
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'time', default='11:30'))
|
db.define_table('tt', Field('aa', 'time', default='11:30'))
|
||||||
t0 = datetime.time(10, 30, 55)
|
t0 = datetime.time(10, 30, 55)
|
||||||
self.assertEqual(db.t.insert(a=t0), 1)
|
self.assertEqual(db.tt.insert(aa=t0), 1)
|
||||||
self.assertEqual(db().select(db.t.a)[0].a, t0)
|
self.assertEqual(db().select(db.tt.aa)[0].aa, t0)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestAll(unittest.TestCase):
|
class TestAll(unittest.TestCase):
|
||||||
@@ -198,7 +207,7 @@ class TestTable(unittest.TestCase):
|
|||||||
in str(persons.ALL))
|
in str(persons.ALL))
|
||||||
|
|
||||||
def testTableAlias(self):
|
def testTableAlias(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
persons = Table(db, 'persons', Field('firstname',
|
persons = Table(db, 'persons', Field('firstname',
|
||||||
'string'), Field('lastname', 'string'))
|
'string'), Field('lastname', 'string'))
|
||||||
aliens = persons.with_alias('aliens')
|
aliens = persons.with_alias('aliens')
|
||||||
@@ -221,276 +230,278 @@ class TestTable(unittest.TestCase):
|
|||||||
class TestInsert(unittest.TestCase):
|
class TestInsert(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
self.assertEqual(db.t.insert(a='1'), 1)
|
self.assertEqual(db.tt.insert(aa='1'), 1)
|
||||||
self.assertEqual(db.t.insert(a='1'), 2)
|
self.assertEqual(db.tt.insert(aa='1'), 2)
|
||||||
self.assertEqual(db.t.insert(a='1'), 3)
|
self.assertEqual(db.tt.insert(aa='1'), 3)
|
||||||
self.assertEqual(db(db.t.a == '1').count(), 3)
|
self.assertEqual(db(db.tt.aa == '1').count(), 3)
|
||||||
self.assertEqual(db(db.t.a == '1').update(a='2'), 3)
|
self.assertEqual(db(db.tt.aa == '1').update(aa='2'), 3)
|
||||||
self.assertEqual(db(db.t.a == '2').count(), 3)
|
self.assertEqual(db(db.tt.aa == '2').count(), 3)
|
||||||
self.assertEqual(db(db.t.a == '2').delete(), 3)
|
self.assertEqual(db(db.tt.aa == '2').delete(), 3)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestSelect(unittest.TestCase):
|
class TestSelect(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
self.assertEqual(db.t.insert(a='1'), 1)
|
self.assertEqual(db.tt.insert(aa='1'), 1)
|
||||||
self.assertEqual(db.t.insert(a='2'), 2)
|
self.assertEqual(db.tt.insert(aa='2'), 2)
|
||||||
self.assertEqual(db.t.insert(a='3'), 3)
|
self.assertEqual(db.tt.insert(aa='3'), 3)
|
||||||
self.assertEqual(len(db(db.t.id > 0).select()), 3)
|
self.assertEqual(len(db(db.tt.id > 0).select()), 3)
|
||||||
self.assertEqual(db(db.t.id > 0).select(orderby=~db.t.a
|
self.assertEqual(db(db.tt.id > 0).select(orderby=~db.tt.aa
|
||||||
| db.t.id)[0].a, '3')
|
| db.tt.id)[0].aa, '3')
|
||||||
self.assertEqual(len(db(db.t.id > 0).select(limitby=(1, 2))), 1)
|
self.assertEqual(len(db(db.tt.id > 0).select(limitby=(1, 2))), 1)
|
||||||
self.assertEqual(db(db.t.id > 0).select(limitby=(1, 2))[0].a,
|
self.assertEqual(db(db.tt.id > 0).select(limitby=(1, 2))[0].aa,
|
||||||
'2')
|
'2')
|
||||||
self.assertEqual(len(db().select(db.t.ALL)), 3)
|
self.assertEqual(len(db().select(db.tt.ALL)), 3)
|
||||||
self.assertEqual(len(db(db.t.a == None).select()), 0)
|
self.assertEqual(len(db(db.tt.aa == None).select()), 0)
|
||||||
self.assertEqual(len(db(db.t.a != None).select()), 3)
|
self.assertEqual(len(db(db.tt.aa != None).select()), 3)
|
||||||
self.assertEqual(len(db(db.t.a > '1').select()), 2)
|
self.assertEqual(len(db(db.tt.aa > '1').select()), 2)
|
||||||
self.assertEqual(len(db(db.t.a >= '1').select()), 3)
|
self.assertEqual(len(db(db.tt.aa >= '1').select()), 3)
|
||||||
self.assertEqual(len(db(db.t.a == '1').select()), 1)
|
self.assertEqual(len(db(db.tt.aa == '1').select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a != '1').select()), 2)
|
self.assertEqual(len(db(db.tt.aa != '1').select()), 2)
|
||||||
self.assertEqual(len(db(db.t.a < '3').select()), 2)
|
self.assertEqual(len(db(db.tt.aa < '3').select()), 2)
|
||||||
self.assertEqual(len(db(db.t.a <= '3').select()), 3)
|
self.assertEqual(len(db(db.tt.aa <= '3').select()), 3)
|
||||||
self.assertEqual(len(db(db.t.a > '1')(db.t.a < '3').select()), 1)
|
self.assertEqual(len(db(db.tt.aa > '1')(db.tt.aa < '3').select()), 1)
|
||||||
self.assertEqual(len(db((db.t.a > '1') & (db.t.a < '3')).select()), 1)
|
self.assertEqual(len(db((db.tt.aa > '1') & (db.tt.aa < '3')).select()), 1)
|
||||||
self.assertEqual(len(db((db.t.a > '1') | (db.t.a < '3')).select()), 3)
|
self.assertEqual(len(db((db.tt.aa > '1') | (db.tt.aa < '3')).select()), 3)
|
||||||
self.assertEqual(len(db((db.t.a > '1') & ~(db.t.a > '2')).select()), 1)
|
self.assertEqual(len(db((db.tt.aa > '1') & ~(db.tt.aa > '2')).select()), 1)
|
||||||
self.assertEqual(len(db(~(db.t.a > '1') & (db.t.a > '2')).select()), 0)
|
self.assertEqual(len(db(~(db.tt.aa > '1') & (db.tt.aa > '2')).select()), 0)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestBelongs(unittest.TestCase):
|
class TestBelongs(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
self.assertEqual(db.t.insert(a='1'), 1)
|
self.assertEqual(db.tt.insert(aa='1'), 1)
|
||||||
self.assertEqual(db.t.insert(a='2'), 2)
|
self.assertEqual(db.tt.insert(aa='2'), 2)
|
||||||
self.assertEqual(db.t.insert(a='3'), 3)
|
self.assertEqual(db.tt.insert(aa='3'), 3)
|
||||||
self.assertEqual(len(db(db.t.a.belongs(('1', '3'))).select()),
|
self.assertEqual(len(db(db.tt.aa.belongs(('1', '3'))).select()),
|
||||||
2)
|
2)
|
||||||
self.assertEqual(len(db(db.t.a.belongs(db(db.t.id
|
self.assertEqual(len(db(db.tt.aa.belongs(db(db.tt.id
|
||||||
> 2)._select(db.t.a))).select()), 1)
|
> 2)._select(db.tt.aa))).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.belongs(db(db.t.a.belongs(('1',
|
self.assertEqual(len(db(db.tt.aa.belongs(db(db.tt.aa.belongs(('1',
|
||||||
'3')))._select(db.t.a))).select()), 2)
|
'3')))._select(db.tt.aa))).select()), 2)
|
||||||
self.assertEqual(len(db(db.t.a.belongs(db(db.t.a.belongs(db
|
self.assertEqual(len(db(db.tt.aa.belongs(db(db.tt.aa.belongs(db
|
||||||
(db.t.a.belongs(('1', '3')))._select(db.t.a)))._select(
|
(db.tt.aa.belongs(('1', '3')))._select(db.tt.aa)))._select(
|
||||||
db.t.a))).select()),
|
db.tt.aa))).select()),
|
||||||
2)
|
2)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestContains(unittest.TestCase):
|
class TestContains(unittest.TestCase):
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a', 'list:string'))
|
db.define_table('tt', Field('aa', 'list:string'))
|
||||||
self.assertEqual(db.t.insert(a=['aaa','bbb']), 1)
|
self.assertEqual(db.tt.insert(aa=['aaa','bbb']), 1)
|
||||||
self.assertEqual(db.t.insert(a=['bbb','ddd']), 2)
|
self.assertEqual(db.tt.insert(aa=['bbb','ddd']), 2)
|
||||||
self.assertEqual(db.t.insert(a=['eee','aaa']), 3)
|
self.assertEqual(db.tt.insert(aa=['eee','aaa']), 3)
|
||||||
self.assertEqual(len(db(db.t.a.contains('aaa')).select()),
|
self.assertEqual(len(db(db.tt.aa.contains('aaa')).select()),
|
||||||
2)
|
2)
|
||||||
self.assertEqual(len(db(db.t.a.contains('bbb')).select()),
|
self.assertEqual(len(db(db.tt.aa.contains('bbb')).select()),
|
||||||
2)
|
2)
|
||||||
self.assertEqual(len(db(db.t.a.contains('aa')).select()),
|
self.assertEqual(len(db(db.tt.aa.contains('aa')).select()),
|
||||||
0)
|
0)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestLike(unittest.TestCase):
|
class TestLike(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
self.assertEqual(db.t.insert(a='abc'), 1)
|
self.assertEqual(db.tt.insert(aa='abc'), 1)
|
||||||
self.assertEqual(len(db(db.t.a.like('a%')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.like('a%')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.like('%b%')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.like('%b%')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.like('%c')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.like('%c')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.like('%d%')).select()), 0)
|
self.assertEqual(len(db(db.tt.aa.like('%d%')).select()), 0)
|
||||||
self.assertEqual(len(db(db.t.a.lower().like('A%')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.lower().like('A%')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.lower().like('%B%')).select()),
|
self.assertEqual(len(db(db.tt.aa.lower().like('%B%')).select()),
|
||||||
1)
|
1)
|
||||||
self.assertEqual(len(db(db.t.a.lower().like('%C')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.lower().like('%C')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.upper().like('A%')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.upper().like('A%')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.upper().like('%B%')).select()),
|
self.assertEqual(len(db(db.tt.aa.upper().like('%B%')).select()),
|
||||||
1)
|
1)
|
||||||
self.assertEqual(len(db(db.t.a.upper().like('%C')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.upper().like('%C')).select()), 1)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.define_table('t', Field('a', 'integer'))
|
db.define_table('tt', Field('aa', 'integer'))
|
||||||
self.assertEqual(db.t.insert(a=1111111111), 1)
|
self.assertEqual(db.tt.insert(aa=1111111111), 1)
|
||||||
self.assertEqual(len(db(db.t.a.like('1%')).select()), 1)
|
self.assertEqual(len(db(db.tt.aa.like('1%')).select()), 1)
|
||||||
self.assertEqual(len(db(db.t.a.like('2%')).select()), 0)
|
self.assertEqual(len(db(db.tt.aa.like('2%')).select()), 0)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestDatetime(unittest.TestCase):
|
class TestDatetime(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a', 'datetime'))
|
db.define_table('tt', Field('aa', 'datetime'))
|
||||||
self.assertEqual(db.t.insert(a=datetime.datetime(1971, 12, 21,
|
self.assertEqual(db.tt.insert(aa=datetime.datetime(1971, 12, 21,
|
||||||
11, 30)), 1)
|
11, 30)), 1)
|
||||||
self.assertEqual(db.t.insert(a=datetime.datetime(1971, 11, 21,
|
self.assertEqual(db.tt.insert(aa=datetime.datetime(1971, 11, 21,
|
||||||
10, 30)), 2)
|
10, 30)), 2)
|
||||||
self.assertEqual(db.t.insert(a=datetime.datetime(1970, 12, 21,
|
self.assertEqual(db.tt.insert(aa=datetime.datetime(1970, 12, 21,
|
||||||
9, 30)), 3)
|
9, 30)), 3)
|
||||||
self.assertEqual(len(db(db.t.a == datetime.datetime(1971, 12,
|
self.assertEqual(len(db(db.tt.aa == datetime.datetime(1971, 12,
|
||||||
21, 11, 30)).select()), 1)
|
21, 11, 30)).select()), 1)
|
||||||
self.assertEqual(db(db.t.a.year() == 1971).count(), 2)
|
self.assertEqual(db(db.tt.aa.year() == 1971).count(), 2)
|
||||||
self.assertEqual(db(db.t.a.month() == 12).count(), 2)
|
self.assertEqual(db(db.tt.aa.month() == 12).count(), 2)
|
||||||
self.assertEqual(db(db.t.a.day() == 21).count(), 3)
|
self.assertEqual(db(db.tt.aa.day() == 21).count(), 3)
|
||||||
self.assertEqual(db(db.t.a.hour() == 11).count(), 1)
|
self.assertEqual(db(db.tt.aa.hour() == 11).count(), 1)
|
||||||
self.assertEqual(db(db.t.a.minutes() == 30).count(), 3)
|
self.assertEqual(db(db.tt.aa.minutes() == 30).count(), 3)
|
||||||
self.assertEqual(db(db.t.a.seconds() == 0).count(), 3)
|
self.assertEqual(db(db.tt.aa.seconds() == 0).count(), 3)
|
||||||
self.assertEqual(db(db.t.a.epoch()<365*24*3600).count(),1)
|
self.assertEqual(db(db.tt.aa.epoch()<365*24*3600).count(),1)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestExpressions(unittest.TestCase):
|
class TestExpressions(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a', 'integer'))
|
db.define_table('tt', Field('aa', 'integer'))
|
||||||
self.assertEqual(db.t.insert(a=1), 1)
|
self.assertEqual(db.tt.insert(aa=1), 1)
|
||||||
self.assertEqual(db.t.insert(a=2), 2)
|
self.assertEqual(db.tt.insert(aa=2), 2)
|
||||||
self.assertEqual(db.t.insert(a=3), 3)
|
self.assertEqual(db.tt.insert(aa=3), 3)
|
||||||
self.assertEqual(db(db.t.a == 3).update(a=db.t.a + 1), 1)
|
self.assertEqual(db(db.tt.aa == 3).update(aa=db.tt.aa + 1), 1)
|
||||||
self.assertEqual(db(db.t.a == 4).count(), 1)
|
self.assertEqual(db(db.tt.aa == 4).count(), 1)
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestJoin(unittest.TestCase):
|
class TestJoin(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t1', Field('a'))
|
db.define_table('t1', Field('aa'))
|
||||||
db.define_table('t2', Field('a'), Field('b', db.t1))
|
db.define_table('t2', Field('aa'), Field('b', db.t1))
|
||||||
i1 = db.t1.insert(a='1')
|
i1 = db.t1.insert(aa='1')
|
||||||
i2 = db.t1.insert(a='2')
|
i2 = db.t1.insert(aa='2')
|
||||||
i3 = db.t1.insert(a='3')
|
i3 = db.t1.insert(aa='3')
|
||||||
db.t2.insert(a='4', b=i1)
|
db.t2.insert(aa='4', b=i1)
|
||||||
db.t2.insert(a='5', b=i2)
|
db.t2.insert(aa='5', b=i2)
|
||||||
db.t2.insert(a='6', b=i2)
|
db.t2.insert(aa='6', b=i2)
|
||||||
self.assertEqual(len(db(db.t1.id
|
self.assertEqual(len(db(db.t1.id
|
||||||
== db.t2.b).select(orderby=db.t1.a
|
== db.t2.b).select(orderby=db.t1.aa
|
||||||
| db.t2.a)), 3)
|
| db.t2.aa)), 3)
|
||||||
self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.a
|
self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
|
||||||
| db.t2.a)[2].t1.a, '2')
|
| db.t2.aa)[2].t1.aa, '2')
|
||||||
self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.a
|
self.assertEqual(db(db.t1.id == db.t2.b).select(orderby=db.t1.aa
|
||||||
| db.t2.a)[2].t2.a, '6')
|
| db.t2.aa)[2].t2.aa, '6')
|
||||||
self.assertEqual(len(db().select(db.t1.ALL, db.t2.ALL,
|
self.assertEqual(len(db().select(db.t1.ALL, db.t2.ALL,
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a)), 4)
|
orderby=db.t1.aa | db.t2.aa)), 4)
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a)[2].t1.a, '2')
|
orderby=db.t1.aa | db.t2.aa)[2].t1.aa, '2')
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a)[2].t2.a, '6')
|
orderby=db.t1.aa | db.t2.aa)[2].t2.aa, '6')
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a)[3].t1.a, '3')
|
orderby=db.t1.aa | db.t2.aa)[3].t1.aa, '3')
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
self.assertEqual(db().select(db.t1.ALL, db.t2.ALL,
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a)[3].t2.a, None)
|
orderby=db.t1.aa | db.t2.aa)[3].t2.aa, None)
|
||||||
self.assertEqual(len(db().select(db.t1.ALL, db.t2.id.count(),
|
self.assertEqual(len(db().select(db.t1.aa, db.t2.id.count(),
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a, groupby=db.t1.a)),
|
orderby=db.t1.aa, groupby=db.t1.aa)),
|
||||||
3)
|
3)
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.id.count(),
|
self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a,
|
orderby=db.t1.aa,
|
||||||
groupby=db.t1.a)[0]._extra[db.t2.id.count()],
|
groupby=db.t1.aa)[0]._extra[db.t2.id.count()],
|
||||||
1)
|
1)
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.id.count(),
|
self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a,
|
orderby=db.t1.aa,
|
||||||
groupby=db.t1.a)[1]._extra[db.t2.id.count()],
|
groupby=db.t1.aa)[1]._extra[db.t2.id.count()],
|
||||||
2)
|
2)
|
||||||
self.assertEqual(db().select(db.t1.ALL, db.t2.id.count(),
|
self.assertEqual(db().select(db.t1.aa, db.t2.id.count(),
|
||||||
left=db.t2.on(db.t1.id == db.t2.b),
|
left=db.t2.on(db.t1.id == db.t2.b),
|
||||||
orderby=db.t1.a | db.t2.a,
|
orderby=db.t1.aa,
|
||||||
groupby=db.t1.a)[2]._extra[db.t2.id.count()],
|
groupby=db.t1.aa)[2]._extra[db.t2.id.count()],
|
||||||
0)
|
0)
|
||||||
db.t1.drop()
|
|
||||||
db.t2.drop()
|
db.t2.drop()
|
||||||
|
db.t1.drop()
|
||||||
|
|
||||||
db.define_table('person',Field('name'))
|
db.define_table('person',Field('name'))
|
||||||
id = db.person.insert(name="max")
|
id = db.person.insert(name="max")
|
||||||
self.assertEqual(id.name,'max')
|
self.assertEqual(id.name,'max')
|
||||||
db.define_table('dog',Field('name'),Field('owner','reference person'))
|
db.define_table('dog',Field('name'),Field('ownerperson','reference person'))
|
||||||
db.dog.insert(name='skipper',owner=1)
|
db.dog.insert(name='skipper',ownerperson=1)
|
||||||
row = db(db.person.id==db.dog.owner).select().first()
|
row = db(db.person.id==db.dog.ownerperson).select().first()
|
||||||
self.assertEqual(row[db.person.name],'max')
|
self.assertEqual(row[db.person.name],'max')
|
||||||
self.assertEqual(row['person.name'],'max')
|
self.assertEqual(row['person.name'],'max')
|
||||||
db.dog.drop()
|
db.dog.drop()
|
||||||
self.assertEqual(len(db.person._referenced_by),0)
|
self.assertEqual(len(db.person._referenced_by),0)
|
||||||
db.person.drop()
|
db.person.drop()
|
||||||
|
|
||||||
class TestMinMaxSum(unittest.TestCase):
|
class TestMinMaxSumAvg(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a', 'integer'))
|
db.define_table('tt', Field('aa', 'integer'))
|
||||||
self.assertEqual(db.t.insert(a=1), 1)
|
self.assertEqual(db.tt.insert(aa=1), 1)
|
||||||
self.assertEqual(db.t.insert(a=2), 2)
|
self.assertEqual(db.tt.insert(aa=2), 2)
|
||||||
self.assertEqual(db.t.insert(a=3), 3)
|
self.assertEqual(db.tt.insert(aa=3), 3)
|
||||||
s = db.t.a.min()
|
s = db.tt.aa.min()
|
||||||
self.assertEqual(db(db.t.id > 0).select(s)[0]._extra[s], 1)
|
self.assertEqual(db(db.tt.id > 0).select(s)[0]._extra[s], 1)
|
||||||
self.assertEqual(db(db.t.id > 0).select(s).first()[s], 1)
|
self.assertEqual(db(db.tt.id > 0).select(s).first()[s], 1)
|
||||||
self.assertEqual(db().select(s).first()[s], 1)
|
self.assertEqual(db().select(s).first()[s], 1)
|
||||||
s = db.t.a.max()
|
s = db.tt.aa.max()
|
||||||
self.assertEqual(db().select(s).first()[s], 3)
|
self.assertEqual(db().select(s).first()[s], 3)
|
||||||
s = db.t.a.sum()
|
s = db.tt.aa.sum()
|
||||||
self.assertEqual(db().select(s).first()[s], 6)
|
self.assertEqual(db().select(s).first()[s], 6)
|
||||||
s = db.t.a.count()
|
s = db.tt.aa.count()
|
||||||
self.assertEqual(db().select(s).first()[s], 3)
|
self.assertEqual(db().select(s).first()[s], 3)
|
||||||
db.t.drop()
|
s = db.tt.aa.avg()
|
||||||
|
self.assertEqual(db().select(s).first()[s], 2)
|
||||||
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestCache(unittest.TestCase):
|
class TestCache(unittest.TestCase):
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
from cache import CacheInRam
|
from cache import CacheInRam
|
||||||
cache = CacheInRam()
|
cache = CacheInRam()
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
db.t.insert(a='1')
|
db.tt.insert(aa='1')
|
||||||
r0 = db().select(db.t.ALL)
|
r0 = db().select(db.tt.ALL)
|
||||||
r1 = db().select(db.t.ALL, cache=(cache, 1000))
|
r1 = db().select(db.tt.ALL, cache=(cache, 1000))
|
||||||
self.assertEqual(len(r0),len(r1))
|
self.assertEqual(len(r0),len(r1))
|
||||||
r2 = db().select(db.t.ALL, cache=(cache, 1000))
|
r2 = db().select(db.tt.ALL, cache=(cache, 1000))
|
||||||
self.assertEqual(len(r0),len(r2))
|
self.assertEqual(len(r0),len(r2))
|
||||||
r3 = db().select(db.t.ALL, cache=(cache, 1000), cacheable=True)
|
r3 = db().select(db.tt.ALL, cache=(cache, 1000), cacheable=True)
|
||||||
self.assertEqual(len(r0),len(r3))
|
self.assertEqual(len(r0),len(r3))
|
||||||
r4 = db().select(db.t.ALL, cache=(cache, 1000), cacheable=True)
|
r4 = db().select(db.tt.ALL, cache=(cache, 1000), cacheable=True)
|
||||||
self.assertEqual(len(r0),len(r4))
|
self.assertEqual(len(r0),len(r4))
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
|
|
||||||
|
|
||||||
class TestMigrations(unittest.TestCase):
|
class TestMigrations(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite://.storage.db')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'), migrate='.storage.table')
|
db.define_table('tt', Field('aa'), migrate='.storage.table')
|
||||||
db.commit()
|
db.commit()
|
||||||
db.close()
|
db.close()
|
||||||
db = DAL('sqlite://.storage.db')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'), Field('b'),
|
db.define_table('tt', Field('aa'), Field('b'),
|
||||||
migrate='.storage.table')
|
migrate='.storage.table')
|
||||||
db.commit()
|
db.commit()
|
||||||
db.close()
|
db.close()
|
||||||
db = DAL('sqlite://.storage.db')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'), Field('b', 'text'),
|
db.define_table('tt', Field('aa'), Field('b', 'text'),
|
||||||
migrate='.storage.table')
|
migrate='.storage.table')
|
||||||
db.commit()
|
db.commit()
|
||||||
db.close()
|
db.close()
|
||||||
db = DAL('sqlite://.storage.db')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'), migrate='.storage.table')
|
db.define_table('tt', Field('aa'), migrate='.storage.table')
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.commit()
|
db.commit()
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
@@ -500,81 +511,81 @@ class TestMigrations(unittest.TestCase):
|
|||||||
if os.path.exists('.storage.table'):
|
if os.path.exists('.storage.table'):
|
||||||
os.unlink('.storage.table')
|
os.unlink('.storage.table')
|
||||||
|
|
||||||
class TestReferece(unittest.TestCase):
|
class TestReference(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('name'), Field('a','reference t'))
|
db.define_table('tt', Field('name'), Field('aa','reference tt'))
|
||||||
db.commit()
|
db.commit()
|
||||||
x = db.t.insert(name='max')
|
x = db.tt.insert(name='max')
|
||||||
assert x.id == 1
|
assert x.id == 1
|
||||||
assert x['id'] == 1
|
assert x['id'] == 1
|
||||||
x.a = x
|
x.aa = x
|
||||||
assert x.a == 1
|
assert x.aa == 1
|
||||||
x.update_record()
|
x.update_record()
|
||||||
y = db.t[1]
|
y = db.tt[1]
|
||||||
assert y.a == 1
|
assert y.aa == 1
|
||||||
assert y.a.a.a.a.a.a.name == 'max'
|
assert y.aa.aa.aa.aa.aa.aa.name == 'max'
|
||||||
z=db.t.insert(name='xxx', a = y)
|
z=db.tt.insert(name='xxx', aa = y)
|
||||||
assert z.a == y.id
|
assert z.aa == y.id
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
class TestClientLevelOps(unittest.TestCase):
|
class TestClientLevelOps(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
db.commit()
|
db.commit()
|
||||||
db.t.insert(a="test")
|
db.tt.insert(aa="test")
|
||||||
rows1 = db(db.t.id>0).select()
|
rows1 = db(db.tt.id>0).select()
|
||||||
rows2 = db(db.t.id>0).select()
|
rows2 = db(db.tt.id>0).select()
|
||||||
rows3 = rows1 & rows2
|
rows3 = rows1 & rows2
|
||||||
assert len(rows3) == 2
|
assert len(rows3) == 2
|
||||||
rows4 = rows1 | rows2
|
rows4 = rows1 | rows2
|
||||||
assert len(rows4) == 1
|
assert len(rows4) == 1
|
||||||
rows5 = rows1.find(lambda row: row.a=="test")
|
rows5 = rows1.find(lambda row: row.aa=="test")
|
||||||
assert len(rows5) == 1
|
assert len(rows5) == 1
|
||||||
rows6 = rows2.exclude(lambda row: row.a=="test")
|
rows6 = rows2.exclude(lambda row: row.aa=="test")
|
||||||
assert len(rows6) == 1
|
assert len(rows6) == 1
|
||||||
rows7 = rows5.sort(lambda row: row.a)
|
rows7 = rows5.sort(lambda row: row.aa)
|
||||||
assert len(rows7) == 1
|
assert len(rows7) == 1
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
|
||||||
class TestVirtualFields(unittest.TestCase):
|
class TestVirtualFields(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t', Field('a'))
|
db.define_table('tt', Field('aa'))
|
||||||
db.commit()
|
db.commit()
|
||||||
db.t.insert(a="test")
|
db.tt.insert(aa="test")
|
||||||
class Compute:
|
class Compute:
|
||||||
def a_upper(row): return row.t.a.upper()
|
def a_upper(row): return row.tt.aa.upper()
|
||||||
db.t.virtualfields.append(Compute())
|
db.tt.virtualfields.append(Compute())
|
||||||
assert db(db.t.id>0).select().first().a_upper == 'TEST'
|
assert db(db.tt.id>0).select().first().a_upper == 'TEST'
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
class TestComputedFields(unittest.TestCase):
|
class TestComputedFields(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('t',
|
db.define_table('tt',
|
||||||
Field('a'),
|
Field('aa'),
|
||||||
Field('b',default='x'),
|
Field('bb',default='x'),
|
||||||
Field('c',compute=lambda r: r.a+r.b))
|
Field('cc',compute=lambda r: r.aa+r.bb))
|
||||||
db.commit()
|
db.commit()
|
||||||
id = db.t.insert(a="z")
|
id = db.tt.insert(aa="z")
|
||||||
self.assertEqual(db.t[id].c,'zx')
|
self.assertEqual(db.tt[id].cc,'zx')
|
||||||
db.t.drop()
|
db.tt.drop()
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
class TestImportExportFields(unittest.TestCase):
|
class TestImportExportFields(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('person', Field('name'))
|
db.define_table('person', Field('name'))
|
||||||
db.define_table('pet',Field('friend',db.person),Field('name'))
|
db.define_table('pet',Field('friend',db.person),Field('name'))
|
||||||
for n in range(2):
|
for n in range(2):
|
||||||
@@ -598,7 +609,7 @@ class TestImportExportFields(unittest.TestCase):
|
|||||||
class TestImportExportUuidFields(unittest.TestCase):
|
class TestImportExportUuidFields(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('person', Field('name'),Field('uuid'))
|
db.define_table('person', Field('name'),Field('uuid'))
|
||||||
db.define_table('pet',Field('friend',db.person),Field('name'))
|
db.define_table('pet',Field('friend',db.person),Field('name'))
|
||||||
for n in range(2):
|
for n in range(2):
|
||||||
@@ -622,7 +633,7 @@ class TestImportExportUuidFields(unittest.TestCase):
|
|||||||
class TestDALDictImportExport(unittest.TestCase):
|
class TestDALDictImportExport(unittest.TestCase):
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
db = DAL('sqlite:memory:')
|
db = DAL(DEFAULT_URI, check_reserved=['all'])
|
||||||
db.define_table('person', Field('name', default="Michael"),Field('uuid'))
|
db.define_table('person', Field('name', default="Michael"),Field('uuid'))
|
||||||
db.define_table('pet',Field('friend',db.person),Field('name'))
|
db.define_table('pet',Field('friend',db.person),Field('name'))
|
||||||
dbdict = db.as_dict(flat=True, sanitize=False)
|
dbdict = db.as_dict(flat=True, sanitize=False)
|
||||||
@@ -635,77 +646,88 @@ class TestDALDictImportExport(unittest.TestCase):
|
|||||||
assert dbdict["items"]["person"]["items"]["name"]["default"] == db.person.name.default
|
assert dbdict["items"]["person"]["items"]["name"]["default"] == db.person.name.default
|
||||||
assert dbdict
|
assert dbdict
|
||||||
|
|
||||||
db2 = DAL(dbdict)
|
db2 = DAL(dbdict, check_reserved=['all'])
|
||||||
assert len(db.tables) == len(db2.tables)
|
assert len(db.tables) == len(db2.tables)
|
||||||
assert hasattr(db2, "pet") and isinstance(db2.pet, Table)
|
assert hasattr(db2, "pet") and isinstance(db2.pet, Table)
|
||||||
assert hasattr(db2.pet, "friend") and isinstance(db2.pet.friend, Field)
|
assert hasattr(db2.pet, "friend") and isinstance(db2.pet.friend, Field)
|
||||||
|
db.pet.drop()
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
db2.commit()
|
||||||
|
|
||||||
have_serializers = True
|
have_serializers = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import serializers
|
import serializers
|
||||||
dbjson = db.as_json(sanitize=False)
|
dbjson = db.as_json(sanitize=False)
|
||||||
assert isinstance(dbjson, basestring) and len(dbjson) > 0
|
assert isinstance(dbjson, basestring) and len(dbjson) > 0
|
||||||
db3 = DAL(serializers.loads_json(dbjson))
|
|
||||||
|
unicode_keys = True
|
||||||
|
if sys.version < "2.6.5":
|
||||||
|
unicode_keys = False
|
||||||
|
db3 = DAL(serializers.loads_json(dbjson,
|
||||||
|
unicode_keys=unicode_keys))
|
||||||
assert hasattr(db3, "person") and hasattr(db3.person, "uuid") and\
|
assert hasattr(db3, "person") and hasattr(db3.person, "uuid") and\
|
||||||
db3.person.uuid.type == db.person.uuid.type
|
db3.person.uuid.type == db.person.uuid.type
|
||||||
db3.pet.drop()
|
|
||||||
db3.person.drop()
|
db3.person.drop()
|
||||||
db3.commit()
|
db3.commit()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
mpfc = "Monty Python's Flying Circus"
|
mpfc = "Monty Python's Flying Circus"
|
||||||
dbdict4 = {"uri": 'sqlite:memory:',
|
dbdict4 = {"uri": DEFAULT_URI,
|
||||||
"items":{"staff":{"items": {"name":
|
"items":{"staff":{"items": {"name":
|
||||||
{"default":"Michael"},
|
{"default":"Michael"},
|
||||||
"food":
|
"food":
|
||||||
{"default":"Spam"},
|
{"default":"Spam"},
|
||||||
"show":
|
"tvshow":
|
||||||
{"type": "reference show"}
|
{"type": "reference tvshow"}
|
||||||
}},
|
}},
|
||||||
"show":{"items": {"name":
|
"tvshow":{"items": {"name":
|
||||||
{"default":mpfc},
|
{"default":mpfc},
|
||||||
"rating":
|
"rating":
|
||||||
{"type":"double"}}}}}
|
{"type":"double"}}}}}
|
||||||
db4 = DAL(dbdict4)
|
db4 = DAL(dbdict4, check_reserved=['all'])
|
||||||
assert "staff" in db4.tables
|
assert "staff" in db4.tables
|
||||||
assert "name" in db4.staff
|
assert "name" in db4.staff
|
||||||
assert db4.show.rating.type == "double"
|
assert db4.tvshow.rating.type == "double"
|
||||||
assert (db4.show.insert(), db4.show.insert(name="Loriot"),
|
assert (db4.tvshow.insert(), db4.tvshow.insert(name="Loriot"),
|
||||||
db4.show.insert(name="Il Mattatore")) == (1, 2, 3)
|
db4.tvshow.insert(name="Il Mattatore")) == (1, 2, 3)
|
||||||
assert db4(db4.show).select().first().id == 1
|
assert db4(db4.tvshow).select().first().id == 1
|
||||||
assert db4(db4.show).select().first().name == mpfc
|
assert db4(db4.tvshow).select().first().name == mpfc
|
||||||
|
|
||||||
dbdict5 = {"uri": 'sqlite:memory:'}
|
db4.staff.drop()
|
||||||
db5 = DAL(dbdict5)
|
db4.tvshow.drop()
|
||||||
|
db4.commit()
|
||||||
|
|
||||||
|
dbdict5 = {"uri": DEFAULT_URI}
|
||||||
|
db5 = DAL(dbdict5, check_reserved=['all'])
|
||||||
assert db5.tables in ([], None)
|
assert db5.tables in ([], None)
|
||||||
assert not (str(db5) in ("", None))
|
assert not (str(db5) in ("", None))
|
||||||
|
|
||||||
dbdict6 = {"uri": 'sqlite:memory:',
|
dbdict6 = {"uri": DEFAULT_URI,
|
||||||
"items":{"staff":{},
|
"items":{"staff":{},
|
||||||
"show":{"items": {"name": {},
|
"tvshow":{"items": {"name": {},
|
||||||
"rating":
|
"rating":
|
||||||
{"type":"double"}}}}}
|
{"type":"double"}
|
||||||
db6 = DAL(dbdict6)
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db6 = DAL(dbdict6, check_reserved=['all'])
|
||||||
|
|
||||||
assert len(db6["staff"].fields) == 1
|
assert len(db6["staff"].fields) == 1
|
||||||
assert "name" in db6["show"].fields
|
assert "name" in db6["tvshow"].fields
|
||||||
|
|
||||||
assert db6.staff.insert() is not None
|
assert db6.staff.insert() is not None
|
||||||
assert db6(db6.staff).select().first().id == 1
|
assert db6(db6.staff).select().first().id == 1
|
||||||
|
|
||||||
|
|
||||||
db6.staff.drop()
|
db6.staff.drop()
|
||||||
db6.show.drop()
|
db6.tvshow.drop()
|
||||||
db6.commit()
|
db6.commit()
|
||||||
db4.staff.drop()
|
|
||||||
db4.show.drop()
|
|
||||||
db4.commit()
|
|
||||||
db2.pet.drop()
|
|
||||||
db2.person.drop()
|
|
||||||
db2.commit()
|
|
||||||
db.pet.drop()
|
|
||||||
db.person.drop()
|
|
||||||
db.commit()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
+57
-30
@@ -4475,6 +4475,8 @@ class Service(object):
|
|||||||
return return_response(id, s)
|
return return_response(id, s)
|
||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
|
except HTTP, e:
|
||||||
|
raise e
|
||||||
except Service.JsonRpcException, e:
|
except Service.JsonRpcException, e:
|
||||||
return return_error(id, e.code, e.info)
|
return return_error(id, e.code, e.info)
|
||||||
except BaseException:
|
except BaseException:
|
||||||
@@ -4897,7 +4899,7 @@ class Wiki(object):
|
|||||||
everybody = 'everybody'
|
everybody = 'everybody'
|
||||||
rows_page = 25
|
rows_page = 25
|
||||||
def markmin_base(self,body):
|
def markmin_base(self,body):
|
||||||
return MARKMIN(body, extra=self.extra,
|
return MARKMIN(body, extra=self.settings.extra,
|
||||||
url=True, environment=self.env,
|
url=True, environment=self.env,
|
||||||
autolinks=lambda link: expand_one(link, {})).xml()
|
autolinks=lambda link: expand_one(link, {})).xml()
|
||||||
|
|
||||||
@@ -4931,29 +4933,43 @@ class Wiki(object):
|
|||||||
controller, function, args = items[0], items[1], items[2:]
|
controller, function, args = items[0], items[1], items[2:]
|
||||||
return LOAD(controller, function, args=args, ajax=True).xml()
|
return LOAD(controller, function, args=args, ajax=True).xml()
|
||||||
|
|
||||||
|
def get_render(self):
|
||||||
|
if isinstance(self.settings.render, basestring):
|
||||||
|
r = getattr(self, "%s_render" % self.settings.render)
|
||||||
|
elif callable(self.settings.render):
|
||||||
|
r = self.settings.render
|
||||||
|
else:
|
||||||
|
raise ValueError("Invalid render type %s" % type(render))
|
||||||
|
return r
|
||||||
|
|
||||||
def __init__(self, auth, env=None, render='markmin',
|
def __init__(self, auth, env=None, render='markmin',
|
||||||
manage_permissions=False, force_prefix='',
|
manage_permissions=False, force_prefix='',
|
||||||
restrict_search=False, extra=None,
|
restrict_search=False, extra=None,
|
||||||
menu_groups=None, templates=None):
|
menu_groups=None, templates=None):
|
||||||
|
|
||||||
|
settings = self.settings = Settings()
|
||||||
|
|
||||||
|
# render: "markmin", "html", ..., <function>
|
||||||
|
settings.render = render
|
||||||
|
perms = settings.manage_permissions = manage_permissions
|
||||||
|
|
||||||
|
settings.force_prefix = force_prefix
|
||||||
|
settings.restrict_search = restrict_search
|
||||||
|
settings.extra = extra or {}
|
||||||
|
settings.menu_groups = menu_groups
|
||||||
|
settings.templates = templates
|
||||||
|
|
||||||
db = auth.db
|
db = auth.db
|
||||||
self.env = env or {}
|
self.env = env or {}
|
||||||
self.env['component'] = Wiki.component
|
self.env['component'] = Wiki.component
|
||||||
if render == 'markmin':
|
|
||||||
render = self.markmin_render
|
|
||||||
elif render == 'html':
|
|
||||||
render = self.html_render
|
|
||||||
self.render = render
|
|
||||||
self.auth = auth
|
self.auth = auth
|
||||||
self.menu_groups = menu_groups
|
|
||||||
if self.auth.user:
|
if self.auth.user:
|
||||||
self.force_prefix = force_prefix % self.auth.user
|
self.settings.force_prefix = force_prefix % self.auth.user
|
||||||
else:
|
else:
|
||||||
self.force_prefix = force_prefix
|
self.settings.force_prefix = force_prefix
|
||||||
|
|
||||||
self.host = current.request.env.http_host
|
self.host = current.request.env.http_host
|
||||||
perms = self.manage_permissions = manage_permissions
|
|
||||||
self.restrict_search = restrict_search
|
|
||||||
self.extra = extra or {}
|
|
||||||
self.templates = templates
|
|
||||||
|
|
||||||
table_definitions = [
|
table_definitions = [
|
||||||
('wiki_page', {
|
('wiki_page', {
|
||||||
@@ -4973,7 +4989,8 @@ class Wiki(object):
|
|||||||
writable=perms, readable=perms,
|
writable=perms, readable=perms,
|
||||||
default=[Wiki.everybody]),
|
default=[Wiki.everybody]),
|
||||||
Field('changelog'),
|
Field('changelog'),
|
||||||
Field('html', 'text', compute=render,
|
Field('html', 'text',
|
||||||
|
compute=self.get_render(),
|
||||||
readable=False, writable=False),
|
readable=False, writable=False),
|
||||||
auth.signature],
|
auth.signature],
|
||||||
'vars':{'format':'%(title)s'}}),
|
'vars':{'format':'%(title)s'}}),
|
||||||
@@ -5006,8 +5023,9 @@ class Wiki(object):
|
|||||||
args += value['args']
|
args += value['args']
|
||||||
db.define_table(key, *args, **value['vars'])
|
db.define_table(key, *args, **value['vars'])
|
||||||
|
|
||||||
if self.templates is None and not self.manage_permissions:
|
if self.settings.templates is None and not \
|
||||||
self.templates = db.wiki_page.tags.contains('template')&\
|
self.settings.manage_permissions:
|
||||||
|
self.settings.templates = db.wiki_page.tags.contains('template')&\
|
||||||
db.wiki_page.can_read.contains('everybody')
|
db.wiki_page.can_read.contains('everybody')
|
||||||
|
|
||||||
def update_tags_insert(page, id, db=db):
|
def update_tags_insert(page, id, db=db):
|
||||||
@@ -5031,13 +5049,17 @@ class Wiki(object):
|
|||||||
gid = group.id if group else db.auth_group.insert(
|
gid = group.id if group else db.auth_group.insert(
|
||||||
role='wiki_editor')
|
role='wiki_editor')
|
||||||
auth.add_membership(gid)
|
auth.add_membership(gid)
|
||||||
|
|
||||||
|
settings.lock_keys = True
|
||||||
|
|
||||||
# WIKI ACCESS POLICY
|
# WIKI ACCESS POLICY
|
||||||
|
|
||||||
def not_authorized(self, page=None):
|
def not_authorized(self, page=None):
|
||||||
raise HTTP(401)
|
raise HTTP(401)
|
||||||
|
|
||||||
def can_read(self, page):
|
def can_read(self, page):
|
||||||
if 'everybody' in page.can_read or not self.manage_permissions:
|
if 'everybody' in page.can_read or not \
|
||||||
|
self.settings.manage_permissions:
|
||||||
return True
|
return True
|
||||||
elif self.auth.user:
|
elif self.auth.user:
|
||||||
groups = self.auth.user_groups.values()
|
groups = self.auth.user_groups.values()
|
||||||
@@ -5067,11 +5089,11 @@ class Wiki(object):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def can_see_menu(self):
|
def can_see_menu(self):
|
||||||
if self.menu_groups is None:
|
if self.settings.menu_groups is None:
|
||||||
return True
|
return True
|
||||||
if self.auth.user:
|
if self.auth.user:
|
||||||
groups = self.auth.user_groups.values()
|
groups = self.auth.user_groups.values()
|
||||||
if any(t in self.menu_groups for t in groups):
|
if any(t in self.settings.menu_groups for t in groups):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -5108,7 +5130,7 @@ class Wiki(object):
|
|||||||
elif zero == '_cloud':
|
elif zero == '_cloud':
|
||||||
return self.cloud()
|
return self.cloud()
|
||||||
elif zero == '_preview':
|
elif zero == '_preview':
|
||||||
return self.preview(self.render)
|
return self.preview(self.get_render())
|
||||||
|
|
||||||
def first_paragraph(self, page):
|
def first_paragraph(self, page):
|
||||||
if not self.can_read(page):
|
if not self.can_read(page):
|
||||||
@@ -5176,9 +5198,9 @@ class Wiki(object):
|
|||||||
title_guess = ' '.join(c.capitalize() for c in slug.split('-'))
|
title_guess = ' '.join(c.capitalize() for c in slug.split('-'))
|
||||||
if not page:
|
if not page:
|
||||||
if not (self.can_manage() or
|
if not (self.can_manage() or
|
||||||
slug.startswith(self.force_prefix)):
|
slug.startswith(self.settings.force_prefix)):
|
||||||
current.session.flash = 'slug must have "%s" prefix' \
|
current.session.flash = 'slug must have "%s" prefix' \
|
||||||
% self.force_prefix
|
% self.settings.force_prefix
|
||||||
redirect(URL(args=('_create')))
|
redirect(URL(args=('_create')))
|
||||||
db.wiki_page.can_read.default = [Wiki.everybody]
|
db.wiki_page.can_read.default = [Wiki.everybody]
|
||||||
db.wiki_page.can_edit.default = [auth.user_group_role()]
|
db.wiki_page.can_edit.default = [auth.user_group_role()]
|
||||||
@@ -5234,7 +5256,10 @@ class Wiki(object):
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
""" % dict(url=URL(args=('_preview')), urlmedia=URL(extension='load',args=('_editmedia'),vars=dict(embedded=1)))
|
""" % dict(url=URL(args=('_preview', slug)),
|
||||||
|
urlmedia=URL(extension='load',
|
||||||
|
args=('_editmedia',slug),
|
||||||
|
vars=dict(embedded=1)))
|
||||||
return dict(content=TAG[''](form, SCRIPT(script)))
|
return dict(content=TAG[''](form, SCRIPT(script)))
|
||||||
|
|
||||||
def editmedia(self, slug):
|
def editmedia(self, slug):
|
||||||
@@ -5280,14 +5305,15 @@ class Wiki(object):
|
|||||||
options=[OPTION(row.slug,_value=row.id) for row in slugs]
|
options=[OPTION(row.slug,_value=row.id) for row in slugs]
|
||||||
options.insert(0, OPTION('',_value=''))
|
options.insert(0, OPTION('',_value=''))
|
||||||
fields = [Field("slug", default=current.request.args(1) or
|
fields = [Field("slug", default=current.request.args(1) or
|
||||||
self.force_prefix,
|
self.settings.force_prefix,
|
||||||
requires=(IS_SLUG(), IS_NOT_IN_DB(db,db.wiki_page.slug))),]
|
requires=(IS_SLUG(), IS_NOT_IN_DB(db,db.wiki_page.slug))),]
|
||||||
if self.templates:
|
if self.settings.templates:
|
||||||
fields.append(
|
fields.append(
|
||||||
Field("from_template", "reference wiki_page",
|
Field("from_template", "reference wiki_page",
|
||||||
requires=IS_EMPTY_OR(IS_IN_DB(db(self.templates),
|
requires=IS_EMPTY_OR(
|
||||||
db.wiki_page._id,
|
IS_IN_DB(db(self.settings.templates),
|
||||||
'%(slug)s')),
|
db.wiki_page._id,
|
||||||
|
'%(slug)s')),
|
||||||
comment=current.T(
|
comment=current.T(
|
||||||
"Choose Template or empty for new Page")))
|
"Choose Template or empty for new Page")))
|
||||||
form = SQLFORM.factory(*fields, **dict(_class="well span6"))
|
form = SQLFORM.factory(*fields, **dict(_class="well span6"))
|
||||||
@@ -5329,7 +5355,7 @@ class Wiki(object):
|
|||||||
request, db = current.request, self.auth.db
|
request, db = current.request, self.auth.db
|
||||||
media = db.wiki_media(id)
|
media = db.wiki_media(id)
|
||||||
if media:
|
if media:
|
||||||
if self.manage_permissions:
|
if self.settings.manage_permissions:
|
||||||
page = db.wiki_page(media.wiki_page)
|
page = db.wiki_page(media.wiki_page)
|
||||||
if not self.can_read(page):
|
if not self.can_read(page):
|
||||||
return self.not_authorized(page)
|
return self.not_authorized(page)
|
||||||
@@ -5428,7 +5454,7 @@ class Wiki(object):
|
|||||||
query = (db.wiki_page.id == db.wiki_tag.wiki_page) &\
|
query = (db.wiki_page.id == db.wiki_tag.wiki_page) &\
|
||||||
(db.wiki_tag.name.belongs(tags))
|
(db.wiki_tag.name.belongs(tags))
|
||||||
query = query | db.wiki_page.title.contains(request.vars.q)
|
query = query | db.wiki_page.title.contains(request.vars.q)
|
||||||
if self.restrict_search and not self.manage():
|
if self.settings.restrict_search and not self.manage():
|
||||||
query = query & (db.wiki_page.created_by == self.auth.user_id)
|
query = query & (db.wiki_page.created_by == self.auth.user_id)
|
||||||
pages = db(query).select(count,
|
pages = db(query).select(count,
|
||||||
*fields, **dict(orderby=orderby or ~count,
|
*fields, **dict(orderby=orderby or ~count,
|
||||||
@@ -5489,6 +5515,7 @@ class Wiki(object):
|
|||||||
request = current.request
|
request = current.request
|
||||||
return render(request.post_vars)
|
return render(request.post_vars)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import doctest
|
import doctest
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
|
|||||||
+34
-12
@@ -2219,22 +2219,29 @@ class IS_DATE(Validator):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, format='%Y-%m-%d',
|
def __init__(self, format='%Y-%m-%d',
|
||||||
error_message='enter date as %(format)s'):
|
error_message='enter date as %(format)s',
|
||||||
|
timezone = None):
|
||||||
self.format = translate(format)
|
self.format = translate(format)
|
||||||
self.error_message = str(error_message)
|
self.error_message = str(error_message)
|
||||||
|
self.timezone = timezone
|
||||||
self.extremes = {}
|
self.extremes = {}
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
|
ovalue = value
|
||||||
if isinstance(value, datetime.date):
|
if isinstance(value, datetime.date):
|
||||||
|
if self.timezone is not None:
|
||||||
|
value = value - datetime.timedelta(seconds=self.timezone*3600)
|
||||||
return (value, None)
|
return (value, None)
|
||||||
try:
|
try:
|
||||||
(y, m, d, hh, mm, ss, t0, t1, t2) = \
|
(y, m, d, hh, mm, ss, t0, t1, t2) = \
|
||||||
time.strptime(value, str(self.format))
|
time.strptime(value, str(self.format))
|
||||||
value = datetime.date(y, m, d)
|
value = datetime.date(y, m, d)
|
||||||
|
if self.timezone is not None:
|
||||||
|
value = value - datetime.timedelta(seconds=self.timezone*3600)
|
||||||
return (value, None)
|
return (value, None)
|
||||||
except:
|
except:
|
||||||
self.extremes.update(IS_DATETIME.nice(self.format))
|
self.extremes.update(IS_DATETIME.nice(self.format))
|
||||||
return (value, translate(self.error_message) % self.extremes)
|
return (ovalue, translate(self.error_message) % self.extremes)
|
||||||
|
|
||||||
def formatter(self, value):
|
def formatter(self, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
@@ -2247,6 +2254,8 @@ class IS_DATE(Validator):
|
|||||||
if year < 1900:
|
if year < 1900:
|
||||||
year = 2000
|
year = 2000
|
||||||
d = datetime.date(year, value.month, value.day)
|
d = datetime.date(year, value.month, value.day)
|
||||||
|
if self.timezone is not None:
|
||||||
|
d = d + datetime.timedelta(seconds=self.timezone*3600)
|
||||||
return d.strftime(format)
|
return d.strftime(format)
|
||||||
|
|
||||||
|
|
||||||
@@ -2279,22 +2288,27 @@ class IS_DATETIME(Validator):
|
|||||||
return dict(format=format)
|
return dict(format=format)
|
||||||
|
|
||||||
def __init__(self, format='%Y-%m-%d %H:%M:%S',
|
def __init__(self, format='%Y-%m-%d %H:%M:%S',
|
||||||
error_message='enter date and time as %(format)s'):
|
error_message='enter date and time as %(format)s',
|
||||||
|
timezone=None):
|
||||||
self.format = translate(format)
|
self.format = translate(format)
|
||||||
self.error_message = str(error_message)
|
self.error_message = str(error_message)
|
||||||
self.extremes = {}
|
self.extremes = {}
|
||||||
|
self.timezone = timezone
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
|
ovalue = value
|
||||||
if isinstance(value, datetime.datetime):
|
if isinstance(value, datetime.datetime):
|
||||||
return (value, None)
|
return (value, None)
|
||||||
try:
|
try:
|
||||||
(y, m, d, hh, mm, ss, t0, t1, t2) = \
|
(y, m, d, hh, mm, ss, t0, t1, t2) = \
|
||||||
time.strptime(value, str(self.format))
|
time.strptime(value, str(self.format))
|
||||||
value = datetime.datetime(y, m, d, hh, mm, ss)
|
value = datetime.datetime(y, m, d, hh, mm, ss)
|
||||||
|
if self.timezone is not None:
|
||||||
|
value = value - datetime.timedelta(seconds=self.timezone*3600)
|
||||||
return (value, None)
|
return (value, None)
|
||||||
except:
|
except:
|
||||||
self.extremes.update(IS_DATETIME.nice(self.format))
|
self.extremes.update(IS_DATETIME.nice(self.format))
|
||||||
return (value, translate(self.error_message) % self.extremes)
|
return (ovalue, translate(self.error_message) % self.extremes)
|
||||||
|
|
||||||
def formatter(self, value):
|
def formatter(self, value):
|
||||||
if value is None:
|
if value is None:
|
||||||
@@ -2308,6 +2322,8 @@ class IS_DATETIME(Validator):
|
|||||||
year = 2000
|
year = 2000
|
||||||
d = datetime.datetime(year, value.month, value.day,
|
d = datetime.datetime(year, value.month, value.day,
|
||||||
value.hour, value.minute, value.second)
|
value.hour, value.minute, value.second)
|
||||||
|
if self.timezone is not None:
|
||||||
|
d = d + datetime.timedelta(seconds=self.timezone*3600)
|
||||||
return d.strftime(format)
|
return d.strftime(format)
|
||||||
|
|
||||||
|
|
||||||
@@ -2336,7 +2352,8 @@ class IS_DATE_IN_RANGE(IS_DATE):
|
|||||||
minimum=None,
|
minimum=None,
|
||||||
maximum=None,
|
maximum=None,
|
||||||
format='%Y-%m-%d',
|
format='%Y-%m-%d',
|
||||||
error_message=None):
|
error_message=None,
|
||||||
|
timezone=None):
|
||||||
self.minimum = minimum
|
self.minimum = minimum
|
||||||
self.maximum = maximum
|
self.maximum = maximum
|
||||||
if error_message is None:
|
if error_message is None:
|
||||||
@@ -2348,17 +2365,19 @@ class IS_DATE_IN_RANGE(IS_DATE):
|
|||||||
error_message = "enter date in range %(min)s %(max)s"
|
error_message = "enter date in range %(min)s %(max)s"
|
||||||
IS_DATE.__init__(self,
|
IS_DATE.__init__(self,
|
||||||
format=format,
|
format=format,
|
||||||
error_message=error_message)
|
error_message=error_message,
|
||||||
|
timezone=timezone)
|
||||||
self.extremes = dict(min=minimum, max=maximum)
|
self.extremes = dict(min=minimum, max=maximum)
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
|
ovalue = value
|
||||||
(value, msg) = IS_DATE.__call__(self, value)
|
(value, msg) = IS_DATE.__call__(self, value)
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
return (value, msg)
|
return (value, msg)
|
||||||
if self.minimum and self.minimum > value:
|
if self.minimum and self.minimum > value:
|
||||||
return (value, translate(self.error_message) % self.extremes)
|
return (ovalue, translate(self.error_message) % self.extremes)
|
||||||
if self.maximum and value > self.maximum:
|
if self.maximum and value > self.maximum:
|
||||||
return (value, translate(self.error_message) % self.extremes)
|
return (ovalue, translate(self.error_message) % self.extremes)
|
||||||
return (value, None)
|
return (value, None)
|
||||||
|
|
||||||
|
|
||||||
@@ -2386,7 +2405,8 @@ class IS_DATETIME_IN_RANGE(IS_DATETIME):
|
|||||||
minimum=None,
|
minimum=None,
|
||||||
maximum=None,
|
maximum=None,
|
||||||
format='%Y-%m-%d %H:%M:%S',
|
format='%Y-%m-%d %H:%M:%S',
|
||||||
error_message=None):
|
error_message=None,
|
||||||
|
timezone=None):
|
||||||
self.minimum = minimum
|
self.minimum = minimum
|
||||||
self.maximum = maximum
|
self.maximum = maximum
|
||||||
if error_message is None:
|
if error_message is None:
|
||||||
@@ -2398,17 +2418,19 @@ class IS_DATETIME_IN_RANGE(IS_DATETIME):
|
|||||||
error_message = "enter date and time in range %(min)s %(max)s"
|
error_message = "enter date and time in range %(min)s %(max)s"
|
||||||
IS_DATETIME.__init__(self,
|
IS_DATETIME.__init__(self,
|
||||||
format=format,
|
format=format,
|
||||||
error_message=error_message)
|
error_message=error_message,
|
||||||
|
timezone=timezone)
|
||||||
self.extremes = dict(min=minimum, max=maximum)
|
self.extremes = dict(min=minimum, max=maximum)
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
|
ovalue = value
|
||||||
(value, msg) = IS_DATETIME.__call__(self, value)
|
(value, msg) = IS_DATETIME.__call__(self, value)
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
return (value, msg)
|
return (value, msg)
|
||||||
if self.minimum and self.minimum > value:
|
if self.minimum and self.minimum > value:
|
||||||
return (value, translate(self.error_message) % self.extremes)
|
return (ovalue, translate(self.error_message) % self.extremes)
|
||||||
if self.maximum and value > self.maximum:
|
if self.maximum and value > self.maximum:
|
||||||
return (value, translate(self.error_message) % self.extremes)
|
return (ovalue, translate(self.error_message) % self.extremes)
|
||||||
return (value, None)
|
return (value, None)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
-17
@@ -1,17 +0,0 @@
|
|||||||
language: python
|
|
||||||
|
|
||||||
python:
|
|
||||||
- '2.5'
|
|
||||||
- '2.6'
|
|
||||||
- '2.7'
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- pip install unittest2
|
|
||||||
- mysql -e 'create database test_pymysql;'
|
|
||||||
- mysql -e 'create database test_pymysql2;'
|
|
||||||
|
|
||||||
script: PYTHONPATH=. unit2 -v gluon.tests
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
irc:
|
|
||||||
channels: "irc.freenode.org#web2py"
|
|
||||||
Reference in New Issue
Block a user