Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58533954dc | ||
|
|
236dc4b943 | ||
|
|
6612fd1cfe | ||
|
|
520950ba74 | ||
|
|
e943aa9c25 | ||
|
|
756aec7206 | ||
|
|
970e2ed35c | ||
|
|
1388c39636 | ||
|
|
6e84737924 | ||
|
|
0ad50630f2 | ||
|
|
f42ee15f5f | ||
|
|
2b0bfba649 | ||
|
|
9f1edf267d | ||
|
|
f3bda9ad02 | ||
|
|
f8afc76263 | ||
|
|
65b4aaf842 | ||
|
|
1b729cfbfc | ||
|
|
1aa5f30091 | ||
|
|
b17174c04c | ||
|
|
ac80adc9b4 | ||
|
|
888fa3dfc8 | ||
|
|
f3d815e84b | ||
|
|
9915fdf093 | ||
|
|
ef8f802df9 | ||
|
|
f7bf1020df | ||
|
|
75b8ceb022 | ||
|
|
b4f3784136 | ||
|
|
f1297bb827 | ||
|
|
435ebeaae4 | ||
|
|
537045082c | ||
|
|
4bea52a7b5 | ||
|
|
33295e516f | ||
|
|
f33ccf3366 | ||
|
|
0784680c90 | ||
|
|
e940228eaf | ||
|
|
50769a627a | ||
|
|
e68ecaa131 | ||
|
|
95e6e8577b | ||
|
|
19c83d4ad6 | ||
|
|
9c92bd1050 | ||
|
|
b3b95ccf5f | ||
|
|
cefa30841b | ||
|
|
15ff8669cb | ||
|
|
a921751e8e |
@@ -32,7 +32,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.10.3-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
echo 'Version 2.10.4-beta+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
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Version 2.10.3-stable+timestamp.2015.04.02.16.28.49
|
Version 2.10.4-stable+timestamp.2015.04.26.09.05.21
|
||||||
|
|||||||
@@ -180,6 +180,11 @@ class Servers:
|
|||||||
s = wsgi.WSGIServer(callable=app, bind="%s:%d" % address)
|
s = wsgi.WSGIServer(callable=app, bind="%s:%d" % address)
|
||||||
s.start()
|
s.start()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def waitress(app, address, **options):
|
||||||
|
from waitress import serve
|
||||||
|
serve(app, host=address[0], port=address[1], _quiet=True)
|
||||||
|
|
||||||
|
|
||||||
def mongrel2_handler(application, conn, debug=False):
|
def mongrel2_handler(application, conn, debug=False):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-pane active" id="alltables">
|
<div class="tab-pane active" id="alltables">
|
||||||
<table>
|
<table class="table">
|
||||||
{{for db in sorted(databases):}}
|
{{for db in sorted(databases):}}
|
||||||
{{for table in databases[db].tables:}}
|
{{for table in databases[db].tables:}}
|
||||||
{{qry='%s.%s.id>0'%(db,table)}}
|
{{qry='%s.%s.id>0'%(db,table)}}
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
{{=A("%s.%s" % (db,table),_href=URL('select',args=[db],vars=dict(query=qry)))}}
|
{{=A("%s.%s" % (db,table),_href=URL('select',args=[db],vars=dict(query=qry)))}}
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn")}}
|
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn btn-default")}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
</pre>
|
</pre>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
{{if table:}}
|
{{if table:}}
|
||||||
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/>
|
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn btn-default")}}<br/><br/>
|
||||||
<h3>{{=T("Rows in Table")}}</h3><br/>
|
<h3>{{=T("Rows in Table")}}</h3><br/>
|
||||||
{{else:}}
|
{{else:}}
|
||||||
<h3>{{=T("Rows selected")}}</h3><br/>
|
<h3>{{=T("Rows selected")}}</h3><br/>
|
||||||
@@ -72,8 +72,8 @@
|
|||||||
{{=T('"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN')}}</p>
|
{{=T('"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN')}}</p>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
<h4>{{=T("%s selected", nrows)}}</h4>
|
<h4>{{=T("%s selected", nrows)}}</h4>
|
||||||
{{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn")}}{{pass}}
|
{{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn btn-default")}}{{pass}}
|
||||||
{{if stop<nrows:}}{{=A(T('next %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start+step)),_class="btn")}}{{pass}}
|
{{if stop<nrows:}}{{=A(T('next %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start+step)),_class="btn btn-default")}}{{pass}}
|
||||||
{{if rows:}}
|
{{if rows:}}
|
||||||
<div style="overflow:auto; width:80%;">
|
<div style="overflow:auto; width:80%;">
|
||||||
{{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}}
|
{{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}}
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<br/><br/><h3>{{=T("Import/Export")}}</h3><br/>
|
<br/><br/><h3>{{=T("Import/Export")}}</h3><br/>
|
||||||
<a href="{{=URL('csv',args=request.args[0],vars=dict(query=query))}}" class="btn">{{=T("export as csv file")}}</a>
|
<a href="{{=URL('csv',args=request.args[0],vars=dict(query=query))}}" class="btn btn-default">{{=T("export as csv file")}}</a>
|
||||||
{{=formcsv or ''}}
|
{{=formcsv or ''}}
|
||||||
|
|
||||||
{{elif request.function=='insert':}}
|
{{elif request.function=='insert':}}
|
||||||
|
|||||||
@@ -33,6 +33,9 @@
|
|||||||
<li><a target="_blank" href="https://loadinfo-net.appspot.com">LoadInfo</a> (Bulgaria)</li>
|
<li><a target="_blank" href="https://loadinfo-net.appspot.com">LoadInfo</a> (Bulgaria)</li>
|
||||||
<li><a target="_blank" href="http://www.appliedobjects.com">Applied Objects</a> (New Zealand)</li>
|
<li><a target="_blank" href="http://www.appliedobjects.com">Applied Objects</a> (New Zealand)</li>
|
||||||
<li><a target="_blank" href="http://www.sistemasagiles.com.ar/">Sistemas Ágiles</a> ("Agile Systems") (Argentina)</li>
|
<li><a target="_blank" href="http://www.sistemasagiles.com.ar/">Sistemas Ágiles</a> ("Agile Systems") (Argentina)</li>
|
||||||
|
<li><a target="_blank" href="http://www.definescope.com/en/services/consulting/">DefineScope</a> (Portugal)</li>
|
||||||
|
<li><a target="_blank" href="http://10Biosystems.com">10BioSystems</a></li>
|
||||||
|
<li><a target="_blank" href="http://www.dutveul.nl">Dutveul</a> (Netherlands)</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ auth.define_tables(username=False, signature=False)
|
|||||||
|
|
||||||
## configure email
|
## configure email
|
||||||
mail = auth.settings.mailer
|
mail = auth.settings.mailer
|
||||||
mail.settings.server = 'logging' if request.is_local else myconf.take('smtp.sender')
|
mail.settings.server = 'logging' if request.is_local else myconf.take('smtp.server')
|
||||||
mail.settings.sender = myconf.take('smtp.sender')
|
mail.settings.sender = myconf.take('smtp.sender')
|
||||||
mail.settings.login = myconf.take('smtp.login')
|
mail.settings.login = myconf.take('smtp.login')
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!-- app configuration for web2py on IIS -->
|
||||||
|
<configuration>
|
||||||
|
<appSettings>
|
||||||
|
<add key="WSGI_HANDLER" value="gluon.main.wsgibase" />
|
||||||
|
<add key="WSGI_RESTART_FILE_REGEX" value=".*((routes\.py)|(\.config))$" />
|
||||||
|
</appSettings>
|
||||||
|
<system.webServer>
|
||||||
|
<rewrite>
|
||||||
|
<rules>
|
||||||
|
<clear />
|
||||||
|
<rule name="static" enabled="true" stopProcessing="true">
|
||||||
|
<match url="^(\w+)/static(?:/_[\d]+\.[\d]+\.[\d]+)?/(.*)$" />
|
||||||
|
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
|
||||||
|
<action type="Rewrite" url="applications/{R:1}/static/{R:2}" logRewrittenUrl="false" />
|
||||||
|
</rule>
|
||||||
|
<rule name="web2py_app" enabled="true" stopProcessing="true">
|
||||||
|
<match url="(.*)" ignoreCase="false" />
|
||||||
|
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
|
||||||
|
<action type="Rewrite" url="handler.web2py/{R:1}" appendQueryString="true" />
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
<outboundRules>
|
||||||
|
<rule name="static_version_cache_control" preCondition="static_version">
|
||||||
|
<match serverVariable="RESPONSE_Cache-Control" pattern=".*" />
|
||||||
|
<action type="Rewrite" value="max-age=315360000" />
|
||||||
|
<conditions>
|
||||||
|
</conditions>
|
||||||
|
</rule>
|
||||||
|
<rule name="static_version_Expires" preCondition="static_version">
|
||||||
|
<match serverVariable="RESPONSE_Expires" pattern=".*" />
|
||||||
|
<action type="Rewrite" value="Thu, 31 Dec 2037 23:59:59 GMT" />
|
||||||
|
</rule>
|
||||||
|
<preConditions>
|
||||||
|
<preCondition name="static_version">
|
||||||
|
<add input="{REQUEST_URI}" pattern="(\w+)/static(?:/_[\d]+\.[\d]+\.[\d]+)?/(.*)$" />
|
||||||
|
</preCondition>
|
||||||
|
</preConditions>
|
||||||
|
</outboundRules>
|
||||||
|
</rewrite>
|
||||||
|
<handlers>
|
||||||
|
<!-- replace SCRIPT_PROCESSOR with the configured handler for python -->
|
||||||
|
<add name="Python_via_FastCGI" path="handler.web2py" verb="*" modules="FastCgiModule" scriptProcessor="SCRIPT_PROCESSOR" resourceType="Unspecified" requireAccess="Script" />
|
||||||
|
</handlers>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
||||||
+2
-2
@@ -99,7 +99,7 @@ class CacheAbstract(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
cache_stats_name = 'web2py_cache_statistics'
|
cache_stats_name = 'web2py_cache_statistics'
|
||||||
max_ram_utilization = 90 # percent
|
max_ram_utilization = None # percent
|
||||||
|
|
||||||
def __init__(self, request=None):
|
def __init__(self, request=None):
|
||||||
"""Initializes the object
|
"""Initializes the object
|
||||||
@@ -353,7 +353,7 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
raise KeyError
|
raise KeyError
|
||||||
|
|
||||||
self.wait_portalock(val_file)
|
self.wait_portalock(val_file)
|
||||||
value = pickle.load(recfile.open(key, 'rb', path=self.folder))
|
value = pickle.load(val_file)
|
||||||
val_file.close()
|
val_file.close()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|||||||
@@ -521,9 +521,19 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
logging.error(
|
logging.error(
|
||||||
'There is no username or email for %s!' % username)
|
'There is no username or email for %s!' % username)
|
||||||
raise
|
raise
|
||||||
db_group_search = db((db.auth_membership.user_id == db_user_id) &
|
# if old pydal version, assume this is a relational database which can do joins
|
||||||
(db.auth_user.id == db.auth_membership.user_id) &
|
db_can_join = db.can_join() if hasattr(db, 'can_join') else True
|
||||||
(db.auth_group.id == db.auth_membership.group_id))
|
if db_can_join:
|
||||||
|
db_group_search = db(
|
||||||
|
(db.auth_membership.user_id == db_user_id) &
|
||||||
|
(db.auth_user.id == db.auth_membership.user_id) &
|
||||||
|
(db.auth_group.id == db.auth_membership.group_id))
|
||||||
|
else:
|
||||||
|
# no joins on NoSQL databases, perform two queries
|
||||||
|
db_group_search = db(db.auth_membership.user_id == db_user_id)
|
||||||
|
group_ids = [x.group_id for x in db_group_search.select(
|
||||||
|
db.auth_membership.group_id, distinct=True)]
|
||||||
|
db_group_search = db(db.auth_group.id.belongs(group_ids))
|
||||||
db_groups_of_the_user = list()
|
db_groups_of_the_user = list()
|
||||||
db_group_id = dict()
|
db_group_id = dict()
|
||||||
|
|
||||||
|
|||||||
+439
-421
File diff suppressed because it is too large
Load Diff
+35
-35
@@ -4,7 +4,24 @@ from hashlib import sha1
|
|||||||
|
|
||||||
class Stripe:
|
class Stripe:
|
||||||
"""
|
"""
|
||||||
Usage:
|
Use in WEB2PY (guaranteed PCI compliant)
|
||||||
|
|
||||||
|
def pay():
|
||||||
|
from gluon.contrib.stripe import StripeForm
|
||||||
|
form = StripeForm(
|
||||||
|
pk=STRIPE_PUBLISHABLE_KEY,
|
||||||
|
sk=STRIPE_SECRET_KEY,
|
||||||
|
amount=150, # $1.5 (amount is in cents)
|
||||||
|
description="Nothing").process()
|
||||||
|
if form.accepted:
|
||||||
|
payment_id = form.response['id']
|
||||||
|
redirect(URL('thank_you'))
|
||||||
|
elif form.errors:
|
||||||
|
redirect(URL('pay_error'))
|
||||||
|
return dict(form=form)
|
||||||
|
|
||||||
|
Low level API:
|
||||||
|
|
||||||
key='<api key>'
|
key='<api key>'
|
||||||
d = Stripe(key).charge(
|
d = Stripe(key).charge(
|
||||||
amount=100, # 1 dollar!!!!
|
amount=100, # 1 dollar!!!!
|
||||||
@@ -22,22 +39,6 @@ class Stripe:
|
|||||||
{u'fee': 0, u'description': u'test charge', u'created': 1321242072, u'refunded': False, u'livemode': False, u'object': u'charge', u'currency': u'usd', u'amount': 100, u'paid': True, u'id': u'ch_sdjasgfga83asf', u'card': {u'exp_month': 5, u'country': u'US', u'object': u'card', u'last4': u'4242', u'exp_year': 2012, u'type': u'Visa'}}
|
{u'fee': 0, u'description': u'test charge', u'created': 1321242072, u'refunded': False, u'livemode': False, u'object': u'charge', u'currency': u'usd', u'amount': 100, u'paid': True, u'id': u'ch_sdjasgfga83asf', u'card': {u'exp_month': 5, u'country': u'US', u'object': u'card', u'last4': u'4242', u'exp_year': 2012, u'type': u'Visa'}}
|
||||||
if paid is True than transaction was processed
|
if paid is True than transaction was processed
|
||||||
|
|
||||||
Use in WEB2PY (guaranteed PCI compliant)
|
|
||||||
|
|
||||||
def pay():
|
|
||||||
from gluon.contrib.stripe import StripeForm
|
|
||||||
form = StripeForm(
|
|
||||||
pk=STRIPE_PUBLISHABLE_KEY,
|
|
||||||
sk=STRIPE_SECRET_KEY,
|
|
||||||
amount=150, # $1.5 (amount is in cents)
|
|
||||||
description="Nothing").process()
|
|
||||||
if form.accepted:
|
|
||||||
payment_id = form.response['id']
|
|
||||||
redirect(URL('thank_you'))
|
|
||||||
elif form.errors:
|
|
||||||
redirect(URL('pay_error'))
|
|
||||||
return dict(form=form)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
URL_CHARGE = 'https://%s:@api.stripe.com/v1/charges'
|
URL_CHARGE = 'https://%s:@api.stripe.com/v1/charges'
|
||||||
@@ -188,37 +189,36 @@ jQuery(function(){
|
|||||||
<h3>Payment Amount: {{=currency_symbol}} {{="%.2f" % (0.01*amount)}}</h3>
|
<h3>Payment Amount: {{=currency_symbol}} {{="%.2f" % (0.01*amount)}}</h3>
|
||||||
<form action="" method="POST" id="payment-form" class="form-horizontal">
|
<form action="" method="POST" id="payment-form" class="form-horizontal">
|
||||||
|
|
||||||
<div class="form-row control-group">
|
<div class="form-row form-group">
|
||||||
<label class="control-label">Card Number</label>
|
<label class="col-sm-2 control-label">Card Number</label>
|
||||||
<div class="controls">
|
<div class="controls col-sm-10">
|
||||||
<input type="text" size="20" data-stripe="number"
|
<input type="text" size="20" data-stripe="number"
|
||||||
placeholder="4242424242424242"/>
|
placeholder="4242424242424242" class="form-control"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row control-group">
|
<div class="form-row form-group">
|
||||||
<label class="control-label">CVC</label>
|
<label class="col-sm-2 control-label">CVC</label>
|
||||||
<div class="controls">
|
<div class="controls col-sm-10">
|
||||||
<input type="text" size="4" style="width:80px" data-stripe="cvc"
|
<input type="text" size="4" style="width:80px" data-stripe="cvc"
|
||||||
placeholder="XXX"/>
|
placeholder="XXX" class="form-control"/>
|
||||||
<a href="http://en.wikipedia.org/wiki/Card_Verification_Code" target="_blank">What is this?</a>
|
<a href="http://en.wikipedia.org/wiki/Card_Verification_Code" target="_blank">What is this?</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row control-group">
|
<div class="form-row form-group">
|
||||||
<label class="control-label">Expiration</label>
|
<label class="col-sm-2 control-label">Expiration</label>
|
||||||
<div class="controls">
|
<div class="controls col-sm-10">
|
||||||
<input type="text" size="2" style="width:40px" data-stripe="exp-month"
|
<input type="text" size="2" style="width:40px; display:inline-block"
|
||||||
placeholder="MM"/>
|
data-stripe="exp-month" placeholder="MM" class="form-control"/>
|
||||||
/
|
/
|
||||||
<input type="text" size="4" style="width:80px" data-stripe="exp-year"
|
<input type="text" size="4" style="width:80px; display:inline-block"
|
||||||
placeholder="YYYY"/>
|
data-stripe="exp-year" placeholder="YYYY" class="form-control"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-row form-group">
|
||||||
<div class="control-group">
|
<div class="controls col-sm-offset-2 col-sm-10">
|
||||||
<div class="controls">
|
|
||||||
<button type="submit" class="btn btn-primary">Submit Payment</button>
|
<button type="submit" class="btn btn-primary">Submit Payment</button>
|
||||||
<div class="payment-errors error hidden"></div>
|
<div class="payment-errors error hidden"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+4
-4
@@ -7,14 +7,14 @@
|
|||||||
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||||
|
|
||||||
Takes care of adapting pyDAL to web2py's needs
|
Takes care of adapting pyDAL to web2py's needs
|
||||||
--------------------------------------------
|
-----------------------------------------------
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pydal import DAL as DAL
|
from pydal import DAL as DAL
|
||||||
from pydal import Field
|
from pydal import Field
|
||||||
from pydal.objects import Row, Rows, Table, Query, Expression
|
from pydal.objects import Row, Rows, Table, Query, Expression
|
||||||
from pydal import SQLCustomType, geoPoint, geoLine, geoPolygon
|
from pydal import SQLCustomType, geoPoint, geoLine, geoPolygon
|
||||||
import copy_reg as copyreg
|
|
||||||
|
|
||||||
def _default_validators(db, field):
|
def _default_validators(db, field):
|
||||||
"""
|
"""
|
||||||
@@ -81,12 +81,12 @@ def _default_validators(db, field):
|
|||||||
requires[0] = validators.IS_EMPTY_OR(requires[0])
|
requires[0] = validators.IS_EMPTY_OR(requires[0])
|
||||||
return requires
|
return requires
|
||||||
|
|
||||||
from gluon import serializers as w2p_serializers
|
from gluon.serializers import custom_json, xml
|
||||||
from gluon.utils import web2py_uuid
|
from gluon.utils import web2py_uuid
|
||||||
from gluon import sqlhtml
|
from gluon import sqlhtml
|
||||||
|
|
||||||
|
|
||||||
DAL.serializers = w2p_serializers
|
DAL.serializers = {'json': custom_json, 'xml': xml}
|
||||||
DAL.validators_method = _default_validators
|
DAL.validators_method = _default_validators
|
||||||
DAL.uuid = lambda x: web2py_uuid()
|
DAL.uuid = lambda x: web2py_uuid()
|
||||||
DAL.representers = {
|
DAL.representers = {
|
||||||
|
|||||||
+1
-1
Submodule gluon/packages/dal updated: b08cb1f779...62eb7767db
+15
-3
@@ -58,9 +58,12 @@ def represent(field, value, record):
|
|||||||
f = field.represent
|
f = field.represent
|
||||||
if not callable(f):
|
if not callable(f):
|
||||||
return str(value)
|
return str(value)
|
||||||
n = f.func_code.co_argcount - len(f.func_defaults or [])
|
if hasattr(f,'func_code'):
|
||||||
if getattr(f, 'im_self', None):
|
n = f.func_code.co_argcount - len(f.func_defaults or [])
|
||||||
n -= 1
|
if getattr(f, 'im_self', None):
|
||||||
|
n -= 1
|
||||||
|
else:
|
||||||
|
n = 1
|
||||||
if n == 1:
|
if n == 1:
|
||||||
return f(value)
|
return f(value)
|
||||||
elif n == 2:
|
elif n == 2:
|
||||||
@@ -1205,6 +1208,9 @@ class SQLFORM(FORM):
|
|||||||
elif field.type == 'boolean':
|
elif field.type == 'boolean':
|
||||||
inp = self.widgets.boolean.widget(
|
inp = self.widgets.boolean.widget(
|
||||||
field, default, _disabled=True)
|
field, default, _disabled=True)
|
||||||
|
elif isinstance(field.type, SQLCustomType) and callable(field.type.represent):
|
||||||
|
# SQLCustomType has a represent, use it
|
||||||
|
inp = field.type.represent(default, record)
|
||||||
else:
|
else:
|
||||||
inp = field.formatter(default)
|
inp = field.formatter(default)
|
||||||
if getattr(field, 'show_if', None):
|
if getattr(field, 'show_if', None):
|
||||||
@@ -1246,6 +1252,9 @@ class SQLFORM(FORM):
|
|||||||
dspval = ''
|
dspval = ''
|
||||||
elif field.type == 'blob':
|
elif field.type == 'blob':
|
||||||
continue
|
continue
|
||||||
|
elif isinstance(field.type, SQLCustomType) and callable(field.type.widget):
|
||||||
|
# SQLCustomType has a widget, use it
|
||||||
|
inp = field.type.widget(field, default)
|
||||||
else:
|
else:
|
||||||
field_type = widget_class.match(str(field.type)).group()
|
field_type = widget_class.match(str(field.type)).group()
|
||||||
field_type = field_type in self.widgets and field_type or 'string'
|
field_type = field_type in self.widgets and field_type or 'string'
|
||||||
@@ -2708,6 +2717,9 @@ class SQLFORM(FORM):
|
|||||||
_href='%s/%s' % (upload, value))
|
_href='%s/%s' % (upload, value))
|
||||||
else:
|
else:
|
||||||
value = ''
|
value = ''
|
||||||
|
elif isinstance(field.type, SQLCustomType) and callable(field.type.represent):
|
||||||
|
# SQLCustomType has a represent, use it
|
||||||
|
value = field.type.represent(value, row)
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
value = truncate_string(value, maxlength)
|
value = truncate_string(value, maxlength)
|
||||||
elif not isinstance(value, XmlComponent):
|
elif not isinstance(value, XmlComponent):
|
||||||
|
|||||||
@@ -15,10 +15,11 @@ from gluon.dal import DAL, Field
|
|||||||
|
|
||||||
class TestDALSubclass(unittest.TestCase):
|
class TestDALSubclass(unittest.TestCase):
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
import gluon.serializers as mserializers
|
from gluon.serializers import custom_json, xml
|
||||||
from gluon import sqlhtml
|
from gluon import sqlhtml
|
||||||
db = DAL(check_reserved=['all'])
|
db = DAL(check_reserved=['all'])
|
||||||
self.assertEqual(db.serializers, mserializers)
|
self.assertEqual(db.serializers['json'], custom_json)
|
||||||
|
self.assertEqual(db.serializers['xml'], xml)
|
||||||
self.assertEqual(db.representers['rows_render'], sqlhtml.represent)
|
self.assertEqual(db.representers['rows_render'], sqlhtml.represent)
|
||||||
self.assertEqual(db.representers['rows_xml'], sqlhtml.SQLTABLE)
|
self.assertEqual(db.representers['rows_xml'], sqlhtml.SQLTABLE)
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -5362,7 +5362,7 @@ class Expose(object):
|
|||||||
if current.request.raw_args:
|
if current.request.raw_args:
|
||||||
self.args = [arg for arg in current.request.raw_args.split('/') if arg]
|
self.args = [arg for arg in current.request.raw_args.split('/') if arg]
|
||||||
else:
|
else:
|
||||||
self.args = [arg for arg in current.request.args if args]
|
self.args = [arg for arg in current.request.args if arg]
|
||||||
filename = os.path.join(base, *self.args)
|
filename = os.path.join(base, *self.args)
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
raise HTTP(404, "FILE NOT FOUND")
|
raise HTTP(404, "FILE NOT FOUND")
|
||||||
|
|||||||
+1
-1
@@ -611,7 +611,7 @@ class IS_IN_DB(Validator):
|
|||||||
|
|
||||||
def count(values, s=self.dbset, f=field):
|
def count(values, s=self.dbset, f=field):
|
||||||
return s(f.belongs(map(int, values))).count()
|
return s(f.belongs(map(int, values))).count()
|
||||||
if isinstance(self.dbset.db._adapter, GoogleDatastoreAdapter):
|
if GoogleDatastoreAdapter is not None and isinstance(self.dbset.db._adapter, GoogleDatastoreAdapter):
|
||||||
range_ids = range(0, len(values), 30)
|
range_ids = range(0, len(values), 30)
|
||||||
total = sum(count(values[i:i + 30]) for i in range_ids)
|
total = sum(count(values[i:i + 30]) for i in range_ids)
|
||||||
if total == len(values):
|
if total == len(values):
|
||||||
|
|||||||
@@ -0,0 +1,169 @@
|
|||||||
|
"This script will work fine for a few cases 'by default':"
|
||||||
|
" - completely CLEAN WS2012R2 host"
|
||||||
|
" - python 2.7 installed in the default path"
|
||||||
|
" - wfasctgi installed on the default path"
|
||||||
|
"It'll install web2py under the default website "
|
||||||
|
" You can use it as a boilerplate to automate your deployments"
|
||||||
|
" but it still is released AS IT IS. "
|
||||||
|
"BIG FAT WARNING: It will install a bunch of dependecies
|
||||||
|
Inspect the source before executing it"
|
||||||
|
""
|
||||||
|
""
|
||||||
|
$ErrorActionPreference = 'stop'
|
||||||
|
|
||||||
|
$REALLY_SURE = Read-Host "Do you want to start with web2py deployment? [y/N]"
|
||||||
|
if (!@('y', 'Y') -contains $REALLY_SURE) {
|
||||||
|
"Ok, Exiting without doing anything"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
#setting root folder
|
||||||
|
$rootfolder = $pwd
|
||||||
|
|
||||||
|
### utilities - start
|
||||||
|
function ask_a_question($question) {
|
||||||
|
$response = Read-Host "$question [Y/n]"
|
||||||
|
if (@('Y', 'y', '', $null) -contains $response) {
|
||||||
|
return $true
|
||||||
|
} else {
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function unzip_me {
|
||||||
|
#Load the assembly
|
||||||
|
[System.Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") | Out-Null
|
||||||
|
#Unzip the file
|
||||||
|
[System.IO.Compression.ZipFile]::ExtractToDirectory($pathToZip, $targetDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
### utilities - end
|
||||||
|
|
||||||
|
#install 4.5 that is needed for a bunch of things anyway
|
||||||
|
Install-WindowsFeature Net-Framework-45-Core
|
||||||
|
|
||||||
|
#fetch web2py
|
||||||
|
$web2py_url = 'http://www.web2py.com/examples/static/web2py_src.zip'
|
||||||
|
$web2py_file = "$pwd\web2py_src.zip"
|
||||||
|
if (!(Test-Path $web2py_file)) {
|
||||||
|
(new-object net.webclient).DownloadFile($web2py_url, $web2py_file)
|
||||||
|
}
|
||||||
|
#Load the assembly
|
||||||
|
[System.Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") | Out-Null
|
||||||
|
#Unzip the file
|
||||||
|
[System.IO.Compression.ZipFile]::ExtractToDirectory($web2py_file, $pwd)
|
||||||
|
|
||||||
|
#features installation (IIS, needed modules, python, chocolatey, etc)
|
||||||
|
$installfeatures = ask_a_question('Do you want to install needed features?')
|
||||||
|
|
||||||
|
if ($installfeatures) {
|
||||||
|
Install-WindowsFeature Web-Server,Web-Default-Doc,Web-Static-Content,Web-Http-Redirect,Web-Http-Logging,Web-Request-Monitor,`
|
||||||
|
Web-Http-Tracing,Web-Stat-Compression,Web-Dyn-Compression,Web-Filtering,Web-Basic-Auth,Web-Windows-Auth,Web-AppInit,`
|
||||||
|
Web-CGI,Web-WebSockets,Web-Mgmt-Console,Web-Net-Ext45
|
||||||
|
}
|
||||||
|
|
||||||
|
$copy_web2py = ask_a_question("Copy web2py to the default website root?")
|
||||||
|
if ($copy_web2py) {
|
||||||
|
Import-Module WebAdministration
|
||||||
|
$available_websites = Get-Website
|
||||||
|
if ($available_websites[0] -eq $null) {
|
||||||
|
$default_one = $available_websites
|
||||||
|
} else {
|
||||||
|
$default_one = $available_websites[0]
|
||||||
|
}
|
||||||
|
$iis_root = [System.Environment]::ExpandEnvironmentVariables($default_one.PhysicalPath)
|
||||||
|
Copy-Item "$rootfolder\web2py\*" $iis_root -Recurse
|
||||||
|
$rootfolder = $iis_root
|
||||||
|
$acl = (Get-Item $rootfolder).GetAccessControl('Access')
|
||||||
|
$identity = "BUILTIN\IIS_IUSRS"
|
||||||
|
$fileSystemRights = "Modify"
|
||||||
|
$inheritanceFlags = "ContainerInherit, ObjectInherit"
|
||||||
|
$propagationFlags = "None"
|
||||||
|
$accessControlType = "Allow"
|
||||||
|
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule($identity, $fileSystemRights, $inheritanceFlags, $propagationFlags, $accessControlType)
|
||||||
|
$acl.SetAccessRule($rule)
|
||||||
|
Set-Acl $rootfolder $acl
|
||||||
|
}
|
||||||
|
|
||||||
|
$create_cert = ask_a_question("Do you want to create a self-signed SSL cert?")
|
||||||
|
if ($create_cert) {
|
||||||
|
$cert = New-SelfSignedCertificate -DnsName ("localtest.me","*.localtest.me") -CertStoreLocation cert:\LocalMachine\My
|
||||||
|
$rootStore = Get-Item cert:\LocalMachine\Root
|
||||||
|
$rootStore.Open("ReadWrite")
|
||||||
|
$rootStore.Add($cert)
|
||||||
|
$rootStore.Close();
|
||||||
|
Import-Module WebAdministration
|
||||||
|
Set-Location IIS:\SslBindings
|
||||||
|
New-WebBinding -Name "Default Web Site" -IP "*" -Port 443 -Protocol https
|
||||||
|
$cert | New-Item 0.0.0.0!443
|
||||||
|
Set-Location $pwd
|
||||||
|
}
|
||||||
|
|
||||||
|
"checking for chocolatey"
|
||||||
|
if (Get-Command "choco.exe" -ErrorAction SilentlyContinue)
|
||||||
|
{
|
||||||
|
"chocolatey found"
|
||||||
|
} else {
|
||||||
|
"installing chocolatey"
|
||||||
|
(new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1') | iex
|
||||||
|
}
|
||||||
|
"installing url-rewrite"
|
||||||
|
choco install UrlRewrite
|
||||||
|
$pythonexe = Read-Host 'Python.exe path [C:\Python27\python.exe]'
|
||||||
|
if (($pythonexe -eq '') -or ($pythonexe -eq $null)) {
|
||||||
|
$pythonexe = 'C:\Python27\python.exe'
|
||||||
|
}
|
||||||
|
if (!(Test-Path $pythonexe)) {
|
||||||
|
"ERROR: python executable not found"
|
||||||
|
$pythonwanted = ask_a_question("do you want to install it automatically?")
|
||||||
|
|
||||||
|
if ($pythonwanted) {
|
||||||
|
choco install webpicmd
|
||||||
|
WebpiCmd.exe /Install /Products:WFastCgi_21_279
|
||||||
|
$pythonexe = 'C:\Python27\python.exe'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
$wfastcgipath = Read-Host 'wfastcgi.py path [C:\Python27\Scripts\wfastcgi.py]'
|
||||||
|
if (($wfastcgipath -eq '') -or ($wfastcgipath -eq $null)) {
|
||||||
|
$wfastcgipath = 'C:\Python27\Scripts\wfastcgi.py'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path $wfastcgipath)) {
|
||||||
|
"ERROR: wfastcgi.py not found"
|
||||||
|
|
||||||
|
$wfastcgiwanted = ask_a_question("do you want to install it automatically?")
|
||||||
|
if ($wfastcgiwanted) {
|
||||||
|
choco install webpicmd
|
||||||
|
WebpiCmd.exe /Install /Products:WFastCgi_21_279
|
||||||
|
} else {
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$pythondir = Split-Path c:\python27\python.exe
|
||||||
|
#installing dependencies
|
||||||
|
$env:Path = $env:Path + ";$pythondir;$pythondir\Scripts"
|
||||||
|
|
||||||
|
pip install pypiwin32
|
||||||
|
|
||||||
|
$PW = Read-Host 'Web2py Admin Password'
|
||||||
|
|
||||||
|
$appcmdpath = "$env:windir\system32\inetsrv\appcmd.exe"
|
||||||
|
|
||||||
|
& $appcmdpath set config /section:system.webServer/fastCGI "/+[fullPath='$pythonexe', arguments='$wfastcgipath']"
|
||||||
|
& $appcmdpath unlock config -section:system.webServer/handlers
|
||||||
|
|
||||||
|
& cd $rootfolder
|
||||||
|
& $pythonexe -c "from gluon.main import save_password; save_password('$PW',443)"
|
||||||
|
|
||||||
|
$webconfig_template = Join-Path $rootfolder "examples\web.config"
|
||||||
|
$destination = Join-Path $rootfolder "web.config"
|
||||||
|
$scriptprocessor = 'scriptProcessor="{0}|{1}"' -f $pythonexe, $wfastcgipath
|
||||||
|
|
||||||
|
(Get-Content $webconfig_template) | Foreach-Object {$_ -replace 'scriptProcessor="SCRIPT_PROCESSOR"', $scriptprocessor} | where {$_ -ne ""} | Set-Content $destination
|
||||||
|
""
|
||||||
|
"Installation finished. Web2py is available either on http://localhost/ or at https://localtest.me/"
|
||||||
|
""
|
||||||
Executable
+78
@@ -0,0 +1,78 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Post error tickets to slack on a 5 minute schedule.
|
||||||
|
#
|
||||||
|
# Proper use depends on having created a web-hook through Slack, and having set
|
||||||
|
# that value in your app's model as the value of global_settings.slack_hook.
|
||||||
|
# Details on creating web-hooks can be found at https://slack.com/integrations
|
||||||
|
#
|
||||||
|
# requires the Requests module for posting to slack, other requirements are
|
||||||
|
# standard or provided by web2py
|
||||||
|
#
|
||||||
|
# Usage (on Unices), replace myapp with the name of your application and run:
|
||||||
|
# nohup python web2py.py -S myapp -M -R scripts/tickets2slack.py &
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import pickle
|
||||||
|
import json
|
||||||
|
|
||||||
|
try:
|
||||||
|
import requests
|
||||||
|
except ImportError as e:
|
||||||
|
print "missing module 'Requests', aborting."
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
from gluon import URL
|
||||||
|
from gluon.utils import md5_hash
|
||||||
|
from gluon.restricted import RestrictedError
|
||||||
|
from gluon.settings import global_settings
|
||||||
|
|
||||||
|
|
||||||
|
path = os.path.join(request.folder, 'errors')
|
||||||
|
sent_errors_file = os.path.join(path, 'slack_errors.pickle')
|
||||||
|
hashes = {}
|
||||||
|
if os.path.exists(sent_errors_file):
|
||||||
|
try:
|
||||||
|
with open(sent_errors_file, 'rb') as f:
|
||||||
|
hashes = pickle.load(f)
|
||||||
|
except Exception as _:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# ## CONFIGURE HERE
|
||||||
|
SLEEP_MINUTES = 5
|
||||||
|
ALLOW_DUPLICATES = False
|
||||||
|
global_settings.slack_hook = global_settings.slack_hook or \
|
||||||
|
'https://hooks.slack.com/services/your_service'
|
||||||
|
# ## END CONFIGURATION
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
for file_name in os.listdir(path):
|
||||||
|
if file_name == 'slack_errors.pickle':
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not ALLOW_DUPLICATES:
|
||||||
|
key = md5_hash(file_name)
|
||||||
|
if key in hashes:
|
||||||
|
continue
|
||||||
|
hashes[key] = 1
|
||||||
|
|
||||||
|
error = RestrictedError()
|
||||||
|
|
||||||
|
try:
|
||||||
|
error.load(request, request.application, file_name)
|
||||||
|
except Exception as _:
|
||||||
|
continue # not an exception file?
|
||||||
|
|
||||||
|
url = URL(a='admin', f='ticket', args=[request.application, file],
|
||||||
|
scheme=True)
|
||||||
|
payload = json.dumps(dict(text="Error in %(app)s.\n%(url)s" %
|
||||||
|
dict(app=request.application, url=url)))
|
||||||
|
|
||||||
|
requests.post(global_settings.slack_hook, data=dict(payload=payload))
|
||||||
|
|
||||||
|
with open(sent_errors_file, 'wb') as f:
|
||||||
|
pickle.dump(hashes, f)
|
||||||
|
time.sleep(SLEEP_MINUTES * 60)
|
||||||
Reference in New Issue
Block a user