tools Module

This file is part of the web2py Web Framework
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>

Auth, Mail, PluginManager and various utilities

class gluon.tools.Mail(server=None, sender=None, login=None, tls=True)[source]

Bases: object

Class for configuring and sending emails with alternative text / html body, multiple attachments and encryption support

Works with SMTP and Google App Engine.

Parameters:
  • server – SMTP server address in address:port notation
  • sender – sender email address
  • login – sender login name and password in login:password notation or None if no authentication is required
  • tls – enables/disables encryption (True by default)

In Google App Engine use

server='gae'

For sake of backward compatibility all fields are optional and default to None, however, to be able to send emails at least server and sender must be specified. They are available under following fields:

mail.settings.server
mail.settings.sender
mail.settings.login
mail.settings.timeout = 60 # seconds (default)

When server is ‘logging’, email is logged but not sent (debug mode)

Optionally you can use PGP encryption or X509:

mail.settings.cipher_type = None
mail.settings.gpg_home = None
mail.settings.sign = True
mail.settings.sign_passphrase = None
mail.settings.encrypt = True
mail.settings.x509_sign_keyfile = None
mail.settings.x509_sign_certfile = None
mail.settings.x509_sign_chainfile = None
mail.settings.x509_nocerts = False
mail.settings.x509_crypt_certfiles = None

cipher_type       : None
                    gpg - need a python-pyme package and gpgme lib
                    x509 - smime
gpg_home          : you can set a GNUPGHOME environment variable
                    to specify home of gnupg
sign              : sign the message (True or False)
sign_passphrase   : passphrase for key signing
encrypt           : encrypt the message (True or False). It defaults
                    to True
                 ... x509 only ...
x509_sign_keyfile : the signers private key filename or
                    string containing the key. (PEM format)
x509_sign_certfile: the signers certificate filename or
                    string containing the cert. (PEM format)
x509_sign_chainfile: sets the optional all-in-one file where you
                     can assemble the certificates of Certification
                     Authorities (CA) which form the certificate
                     chain of email certificate. It can be a
                     string containing the certs to. (PEM format)
x509_nocerts      : if True then no attached certificate in mail
x509_crypt_certfiles: the certificates file or strings to encrypt
                      the messages with can be a file name /
                      string or a list of file names /
                      strings (PEM format)

Examples

Create Mail object with authentication data for remote server:

mail = Mail('example.com:25', 'me@example.com', 'me:password')
Notice for GAE users:
attachments have an automatic content_id=’attachment-i’ where i is progressive number in this way the can be referenced from the HTML as <img src=”cid:attachment-0” /> etc.
class Attachment(payload, filename=None, content_id=None, content_type=None, encoding='utf-8')[source]

Bases: email.mime.base.MIMEBase

Email attachment

Parameters:
  • payload – path to file or file-like object with read() method
  • filename – name of the attachment stored in message; if set to None, it will be fetched from payload path; file-like object payload must have explicit filename specified
  • content_id – id of the attachment; automatically contained within < and >
  • content_type – content type of the attachment; if set to None, it will be fetched from filename using gluon.contenttype module
  • encoding – encoding of all strings passed to this function (except attachment body)

Content ID is used to identify attachments within the html body; in example, attached image with content ID ‘photo’ may be used in html message as a source of img tag <img src=”cid:photo” />.

Example::

Create attachment from text file:

attachment = Mail.Attachment('/path/to/file.txt')

Content-Type: text/plain
MIME-Version: 1.0
Content-Disposition: attachment; filename="file.txt"
Content-Transfer-Encoding: base64

SOMEBASE64CONTENT=

Create attachment from image file with custom filename and cid:

attachment = Mail.Attachment('/path/to/file.png',
                                 filename='photo.png',
                                 content_id='photo')

Content-Type: image/png
MIME-Version: 1.0
Content-Disposition: attachment; filename="photo.png"
Content-Id: <photo>
Content-Transfer-Encoding: base64

SOMEOTHERBASE64CONTENT=
Mail.send(to, subject='[no subject]', message='[no message]', attachments=None, cc=None, bcc=None, reply_to=None, sender=None, encoding='utf-8', raw=False, headers={}, from_address=None, cipher_type=None, sign=None, sign_passphrase=None, encrypt=None, x509_sign_keyfile=None, x509_sign_chainfile=None, x509_sign_certfile=None, x509_crypt_certfiles=None, x509_nocerts=None)[source]

Sends an email using data specified in constructor

Parameters:
  • to – list or tuple of receiver addresses; will also accept single object
  • subject – subject of the email
  • message

    email body text; depends on type of passed object:

    • if 2-list or 2-tuple is passed: first element will be source of plain text while second of html text;
    • otherwise: object will be the only source of plain text and html source will be set to None

    If text or html source is:

    • None: content part will be ignored,
    • string: content part will be set to it,
    • file-like object: content part will be fetched from it using it’s read() method
  • attachments – list or tuple of Mail.Attachment objects; will also accept single object
  • cc – list or tuple of carbon copy receiver addresses; will also accept single object
  • bcc – list or tuple of blind carbon copy receiver addresses; will also accept single object
  • reply_to – address to which reply should be composed
  • encoding – encoding of all strings passed to this method (including message bodies)
  • headers – dictionary of headers to refine the headers just before sending mail, e.g. {‘X-Mailer’ : ‘web2py mailer’}
  • from_address – address to appear in the ‘From:’ header, this is not the envelope sender. If not specified the sender will be used
  • cipher_type – gpg - need a python-pyme package and gpgme lib x509 - smime
  • gpg_home – you can set a GNUPGHOME environment variable to specify home of gnupg
  • sign – sign the message (True or False)
  • sign_passphrase – passphrase for key signing
  • encrypt – encrypt the message (True or False). It defaults to True. ... x509 only ...
  • x509_sign_keyfile – the signers private key filename or string containing the key. (PEM format)
  • x509_sign_certfile – the signers certificate filename or string containing the cert. (PEM format)
  • x509_sign_chainfile – sets the optional all-in-one file where you can assemble the certificates of Certification Authorities (CA) which form the certificate chain of email certificate. It can be a string containing the certs to. (PEM format)
  • x509_nocerts – if True then no attached certificate in mail
  • x509_crypt_certfiles – the certificates file or strings to encrypt the messages with can be a file name / string or a list of file names / strings (PEM format)

Examples

Send plain text message to single address:

mail.send('you@example.com',
          'Message subject',
          'Plain text body of the message')

Send html message to single address:

mail.send('you@example.com',
          'Message subject',
          '<html>Plain text body of the message</html>')

Send text and html message to three addresses (two in cc):

mail.send('you@example.com',
          'Message subject',
          ('Plain text body', '<html>html body</html>'),
          cc=['other1@example.com', 'other2@example.com'])

Send html only message with image attachment available from the message by ‘photo’ content id:

mail.send('you@example.com',
          'Message subject',
          (None, '<html><img src="cid:photo" /></html>'),
          Mail.Attachment('/path/to/photo.jpg'
                          content_id='photo'))

Send email with two attachments and no body text:

mail.send('you@example.com,
          'Message subject',
          None,
          [Mail.Attachment('/path/to/fist.file'),
           Mail.Attachment('/path/to/second.file')])
Returns:True on success, False on failure.

Before return, method updates two object’s fields:

  • self.result: return value of smtplib.SMTP.sendmail() or GAE’s mail.send_mail() method
  • self.error: Exception message or None if above was successful
class gluon.tools.Auth(environment=None, db=None, mailer=True, hmac_key=None, controller='default', function='user', cas_provider=None, signature=True, secure=False, csrf_prevention=True, propagate_extension=None, url_index=None)[source]

Bases: object

accessible_query(name, table, user_id=None)[source]

Returns a query with all accessible records for user_id or the current logged in user this method does not work on GAE because uses JOIN and IN

Example

Use as:

db(auth.accessible_query('read', db.mytable)).select(db.mytable.ALL)
add_group(role, description='')[source]

Creates a group associated to a role

add_membership(group_id=None, user_id=None, role=None)[source]

Gives user_id membership of group_id or role if user is None than user_id is that of current logged in user

add_permission(group_id, name='any', table_name='', record_id=0)[source]

Gives group_id ‘name’ access to ‘table_name’ and ‘record_id’

static archive(form, archive_table=None, current_record='current_record', archive_current=False, fields=None)[source]

If you have a table (db.mytable) that needs full revision history you can just do:

form=crud.update(db.mytable,myrecord,onaccept=auth.archive)

or:

form=SQLFORM(db.mytable,myrecord).process(onaccept=auth.archive)

crud.archive will define a new table “mytable_archive” and store a copy of the current record (if archive_current=True) or a copy of the previous record (if archive_current=False) in the newly created table including a reference to the current record.

fields allows to specify extra fields that need to be archived.

If you want to access such table you need to define it yourself in a model:

db.define_table('mytable_archive',
    Field('current_record',db.mytable),
    db.mytable)

Notice such table includes all fields of db.mytable plus one: current_record. crud.archive does not timestamp the stored record unless your original table has a fields like:

db.define_table(...,
    Field('saved_on','datetime',
         default=request.now,update=request.now,writable=False),
    Field('saved_by',auth.user,
         default=auth.user_id,update=auth.user_id,writable=False),

there is nothing special about these fields since they are filled before the record is archived.

If you want to change the archive table name and the name of the reference field you can do, for example:

db.define_table('myhistory',
    Field('parent_record',db.mytable),
    db.mytable)

and use it as:

form=crud.update(db.mytable,myrecord,
                 onaccept=lambda form:crud.archive(form,
                 archive_table=db.myhistory,
                 current_record='parent_record'))
basic(basic_auth_realm=False)[source]

Performs basic login.

Parameters:basic_auth_realm – optional basic http authentication realm. Can take str or unicode or function or callable or boolean.

reads current.request.env.http_authorization and returns basic_allowed,basic_accepted,user.

if basic_auth_realm is defined is a callable it’s return value is used to set the basic authentication realm, if it’s a string its content is used instead. Otherwise basic authentication realm is set to the application name. If basic_auth_realm is None or False (the default) the behavior is to skip sending any challenge.

cas_login(next=<function <lambda>>, onvalidation=<function <lambda>>, onaccept=<function <lambda>>, log=<function <lambda>>, version=2)[source]
cas_validate(version=2, proxy=False)[source]
change_password(next=<function <lambda>>, onvalidation=<function <lambda>>, onaccept=<function <lambda>>, log=<function <lambda>>)[source]

Returns a form that lets the user change password

default_messages = {'invalid_email': 'Invalid email', 'verify_email_subject': 'Email verification', 'password_change_button': 'Change password', 'unable_send_email': 'Unable to send email', 'has_permission_log': None, 'label_email': 'E-mail', 'add_group_log': 'Group %(group_id)s created', 'verify_email': 'Welcome %(username)s! Click on the link %(link)s to verify your email', 'impersonate_log': 'User %(id)s is impersonating %(other_id)s', 'retrieve_username': 'Your username is: %(username)s', 'label_record_id': 'Record ID', 'register_log': 'User %(id)s Registered', 'username_taken': 'Username already taken', 'verify_password': 'Verify Password', 'label_remember_me': 'Remember me (for 30 days)', 'retrieve_username_log': 'User %(id)s Username retrieved', 'email_taken': 'This email already has an account', 'registration_successful': 'Registration successful', 'label_password': 'Password', 'logged_in': 'Logged in', 'profile_save_button': 'Apply changes', 'login_disabled': 'Login disabled by administrator', 'label_user_id': 'User ID', 'label_first_name': 'First name', 'del_group_log': 'Group %(group_id)s deleted', 'registration_verifying': 'Registration needs verification', 'add_permission_log': None, 'invalid_username': 'Invalid username', 'del_membership_log': None, 'login_button': 'Log In', 'registration_pending': 'Registration is pending approval', 'retrieve_password': 'Your password is: %(password)s', 'invalid_login': 'Invalid login', 'retrieve_username_subject': 'Username retrieve', 'change_password_log': 'User %(id)s Password changed', 'reset_password': 'Click on the link %(link)s to reset your password', 'email_sent': 'Email sent', 'register_button': 'Sign Up', 'logout_log': 'User %(id)s Logged-out', 'access_denied': 'Insufficient privileges', 'new_password_sent': 'A new password was emailed to you', 'delete_label': 'Check to delete', 'verify_password_comment': 'please input your password again', 'submit_button': 'Submit', 'label_reset_password_key': 'Reset Password key', 'label_role': 'Role', 'label_time_stamp': 'Timestamp', 'profile_updated': 'Profile updated', 'logged_out': 'Logged out', 'login_failed_log': None, 'verify_email_log': 'User %(id)s Verification email sent', 'label_name': 'Name', 'function_disabled': 'Function disabled', 'label_registration_key': 'Registration key', 'label_last_name': 'Last name', 'label_description': 'Description', 'label_table_name': 'Object or table name', 'password_changed': 'Password changed', 'new_password': 'New password', 'label_registration_id': 'Registration identifier', 'retrieve_password_log': 'User %(id)s Password retrieved', 'label_origin': 'Origin', 'reset_password_log': 'User %(id)s Password reset', 'invalid_password': 'Invalid password', 'login_log': 'User %(id)s Logged-in', 'profile_log': 'User %(id)s Profile updated', 'invalid_reset_password': 'Invalid reset password', 'password_reset_button': 'Request reset password', 'is_empty': 'Cannot be empty', 'add_membership_log': None, 'label_client_ip': 'Client IP', 'invalid_user': 'Invalid user', 'has_membership_log': None, 'group_description': 'Group uniquely assigned to user %(id)s', 'unable_to_send_email': 'Unable to send email', 'reset_password_subject': 'Password reset', 'label_group_id': 'Group ID', 'email_verified': 'Email verified', 'mismatched_password': "Password fields don't match", 'del_permission_log': None, 'retrieve_password_subject': 'Password retrieve', 'username_sent': 'Your username was emailed to you', 'old_password': 'Old password', 'label_username': 'Username'}

Class for authentication, authorization, role based access control.

Includes:

  • registration and profile
  • login and logout
  • username and password retrieval
  • event logging
  • role creation and assignment
  • user defined group/role based permission
Parameters:
  • environment – is there for legacy but unused (awful)
  • db – has to be the database where to create tables for authentication
  • mailerMail(...) or None (no mailer) or True (make a mailer)
  • hmac_key – can be a hmac_key or hmac_key=Auth.get_or_create_key()
  • controller – (where is the user action?)
  • cas_provider – (delegate authentication to the URL, CAS2)

Authentication Example:

from gluon.contrib.utils import *
mail=Mail()
mail.settings.server='smtp.gmail.com:587'
mail.settings.sender='you@somewhere.com'
mail.settings.login='username:password'
auth=Auth(db)
auth.settings.mailer=mail
# auth.settings....=...
auth.define_tables()
def authentication():
    return dict(form=auth())

Exposes:

  • http://.../{application}/{controller}/authentication/login
  • http://.../{application}/{controller}/authentication/logout
  • http://.../{application}/{controller}/authentication/register
  • http://.../{application}/{controller}/authentication/verify_email
  • http://.../{application}/{controller}/authentication/retrieve_username
  • http://.../{application}/{controller}/authentication/retrieve_password
  • http://.../{application}/{controller}/authentication/reset_password
  • http://.../{application}/{controller}/authentication/profile
  • http://.../{application}/{controller}/authentication/change_password

On registration a group with role=new_user.id is created and user is given membership of this group.

You can create a group with:

group_id=auth.add_group('Manager', 'can access the manage action')
auth.add_permission(group_id, 'access to manage')

Here “access to manage” is just a user defined string. You can give access to a user:

auth.add_membership(group_id, user_id)

If user id is omitted, the logged in user is assumed

Then you can decorate any action:

@auth.requires_permission('access to manage')
def manage():
    return dict()

You can restrict a permission to a specific table:

auth.add_permission(group_id, 'edit', db.sometable)
@auth.requires_permission('edit', db.sometable)

Or to a specific record:

auth.add_permission(group_id, 'edit', db.sometable, 45)
@auth.requires_permission('edit', db.sometable, 45)

If authorization is not granted calls:

auth.settings.on_failed_authorization

Other options:

auth.settings.mailer=None
auth.settings.expiration=3600 # seconds

...

### these are messages that can be customized
...
default_settings = {'profile_fields': None, 'table_permission': None, 'table_event_name': 'auth_event', 'login_userfield': None, 'table_event': None, 'register_captcha': None, 'label_separator': None, 'hideerror': False, 'table_permission_name': 'auth_permission', 'pre_registration_div': None, 'table_cas_name': 'auth_cas', 'allow_basic_login_only': False, 'manager_actions': {}, 'remember_me_form': True, 'logout_onlogout': None, 'client_side': True, 'table_membership': None, 'ondelete': 'CASCADE', 'register_verify_password': True, 'renew_session_onlogout': True, 'long_expiration': 2592000, 'registration_requires_verification': False, 'username_case_sensitive': True, 'logging_enabled': True, 'keep_session_onlogout': False, 'login_after_password_change': True, 'prevent_password_reset_attacks': True, 'expiration': 3600, 'allow_basic_login': False, 'create_user_groups': 'user_%(id)s', 'wiki': <Storage {}>, 'update_fields': ['email'], 'showid': False, 'retrieve_username_captcha': None, 'two_factor_authentication_group': None, 'password_field': 'password', 'keep_session_onlogin': True, 'table_cas': None, 'captcha': None, 'registration_requires_approval': False, 'table_user_name': 'auth_user', 'table_user': None, 'password_min_length': 4, 'renew_session_onlogin': True, 'register_fields': None, 'allow_delete_accounts': False, 'auth_manager_role': None, 'login_email_validate': True, 'alternate_requires_registration': False, 'email_case_sensitive': True, 'use_username': False, 'formstyle': None, 'everybody_group_id': None, 'prevent_open_redirect_attacks': True, 'reset_password_requires_verification': False, 'cas_maps': None, 'login_after_registration': False, 'login_captcha': None, 'multi_login': False, 'retrieve_password_captcha': None, 'on_failed_authentication': <function <lambda> at 0x7fd4c88162a8>, 'table_group_name': 'auth_group', 'table_group': None, 'table_membership_name': 'auth_membership'}
define_signature()[source]
define_tables(username=None, signature=None, migrate=None, fake_migrate=None)[source]

To be called unless tables are defined manually

Examples

Use as:

# defines all needed tables and table files
# 'myprefix_auth_user.table', ...
auth.define_tables(migrate='myprefix_')

# defines all needed tables without migration/table files
auth.define_tables(migrate=False)
del_group(group_id)[source]

Deletes a group

del_membership(group_id=None, user_id=None, role=None)[source]

Revokes membership from group_id to user_id if user_id is None than user_id is that of current logged in user

del_permission(group_id, name='any', table_name='', record_id=0)[source]

Revokes group_id ‘name’ access to ‘table_name’ and ‘record_id’

email_reset_password(user)[source]
enable_record_versioning(tables, archive_db=None, archive_names='%(tablename)s_archive', current_record='current_record', current_record_label=None)[source]

Used to enable full record versioning (including auth tables):

auth = Auth(db)
auth.define_tables(signature=True)
# define our own tables
db.define_table('mything',Field('name'),auth.signature)
auth.enable_record_versioning(tables=db)

tables can be the db (all table) or a list of tables. only tables with modified_by and modified_on fiels (as created by auth.signature) will have versioning. Old record versions will be in table ‘mything_archive’ automatically defined.

when you enable enable_record_versioning, records are never deleted but marked with is_active=False.

enable_record_versioning enables a common_filter for every table that filters out records with is_active = False

Note

If you use auth.enable_record_versioning, do not use auth.archive or you will end up with duplicates. auth.archive does explicitly what enable_record_versioning does automatically.

static get_or_create_key(filename=None, alg='sha512')[source]
get_or_create_user(keys, update_fields=['email'], login=True, get=True)[source]

Used for alternate login methods: If the user exists already then password is updated. If the user doesn’t yet exist, then they are created.

get_vars_next()[source]
groups()[source]

Displays the groups and their roles for the logged in user

has_membership(group_id=None, user_id=None, role=None)[source]

Checks if user is member of group_id or role

has_permission(name='any', table_name='', record_id=0, user_id=None, group_id=None)[source]

Checks if user_id or current logged in user is member of a group that has ‘name’ permission on ‘table_name’ and ‘record_id’ if group_id is passed, it checks whether the group has the permission

here()[source]
id_group(role)[source]

Returns the group_id of the group specified by the role

impersonate(user_id=<function <lambda>>)[source]

To use this make a POST to http://..../impersonate request.post_vars.user_id=<id>

Set request.post_vars.user_id to 0 to restore original user.

requires impersonator is logged in and:

has_permission('impersonate', 'auth_user', user_id)
is_impersonating()[source]
is_logged_in()[source]

Checks if the user is logged in and returns True/False. If so user is in auth.user as well as in session.auth.user

log_event(description, vars=None, origin='auth')[source]

Examples

Use as:

auth.log_event(description='this happened', origin='auth')
login(next=<function <lambda>>, onvalidation=<function <lambda>>, onaccept=<function <lambda>>, log=<function <lambda>>)[source]

Returns a login form

login_bare(username, password)[source]

Logins user as specified by username (or email) and password

login_user(user)[source]

Logins the user = db.auth_user(id)

logout(next=<function <lambda>>, onlogout=<function <lambda>>, log=<function <lambda>>)[source]

Logouts and redirects to login

navbar(prefix='Welcome', action=None, separators=(' [ ', ' | ', ' ] '), user_identifier=<function <lambda>>, referrer_actions=<function <lambda>>, mode='default')[source]

Navbar with support for more templates This uses some code from the old navbar.

Parameters:mode – see options for list of
not_authorized()[source]

You can change the view for this page to make it look as you like

profile(next=<function <lambda>>, onvalidation=<function <lambda>>, onaccept=<function <lambda>>, log=<function <lambda>>)[source]

Returns a form that lets the user change his/her profile

random_password()[source]
register(next=<function <lambda>>, onvalidation=<function <lambda>>, onaccept=<function <lambda>>, log=<function <lambda>>)[source]

Returns a registration form

register_bare(**fields)[source]

Registers a user as specified by username (or email) and a raw password.

request_reset_password(next=<function <lambda>>, onvalidation=<function <lambda>>, onaccept=<function <lambda>>, log=<function <lambda>>)[source]

Returns a form to reset the user password

requires(condition, requires_login=True, otherwise=None)[source]

Decorator that prevents access to action if not logged in

requires_login(otherwise=None)[source]

Decorator that prevents access to action if not logged in

requires_membership(role=None, group_id=None, otherwise=None)[source]

Decorator that prevents access to action if not logged in or if user logged in is not a member of group_id. If role is provided instead of group_id then the group_id is calculated.

requires_permission(name, table_name='', record_id=0, otherwise=None)[source]

Decorator that prevents access to action if not logged in or if user logged in is not a member of any group (role) that has ‘name’ access to ‘table_name’, ‘record_id’.

requires_signature(otherwise=None, hash_vars=True)[source]

Decorator that prevents access to action if not logged in or if user logged in is not a member of group_id. If role is provided instead of group_id then the group_id is calculated.

reset_password(next=<function <lambda>>, onvalidation=<function <lambda>>, onaccept=<function <lambda>>, log=<function <lambda>>)[source]

Returns a form to reset the user password

reset_password_deprecated(next=<function <lambda>>, onvalidation=<function <lambda>>, onaccept=<function <lambda>>, log=<function <lambda>>)[source]

Returns a form to reset the user password (deprecated)

retrieve_password(next=<function <lambda>>, onvalidation=<function <lambda>>, onaccept=<function <lambda>>, log=<function <lambda>>)[source]
retrieve_username(next=<function <lambda>>, onvalidation=<function <lambda>>, onaccept=<function <lambda>>, log=<function <lambda>>)[source]

Returns a form to retrieve the user username (only if there is a username field)

run_login_onaccept()[source]
table_cas()[source]
table_event()[source]
table_group()[source]
table_membership()[source]
table_permission()[source]
table_user()[source]
update_groups()[source]
url(f=None, args=None, vars=None, scheme=False)[source]
user_group(user_id=None)[source]

Returns the group_id of the group uniquely associated to this user i.e. role=user:[user_id]

user_group_role(user_id=None)[source]
user_id

user.id or None

verify_email(next=<function <lambda>>, onaccept=<function <lambda>>, log=<function <lambda>>)[source]

Action used to verify the registration email

wiki(slug=None, env=None, render='markmin', manage_permissions=False, force_prefix='', restrict_search=False, resolve=True, extra=None, menu_groups=None, templates=None, migrate=True, controller=None, function=None, force_render=False, groups=None)[source]
wikimenu()[source]

To be used in menu.py for app wide wiki menus

class gluon.tools.Recaptcha(request=None, public_key='', private_key='', use_ssl=False, error=None, error_message='invalid', label='Verify:', options='', comment='', ajax=False)[source]

Bases: gluon.html.DIV

Examples

Use as:

form = FORM(Recaptcha(public_key='...',private_key='...'))

or:

form = SQLFORM(...)
form.append(Recaptcha(public_key='...',private_key='...'))
API_SERVER = 'http://www.google.com/recaptcha/api'
API_SSL_SERVER = 'https://www.google.com/recaptcha/api'
VERIFY_SERVER = 'http://www.google.com/recaptcha/api/verify'
xml()[source]
class gluon.tools.Recaptcha2(request=None, public_key='', private_key='', error_message='invalid', label='Verify:', options=None, comment='')[source]

Bases: gluon.html.DIV

Experimental: Creates a DIV holding the newer Recaptcha from Google (v2)

Parameters:
  • request – the request. If not passed, uses current request
  • public_key – the public key Google gave you
  • private_key – the private key Google gave you
  • error_message – the error message to show if verification fails
  • label – the label to use
  • options (dict) –

    takes these parameters

    • hl
    • theme
    • type
    • tabindex
    • callback
    • expired-callback

    see https://developers.google.com/recaptcha/docs/display for docs about those

  • comment – the comment

Examples

Use as:

form = FORM(Recaptcha2(public_key='...',private_key='...'))

or:

form = SQLFORM(...)
form.append(Recaptcha2(public_key='...',private_key='...'))

to protect the login page instead, use:

from gluon.tools import Recaptcha2
auth.settings.captcha = Recaptcha2(request, public_key='...',private_key='...')
API_URI = 'https://www.google.com/recaptcha/api.js'
VERIFY_SERVER = 'https://www.google.com/recaptcha/api/siteverify'
xml()[source]
class gluon.tools.Crud(environment, db=None, controller='default')[source]

Bases: object

static archive(form, archive_table=None, current_record='current_record')[source]
create(table, next=<function <lambda>>, onvalidation=<function <lambda>>, onaccept=<function <lambda>>, log=<function <lambda>>, message=<function <lambda>>, formname=<function <lambda>>, **attributes)[source]
delete(table, record_id, next=<function <lambda>>, message=<function <lambda>>)[source]
get_format(field)[source]
get_query(field, op, value, refsearch=False)[source]
has_permission(name, table, record=0)[source]
log_event(message, vars)[source]
read(table, record)[source]
rows(table, query=None, fields=None, orderby=None, limitby=None)[source]
search(*tables, **args)[source]

Creates a search form and its results for a table .. rubric:: Examples

Use as:

form, results = crud.search(db.test,
   queries = ['equals', 'not equal', 'contains'],
   query_labels={'equals':'Equals',
                 'not equal':'Not equal'},
   fields = ['id','children'],
   field_labels = {
       'id':'ID','children':'Children'},
   zero='Please choose',
   query = (db.test.id > 0)&(db.test.id != 3) )
select(table, query=None, fields=None, orderby=None, limitby=None, headers=None, **attr)[source]
tables()[source]
update(table, record, next=<function <lambda>>, onvalidation=<function <lambda>>, onaccept=<function <lambda>>, ondelete=<function <lambda>>, log=<function <lambda>>, message=<function <lambda>>, deletable=<function <lambda>>, formname=<function <lambda>>, **attributes)[source]
url(f=None, args=None, vars=None)[source]

This should point to the controller that exposes download and crud

class gluon.tools.Service(environment=None)[source]

Bases: object

exception JsonRpcException(code, info)[source]

Bases: exceptions.Exception

Service.amfrpc(f)[source]

Example

Use as:

service = Service()
@service.amfrpc
def myfunction(a, b):
    return a + b
def call():
    return service()

Then call it with:

wget http://..../app/default/call/amfrpc/myfunction?a=hello&b=world
Service.amfrpc3(domain='default')[source]

Example

Use as:

service = Service()
@service.amfrpc3('domain')
def myfunction(a, b):
    return a + b
def call():
    return service()

Then call it with:

Service.csv(f)[source]

Example

Use as:

service = Service()
@service.csv
def myfunction(a, b):
    return a + b
def call():
    return service()

Then call it with:

wget http://..../app/default/call/csv/myfunction?a=3&b=4
Service.error()[source]
Service.json(f)[source]

Example

Use as:

service = Service()
@service.json
def myfunction(a, b):
    return [{a: b}]
def call():
    return service()

Then call it with:;

Service.jsonrpc(f)[source]

Example

Use as:

service = Service()
@service.jsonrpc
def myfunction(a, b):
    return a + b
def call():
    return service()

Then call it with:

Service.jsonrpc2(f)[source]

Example

Use as:

service = Service()
@service.jsonrpc2
def myfunction(a, b):
    return a + b
def call():
    return service()

Then call it with:

wget –post-data ‘{“jsonrpc”: “2.0”, “id”: 1, “method”: “myfunction”, “params”: {“a”: 1, “b”: 2}}’ http://..../app/default/call/jsonrpc2
Service.jsonrpc_errors = {-32700: ('Parse error. Invalid JSON was received by the server.', 'An error occurred on the server while parsing the JSON text.'), -32603: ('Internal error', 'Internal JSON-RPC error.'), -32602: ('Invalid params', 'Invalid method parameter(s).'), -32601: ('Method not found', 'The method does not exist / is not available.'), -32600: ('Invalid Request', 'The JSON sent is not a valid Request object.'), -32099: ('Server error', 'Reserved for implementation-defined server-errors.')}
Service.rss(f)[source]

Example

Use as:

service = Service()
@service.rss
def myfunction():
    return dict(title=..., link=..., description=...,
        created_on=..., entries=[dict(title=..., link=...,
            description=..., created_on=...])
def call():
    return service()

Then call it with:

Service.run(f)[source]

Example

Use as:

service = Service()
@service.run
def myfunction(a, b):
    return a + b
def call():
    return service()

Then call it with:

wget http://..../app/default/call/run/myfunction?a=3&b=4
Service.serve_amfrpc(version=0)[source]
Service.serve_csv(args=None)[source]
Service.serve_json(args=None)[source]
Service.serve_jsonrpc()[source]
Service.serve_jsonrpc2(data=None, batch_element=False)[source]
Service.serve_rss(args=None)[source]
Service.serve_run(args=None)[source]
Service.serve_soap(version='1.1')[source]
Service.serve_xml(args=None)[source]
Service.serve_xmlrpc()[source]
Service.soap(name=None, returns=None, args=None, doc=None)[source]

Example

Use as:

service = Service()
@service.soap('MyFunction',returns={'result':int},args={'a':int,'b':int,})
def myfunction(a, b):
    return a + b
def call():
    return service()

Then call it with:

from gluon.contrib.pysimplesoap.client import SoapClient
client = SoapClient(wsdl="http://..../app/default/call/soap?WSDL")
response = client.MyFunction(a=1,b=2)
return response['result']

It also exposes online generated documentation and xml example messages at http://..../app/default/call/soap

Service.xml(f)[source]

Example

Use as:

service = Service()
@service.xml
def myfunction(a, b):
    return a + b
def call():
    return service()

Then call it with:

wget http://..../app/default/call/xml/myfunction?a=3&b=4
Service.xmlrpc(f)[source]

Example

Use as:

service = Service()
@service.xmlrpc
def myfunction(a, b):
    return a + b
def call():
    return service()

The call it with:

class gluon.tools.Wiki(auth, env=None, render='markmin', manage_permissions=False, force_prefix='', restrict_search=False, extra=None, menu_groups=None, templates=None, migrate=True, controller=None, function=None, groups=None)[source]

Bases: object

automenu()[source]

adds the menu if not present

can_edit(page=None)[source]
can_manage()[source]
can_read(page)[source]
can_see_menu()[source]
cloud()[source]
static component(text)[source]

In wiki docs allows @{component:controller/function/args} which renders as a LOAD(..., ajax=True)

create()[source]
edit(slug, from_template=0)[source]
editmedia(slug)[source]
everybody = 'everybody'
first_paragraph(page)[source]
fix_hostname(body)[source]
get_renderer()[source]
html_render(page)[source]
markmin_base(body)[source]
markmin_render(page)[source]
media(id)[source]
menu(controller='default', function='index')[source]
not_authorized(page=None)[source]
pages()[source]
preview(render)[source]
read(slug, force_render=False)[source]
render_tags(tags)[source]
rows_page = 25
search(tags=None, query=None, cloud=True, preview=True, limitby=(0, 100), orderby=None)[source]
settings = None

**Args* – render* – - “markmin” - “html” - <function> : Sets a custom render function - dict(html=<function>, markmin=...): dict(...) allows

multiple custom render functions
  • “multiple” : Is the same as {}. It enables per-record

    formats using builtins

class gluon.tools.PluginManager(plugin=None, **defaults)[source]

Bases: object

Plugin Manager is similar to a storage object but it is a single level singleton. This means that multiple instances within the same thread share the same attributes. Its constructor is also special. The first argument is the name of the plugin you are defining. The named arguments are parameters needed by the plugin with default values. If the parameters were previous defined, the old values are used.

Example

in some general configuration file:

plugins = PluginManager()
plugins.me.param1=3

within the plugin model:

_ = PluginManager('me',param1=5,param2=6,param3=7)

where the plugin is used:

>>> print plugins.me.param1
3
>>> print plugins.me.param2
6
>>> plugins.me.param3 = 8
>>> print plugins.me.param3
8

Here are some tests:

>>> a=PluginManager()
>>> a.x=6
>>> b=PluginManager('check')
>>> print b.x
6
>>> b=PluginManager() # reset settings
>>> print b.x
<Storage {}>
>>> b.x=7
>>> print a.x
7
>>> a.y.z=8
>>> print b.y.z
8
>>> test_thread_separation()
5
>>> plugins=PluginManager('me',db='mydb')
>>> print plugins.me.db
mydb
>>> print 'me' in plugins
True
>>> print plugins.me.installed
True
instances = {}
keys()[source]
gluon.tools.fetch(url, data=None, headers=None, cookie=<SimpleCookie: >, user_agent='Mozilla/5.0')[source]
gluon.tools.geocode(address)[source]
gluon.tools.reverse_geocode(lat, lng, lang=None)[source]

Try to get an approximate address for a given latitude, longitude.

gluon.tools.prettydate(d, T=<function <lambda>>)[source]