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, jwt=None, host_names=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’

allows_jwt(otherwise=None)[source]
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.

bulk_register(max_emails=100)[source]

Creates a form for ther user to send invites to other users to join

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

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

Returns a form to confirm user registration

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', 'logout_log': 'User %(id)s Logged-out', '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', 'bulk_invite_body': 'You have been invited to join %(site)s, click %(link)s to complete the process', 'register_log': 'User %(id)s Registered', 'label_reset_password_key': 'Reset Password key', 'verify_password': 'Verify Password', 'retrieve_password_subject': 'Password retrieve', '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', 'registration_pending': 'Registration is pending approval', 'label_two_factor': 'Authentication code', '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, 'reset_password_subject': 'Password reset', 'del_membership_log': None, 'login_button': 'Log In', 'profile_save_button': 'Apply changes', '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', 'label_origin': 'Origin', 'access_denied': 'Insufficient privileges', 'mismatched_password': "Password fields don't match", 'delete_label': 'Check to delete', 'verify_password_comment': 'please input your password again', 'function_disabled': 'Function disabled', 'username_taken': 'Username already taken', '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', 'two_factor_comment': 'This code was emailed to you and is required for login.', 'label_name': 'Name', 'submit_button': 'Submit', 'label_registration_key': 'Registration key', 'label_last_name': 'Last name', 'label_description': 'Description', 'bulk_invite_subject': 'Invitation to join %(site)s', 'invalid_password': 'Invalid password', 'add_group_log': 'Group %(group_id)s created', 'password_changed': 'Password changed', 'retrieve_two_factor_code_subject': 'Two-step Login Authentication Code', 'new_password': 'New password', 'label_registration_id': 'Registration identifier', 'retrieve_password_log': 'User %(id)s Password retrieved', 'reset_password_log': 'User %(id)s Password reset', 'label_table_name': 'Object or table name', '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', 'del_permission_log': None, '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', 'invalid_two_factor_code': 'Incorrect code. {0} more attempt(s) remaining.', 'unable_to_send_email': 'Unable to send email', 'invalid_username': 'Invalid username', 'label_group_id': 'Group ID', 'email_verified': 'Email verified', 'new_password_sent': 'A new password was emailed to you', 'is_empty': 'Cannot be empty', 'retrieve_two_factor_code': 'Your temporary login code is {0}', 'label_remember_me': 'Remember me (for 30 days)', '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, 'label_separator': None, 'hideerror': False, 'table_permission_name': 'auth_permission', 'register_captcha': None, 'table_cas_name': 'auth_cas', 'allow_basic_login_only': False, 'manager_actions': {}, 'remember_me_form': True, 'logout_onlogout': None, 'table_token_name': 'auth_token', 'client_side': True, 'table_membership': None, 'bulk_register_enabled': False, 'ondelete': 'CASCADE', 'register_verify_password': True, 'renew_session_onlogout': True, 'long_expiration': 2592000, 'registration_requires_verification': False, 'everybody_group_id': None, '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', 'auth_two_factor_tries_left': 3, '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, 'auth_two_factor_enabled': False, 'pre_registration_div': 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 0x7fc28b5d40c8>, 'table_group_name': 'auth_group', 'table_group': None, 'table_membership_name': 'auth_membership'}
define_signature()[source]
define_tables(username=None, signature=None, enable_tokens=False, 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_registration(subject, body, user)[source]

Sends and email invitation to a user informing they have been registered with the application

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

jwt()[source]

To use JWT authentication: 1) instantiate auth with:

auth = Auth(db, jwt = {'secret_key':'secret'})

where ‘secret’ is your own secret string.

  1. Decorate functions that require login but should accept the JWT token credentials:

    @auth.allows_jwt()
    @auth.requires_login()
    def myapi(): return 'hello %s' % auth.user.email
    

Notice jwt is allowed but not required. if user is logged in, myapi is accessible.

  1. Use it!

Now API users can obtain a token with

(returns json object with a token attribute) API users can refresh an existing token with

they can authenticate themselves when calling http:/.../myapi by injecting a header

Authorization: Bearer <the jwt token>

Any additional attributes in the jwt argument of Auth() below:

auth = Auth(db, jwt = {...})

are passed to the constructor of class AuthJWT. Look there for documentation.

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

logout_bare()[source]
manage_tokens()[source]
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_login_or_token(otherwise=None)[source]
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]
select_host(host, host_names=None)[source]

checks that host is valid, i.e. in the list of glob host_names if the host is missing, then is it selects the first entry from host_names read more here: https://github.com/web2py/web2py/issues/1196

table_cas()[source]
table_event()[source]
table_group()[source]
table_membership()[source]
table_permission()[source]
table_token()[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

when_is_logged_in_bypass_next_in_url(next, session)[source]

This function should be use when someone want to avoid asking for user credentials when loaded page contains “user/login?_next=NEXT_COMPONENT” in the URL is refresh but user is already authenticated.

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>>, utc=False)[source]