<filename>curator/models/db.py
# -*- coding: utf-8 -*-
from pprint import pprint
import sys
import os
from ConfigParser import SafeConfigParser
import requests
import json

# WARNING!  This file is a near-duplicat of webapp/models/db.py
#           Any changes here should probably be mirrored there.

conf = SafeConfigParser({})
config_file_found = None
try:
    test_config_paths = [
        "applications/%s/private/localconfig" % request.application,
        "applications/%s/private/config" % request.application,
    ]
    for test_path in test_config_paths:
        if os.path.isfile(test_path):
            config_file_found = test_path
            conf.read(test_path)
    assert 'apis' in conf.sections()
except:
    print("\n=== WEB-APP CONFIG NOT FOUND, INVALID, OR INCOMPLETE ===")
    if config_file_found == None:
        err_msg = "Webapp config not found! Expecting it in one of these locations:\n  {}".format(test_config_paths)
        print(err_msg)
        raise Exception(err_msg)
    err_msg = "Webapp config file ({}) is broken or incomplete (missing [apis] section)".format(config_file_found)
    print(err_msg)
    raise Exception(err_msg)

# add our GitHub client secret from a separate file (kept out of source repo)
if os.path.isfile("applications/%s/private/GITHUB_CLIENT_SECRET" % request.application):
    GITHUB_CLIENT_SECRET = open("applications/%s/private/GITHUB_CLIENT_SECRET" % request.application).read().strip()
    conf.set("apis", "github_client_secret", GITHUB_CLIENT_SECRET)

#########################################################################
## This scaffolding model makes your app work on Google App Engine too
## File is released under public domain and you can use without limitations
#########################################################################

# If SSL/HTTPS is properly configured and you want all HTTP requests to
# be redirected to HTTPS, uncomment the line below:
## request.requires_https()
# NO, this is too all-inclusive and complicates our registered apps on GitHub.
# (Its OAuth should work with either secure or insecure/test setups.)

if not request.env.web2py_runtime_gae:
    ## if NOT running on Google App Engine use SQLite or other DB
    db = DAL('sqlite://storage.sqlite',pool_size=1,check_reserved=['all'])
else:
    ## connect to Google BigTable (optional 'google:datastore://namespace')
    db = DAL('google:datastore')
    ## store sessions and tickets there
    session.connect(request, response, db=db)
    ## or store session in Memcache, Redis, etc.
    ## from gluon.contrib.memdb import MEMDB
    ## from google.appengine.api.memcache import Client
    ## session.connect(request, response, db = MEMDB(Client()))

## by default give a view/generic.extension to all actions from localhost
## none otherwise. a pattern can be 'controller/function.extension'
response.generic_patterns = ['*'] if request.is_local else []
## (optional) optimize handling of static files
# response.optimize_css = 'concat,minify,inline'
# response.optimize_js = 'concat,minify,inline'

#########################################################################
## Here is sample code if you need for
## - email capabilities
## - authentication (registration, login, logout, ... )
## - authorization (role based authorization)
## - services (xml, csv, json, xmlrpc, jsonrpc, amf, rss)
## - old style crud actions
## (more options discussed in gluon/tools.py)
#########################################################################

SECURE_SESSIONS_WITH_HTTPS = conf.getboolean("security", "secure_sessions_with_HTTPS")
# This is set to 'true' during deployment if our wildcard cert file is found. We
# assume this means all prerequisites for HTTPS/SSL are complete.

from gluon.tools import Auth, Crud, Service, PluginManager, prettydate
auth = Auth(db, secure=SECURE_SESSIONS_WITH_HTTPS)
crud, service, plugins = Crud(db), Service(), PluginManager()


#
# Simple storage for study supporting files. These are stored temporary,
# pending deposition in Dryad or another permanent repository.
#
# I'm adapting a recipe for using web2py with the jQuery-File-Upload plugin:
# http://in10min.blogspot.com/2013/04/web2py-implement-multiple-files-upload.html
#

SupportingFiles = db.define_table('supporting_files',
 Field('doc', 'upload', autodelete=True),
 #Field('thumb', 'upload', autodelete=True),
 #Field('sizeFile', 'float'),
 #Field('sessionId', 'string'),)
 Field('file_size', 'float'),
 Field('study_id', 'string'),)

#from smarthumb import SMARTHUMB
#box = (200, 200)
#SupportingFiles.thumb.compute = lambda row: SMARTHUMB(row.doc, box)


#
# OAuth2 for Github (API v3), based on the FB sample provided in gluon/contrib/login_methods/oauth20_account.py
# 

# You need to override the get_user method to match your auth provider needs.
# define the auth_table before call to auth.define_tables()
auth_table = db.define_table(
   auth.settings.table_user_name,
   Field('name', length=256, default=""),          # "<NAME>"
   Field('email', length=128, default=""),         # "<EMAIL>"
   Field('github_login', length=128, default=""),  # "chuckd"  [Github calls this 'login']
   Field('github_url', length=256, default=""),    # "https://github.com/chuckd"  [Github calls this 'html_url']
   Field('avatar_url', length=256, default=""),    # "http://0.gravatar.com/avatar/805...9689b.png"
   #Field('password', 'password', length=256, readable=False, label='Password'),
   Field('github_auth_token', length=128, default= "", writable=False, readable=False),

   ## Some fields are expected by web2py, so repeat some values above..?
   Field('first_name', length=128, default=""),
   Field('last_name', length=128, default=""),
   Field('username', length=128, default="", ),  # unique=True not allowed in sqlite3
   Field('password', 'password', length=256, readable=False, label='Password'),
   Field('registration_key', length=128, default= "", writable=False, readable=False),
   )
   # is there another 'auth_token' field here already?

auth_table.github_login.requires = IS_NOT_IN_DB(db, auth_table.github_login)
auth.define_tables()
# OR auth.define_tables(username=False, signature=False)
# see https://code.google.com/p/web2py/issues/detail?id=1260

# Looking for your app's client ID and secret in {app}/private/config
try:
    CLIENT_ID = conf.get("apis", "github_client_id")
    CLIENT_SECRET = conf.get("apis", "github_client_secret")
    REDIRECT_URI = conf.get("apis", "github_redirect_uri")
except: 
    CLIENT_ID = "CLIENT_ID_NOT_FOUND"
    CLIENT_SECRET = "CLIENT_SECRET_NOT_FOUND"
    REDIRECT_URI = "REDIRECT_URI_NOT_FOUND"

AUTH_URL="http://..."
TOKEN_URL="http://..."

from gluon import current
from gluon.contrib.login_methods.oauth20_account import OAuthAccount

class GitHubAccount(OAuthAccount):
    '''OAuth impl for GitHub'''
    # http://developer.github.com/v3/oauth/
    AUTH_URL="https://github.com/login/oauth/authorize"
    TOKEN_URL="https://github.com/login/oauth/access_token"

    def __init__(self):
        OAuthAccount.__init__(self, 
                              g=globals(),
                              client_id=CLIENT_ID,
                              client_secret=CLIENT_SECRET,
                              auth_url=self.AUTH_URL,
                              token_url=self.TOKEN_URL,
                              redirect_uri=REDIRECT_URI,
                              state=os.urandom(16).encode('hex'),
                                  # random string to detect cross-site request forgery
                              scope='public_repo')  # add ',repo' if including private repos

        # adding session here, since older OAuthAccount doesn't seem to have it.. :-/
        self.session = globals()['session']

    def get_user(self):
        '''Returns the user using the GitHub User API.'''
        ##sys.stderr.write('get_user STARTING...\n')
        access_token = self.accessToken()
        if not access_token:
            ##sys.stderr.write('get_user NO TOKEN FOUND\n')
            return None
         
        ##sys.stderr.write('get_user FOUND access_token:\n')
        ##pprint(access_token)

        ##sys.stderr.write('> get_user, finishing with this CURRENT.session.token:\n')
        ##pprint(current.session.token)
        ##sys.stderr.write('> get_user, trying SELF.session.token:\n')
        ##pprint(self.session.token)
        ##sys.stderr.write('> what about just session.token?\n')
        ##pprint(session.token)

        # fetch full user info from GitHub, to add/update user data
        h = {"Authorization" : ("token %s" % access_token)}
        try:
            user_json = requests.get(url="https://api.github.com/user", headers=h).json()
        except JSONDecodeError, e:
            raise Exception("Cannot parse oauth server response %s %s" % (e.doc, e))
            return None

        ##pprint('----------- user_json ----------')
        ##pprint(user_json)
        ##pprint('----------- auth_user_fields ----------')

        # remap to our chosen auth_user fields
        auth_user_fields = dict(name = user_json.get('name', user_json['login']),
                                email = user_json.get('email', 'EMAIL_NOT_PROVIDED'),
                                github_login = user_json['login'],
                                registration_id = user_json['login'],
                                #   required? see https://groups.google.com/forum/#!topic/web2py/yd4_yExPwXg/discussion
                                github_url = user_json['html_url'],
                                avatar_url = user_json['avatar_url'],
                                github_auth_token = access_token,
                                #   adding more (apparently) standard web2py fields, to make this work..
                                first_name = user_json['login'],
                                # skip 'name' if it's None!
                                last_name = ("(%s)" % (user_json['name'] or user_json['login'])),
                                username = user_json['login'],
                                #password = '<PASSWORD>',
                                registration_key = user_json['login'],  
                                )

        ##pprint(auth_user_fields)
        ##pprint('--------------------------------')

        return dict(auth_user_fields)


# use the class above to build a new login form
auth.settings.login_form=GitHubAccount()

# specify which auth_user fields can be modified on SECOND and subsequent logins
auth.settings.update_fields = ['name', 
                               'email', 
                               'github_login', 
                               #'registration_id', 
                               'github_url', 
                               'avatar_url', 
                               'github_auth_token', 
                               'first_name', 
                               'last_name', 
                               'username', 
                               #'password', 
                               'registration_key']

# there's no point in offer other user-management actions (we just shadow users in GitHub)
auth.settings.actions_disabled=['register', 'change_password','request_reset_password','profile']

## configure email
mail = auth.settings.mailer
mail.settings.server = 'logging' or 'smtp.gmail.com:587'
mail.settings.sender = '<EMAIL>'
mail.settings.login = 'username:password'

## configure auth policy
auth.settings.registration_requires_verification = False
auth.settings.registration_requires_approval = False
auth.settings.reset_password_requires_verification = True

#########################################################################
## Define your tables below (or better in another model file) for example
##
## >>> db.define_table('mytable',Field('myfield','string'))
##
## Fields can be 'string','text','password','integer','double','boolean'
##       'date','time','datetime','blob','upload', 'reference TABLENAME'
## There is an implicit 'id integer autoincrement' field
## Consult manual for more options, validators, etc.
##
## More API examples for controllers:
##
## >>> db.mytable.insert(myfield='value')
## >>> rows=db(db.mytable.myfield=='value').select(db.mytable.ALL)
## >>> for row in rows: print row.id, row.myfield
#########################################################################

## after defining tables, uncomment below to enable auditing
# auth.enable_record_versioning(db)

<filename>curator/models/db.py
# -*- coding: utf-8 -*-
from pprint import pprint
import sys
import os
from ConfigParser import SafeConfigParser
import requests
import json

# WARNING!  This file is a near-duplicat of webapp/models/db.py
#           Any changes here should probably be mirrored there.

conf = SafeConfigParser({})
config_file_found = None
try:
    test_config_paths = [
        "applications/%s/private/localconfig" % request.application,
        "applications/%s/private/config" % request.application,
    ]
    for test_path in test_config_paths:
        if os.path.isfile(test_path):
            config_file_found = test_path
            conf.read(test_path)
    assert 'apis' in conf.sections()
except:
    print("\n=== WEB-APP CONFIG NOT FOUND, INVALID, OR INCOMPLETE ===")
    if config_file_found == None:
        err_msg = "Webapp config not found! Expecting it in one of these locations:\n  {}".format(test_config_paths)
        print(err_msg)
        raise Exception(err_msg)
    err_msg = "Webapp config file ({}) is broken or incomplete (missing [apis] section)".format(config_file_found)
    print(err_msg)
    raise Exception(err_msg)

# add our GitHub client secret from a separate file (kept out of source repo)
if os.path.isfile("applications/%s/private/GITHUB_CLIENT_SECRET" % request.application):
    GITHUB_CLIENT_SECRET = open("applications/%s/private/GITHUB_CLIENT_SECRET" % request.application).read().strip()
    conf.set("apis", "github_client_secret", GITHUB_CLIENT_SECRET)

#########################################################################
## This scaffolding model makes your app work on Google App Engine too
## File is released under public domain and you can use without limitations
#########################################################################

# If SSL/HTTPS is properly configured and you want all HTTP requests to
# be redirected to HTTPS, uncomment the line below:
## request.requires_https()
# NO, this is too all-inclusive and complicates our registered apps on GitHub.
# (Its OAuth should work with either secure or insecure/test setups.)

if not request.env.web2py_runtime_gae:
    ## if NOT running on Google App Engine use SQLite or other DB
    db = DAL('sqlite://storage.sqlite',pool_size=1,check_reserved=['all'])
else:
    ## connect to Google BigTable (optional 'google:datastore://namespace')
    db = DAL('google:datastore')
    ## store sessions and tickets there
    session.connect(request, response, db=db)
    ## or store session in Memcache, Redis, etc.
    ## from gluon.contrib.memdb import MEMDB
    ## from google.appengine.api.memcache import Client
    ## session.connect(request, response, db = MEMDB(Client()))

## by default give a view/generic.extension to all actions from localhost
## none otherwise. a pattern can be 'controller/function.extension'
response.generic_patterns = ['*'] if request.is_local else []
## (optional) optimize handling of static files
# response.optimize_css = 'concat,minify,inline'
# response.optimize_js = 'concat,minify,inline'

#########################################################################
## Here is sample code if you need for
## - email capabilities
## - authentication (registration, login, logout, ... )
## - authorization (role based authorization)
## - services (xml, csv, json, xmlrpc, jsonrpc, amf, rss)
## - old style crud actions
## (more options discussed in gluon/tools.py)
#########################################################################

SECURE_SESSIONS_WITH_HTTPS = conf.getboolean("security", "secure_sessions_with_HTTPS")
# This is set to 'true' during deployment if our wildcard cert file is found. We
# assume this means all prerequisites for HTTPS/SSL are complete.

from gluon.tools import Auth, Crud, Service, PluginManager, prettydate
auth = Auth(db, secure=SECURE_SESSIONS_WITH_HTTPS)
crud, service, plugins = Crud(db), Service(), PluginManager()


#
# Simple storage for study supporting files. These are stored temporary,
# pending deposition in Dryad or another permanent repository.
#
# I'm adapting a recipe for using web2py with the jQuery-File-Upload plugin:
# http://in10min.blogspot.com/2013/04/web2py-implement-multiple-files-upload.html
#

SupportingFiles = db.define_table('supporting_files',
 Field('doc', 'upload', autodelete=True),
 #Field('thumb', 'upload', autodelete=True),
 #Field('sizeFile', 'float'),
 #Field('sessionId', 'string'),)
 Field('file_size', 'float'),
 Field('study_id', 'string'),)

#from smarthumb import SMARTHUMB
#box = (200, 200)
#SupportingFiles.thumb.compute = lambda row: SMARTHUMB(row.doc, box)


#
# OAuth2 for Github (API v3), based on the FB sample provided in gluon/contrib/login_methods/oauth20_account.py
# 

# You need to override the get_user method to match your auth provider needs.
# define the auth_table before call to auth.define_tables()
auth_table = db.define_table(
   auth.settings.table_user_name,
   Field('name', length=256, default=""),          # "<NAME>"
   Field('email', length=128, default=""),         # "<EMAIL>"
   Field('github_login', length=128, default=""),  # "chuckd"  [Github calls this 'login']
   Field('github_url', length=256, default=""),    # "https://github.com/chuckd"  [Github calls this 'html_url']
   Field('avatar_url', length=256, default=""),    # "http://0.gravatar.com/avatar/805...9689b.png"
   #Field('password', 'password', length=256, readable=False, label='Password'),
   Field('github_auth_token', length=128, default= "", writable=False, readable=False),

   ## Some fields are expected by web2py, so repeat some values above..?
   Field('first_name', length=128, default=""),
   Field('last_name', length=128, default=""),
   Field('username', length=128, default="", ),  # unique=True not allowed in sqlite3
   Field('password', 'password', length=256, readable=False, label='Password'),
   Field('registration_key', length=128, default= "", writable=False, readable=False),
   )
   # is there another 'auth_token' field here already?

auth_table.github_login.requires = IS_NOT_IN_DB(db, auth_table.github_login)
auth.define_tables()
# OR auth.define_tables(username=False, signature=False)
# see https://code.google.com/p/web2py/issues/detail?id=1260

# Looking for your app's client ID and secret in {app}/private/config
try:
    CLIENT_ID = conf.get("apis", "github_client_id")
    CLIENT_SECRET = conf.get("apis", "github_client_secret")
    REDIRECT_URI = conf.get("apis", "github_redirect_uri")
except: 
    CLIENT_ID = "CLIENT_ID_NOT_FOUND"
    CLIENT_SECRET = "CLIENT_SECRET_NOT_FOUND"
    REDIRECT_URI = "REDIRECT_URI_NOT_FOUND"

AUTH_URL="http://..."
TOKEN_URL="http://..."

from gluon import current
from gluon.contrib.login_methods.oauth20_account import OAuthAccount

class GitHubAccount(OAuthAccount):
    '''OAuth impl for GitHub'''
    # http://developer.github.com/v3/oauth/
    AUTH_URL="https://github.com/login/oauth/authorize"
    TOKEN_URL="https://github.com/login/oauth/access_token"

    def __init__(self):
        OAuthAccount.__init__(self, 
                              g=globals(),
                              client_id=CLIENT_ID,
                              client_secret=CLIENT_SECRET,
                              auth_url=self.AUTH_URL,
                              token_url=self.TOKEN_URL,
                              redirect_uri=REDIRECT_URI,
                              state=os.urandom(16).encode('hex'),
                                  # random string to detect cross-site request forgery
                              scope='public_repo')  # add ',repo' if including private repos

        # adding session here, since older OAuthAccount doesn't seem to have it.. :-/
        self.session = globals()['session']

    def get_user(self):
        '''Returns the user using the GitHub User API.'''
        ##sys.stderr.write('get_user STARTING...\n')
        access_token = self.accessToken()
        if not access_token:
            ##sys.stderr.write('get_user NO TOKEN FOUND\n')
            return None
         
        ##sys.stderr.write('get_user FOUND access_token:\n')
        ##pprint(access_token)

        ##sys.stderr.write('> get_user, finishing with this CURRENT.session.token:\n')
        ##pprint(current.session.token)
        ##sys.stderr.write('> get_user, trying SELF.session.token:\n')
        ##pprint(self.session.token)
        ##sys.stderr.write('> what about just session.token?\n')
        ##pprint(session.token)

        # fetch full user info from GitHub, to add/update user data
        h = {"Authorization" : ("token %s" % access_token)}
        try:
            user_json = requests.get(url="https://api.github.com/user", headers=h).json()
        except JSONDecodeError, e:
            raise Exception("Cannot parse oauth server response %s %s" % (e.doc, e))
            return None

        ##pprint('----------- user_json ----------')
        ##pprint(user_json)
        ##pprint('----------- auth_user_fields ----------')

        # remap to our chosen auth_user fields
        auth_user_fields = dict(name = user_json.get('name', user_json['login']),
                                email = user_json.get('email', 'EMAIL_NOT_PROVIDED'),
                                github_login = user_json['login'],
                                registration_id = user_json['login'],
                                #   required? see https://groups.google.com/forum/#!topic/web2py/yd4_yExPwXg/discussion
                                github_url = user_json['html_url'],
                                avatar_url = user_json['avatar_url'],
                                github_auth_token = access_token,
                                #   adding more (apparently) standard web2py fields, to make this work..
                                first_name = user_json['login'],
                                # skip 'name' if it's None!
                                last_name = ("(%s)" % (user_json['name'] or user_json['login'])),
                                username = user_json['login'],
                                #password = '<PASSWORD>',
                                registration_key = user_json['login'],  
                                )

        ##pprint(auth_user_fields)
        ##pprint('--------------------------------')

        return dict(auth_user_fields)


# use the class above to build a new login form
auth.settings.login_form=GitHubAccount()

# specify which auth_user fields can be modified on SECOND and subsequent logins
auth.settings.update_fields = ['name', 
                               'email', 
                               'github_login', 
                               #'registration_id', 
                               'github_url', 
                               'avatar_url', 
                               'github_auth_token', 
                               'first_name', 
                               'last_name', 
                               'username', 
                               #'password', 
                               'registration_key']

# there's no point in offer other user-management actions (we just shadow users in GitHub)
auth.settings.actions_disabled=['register', 'change_password','request_reset_password','profile']

## configure email
mail = auth.settings.mailer
mail.settings.server = 'logging' or 'smtp.gmail.com:587'
mail.settings.sender = '<EMAIL>'
mail.settings.login = 'username:password'

## configure auth policy
auth.settings.registration_requires_verification = False
auth.settings.registration_requires_approval = False
auth.settings.reset_password_requires_verification = True

#########################################################################
## Define your tables below (or better in another model file) for example
##
## >>> db.define_table('mytable',Field('myfield','string'))
##
## Fields can be 'string','text','password','integer','double','boolean'
##       'date','time','datetime','blob','upload', 'reference TABLENAME'
## There is an implicit 'id integer autoincrement' field
## Consult manual for more options, validators, etc.
##
## More API examples for controllers:
##
## >>> db.mytable.insert(myfield='value')
## >>> rows=db(db.mytable.myfield=='value').select(db.mytable.ALL)
## >>> for row in rows: print row.id, row.myfield
#########################################################################

## after defining tables, uncomment below to enable auditing
# auth.enable_record_versioning(db)

# -*- coding: utf-8 -*- # WARNING!  This file is a near-duplicat of webapp/models/db.py #           Any changes here should probably be mirrored there. # add our GitHub client secret from a separate file (kept out of source repo) ######################################################################### ## This scaffolding model makes your app work on Google App Engine too ## File is released under public domain and you can use without limitations ######################################################################### # If SSL/HTTPS is properly configured and you want all HTTP requests to # be redirected to HTTPS, uncomment the line below: ## request.requires_https() # NO, this is too all-inclusive and complicates our registered apps on GitHub. # (Its OAuth should work with either secure or insecure/test setups.) ## if NOT running on Google App Engine use SQLite or other DB ## connect to Google BigTable (optional 'google:datastore://namespace') ## store sessions and tickets there ## or store session in Memcache, Redis, etc. ## from gluon.contrib.memdb import MEMDB ## from google.appengine.api.memcache import Client ## session.connect(request, response, db = MEMDB(Client())) ## by default give a view/generic.extension to all actions from localhost ## none otherwise. a pattern can be 'controller/function.extension' ## (optional) optimize handling of static files # response.optimize_css = 'concat,minify,inline' # response.optimize_js = 'concat,minify,inline' ######################################################################### ## Here is sample code if you need for ## - email capabilities ## - authentication (registration, login, logout, ... ) ## - authorization (role based authorization) ## - services (xml, csv, json, xmlrpc, jsonrpc, amf, rss) ## - old style crud actions ## (more options discussed in gluon/tools.py) ######################################################################### # This is set to 'true' during deployment if our wildcard cert file is found. We # assume this means all prerequisites for HTTPS/SSL are complete. # # Simple storage for study supporting files. These are stored temporary, # pending deposition in Dryad or another permanent repository. # # I'm adapting a recipe for using web2py with the jQuery-File-Upload plugin: # http://in10min.blogspot.com/2013/04/web2py-implement-multiple-files-upload.html # #Field('thumb', 'upload', autodelete=True), #Field('sizeFile', 'float'), #Field('sessionId', 'string'),) #from smarthumb import SMARTHUMB #box = (200, 200) #SupportingFiles.thumb.compute = lambda row: SMARTHUMB(row.doc, box) # # OAuth2 for Github (API v3), based on the FB sample provided in gluon/contrib/login_methods/oauth20_account.py # # You need to override the get_user method to match your auth provider needs. # define the auth_table before call to auth.define_tables() # "<NAME>" # "<EMAIL>" # "chuckd"  [Github calls this 'login'] # "https://github.com/chuckd"  [Github calls this 'html_url'] # "http://0.gravatar.com/avatar/805...9689b.png" #Field('password', 'password', length=256, readable=False, label='Password'), ## Some fields are expected by web2py, so repeat some values above..? # unique=True not allowed in sqlite3 # is there another 'auth_token' field here already? # OR auth.define_tables(username=False, signature=False) # see https://code.google.com/p/web2py/issues/detail?id=1260 # Looking for your app's client ID and secret in {app}/private/config OAuth impl for GitHub # http://developer.github.com/v3/oauth/ # random string to detect cross-site request forgery # add ',repo' if including private repos # adding session here, since older OAuthAccount doesn't seem to have it.. :-/ Returns the user using the GitHub User API. ##sys.stderr.write('get_user STARTING...\n') ##sys.stderr.write('get_user NO TOKEN FOUND\n') ##sys.stderr.write('get_user FOUND access_token:\n') ##pprint(access_token) ##sys.stderr.write('> get_user, finishing with this CURRENT.session.token:\n') ##pprint(current.session.token) ##sys.stderr.write('> get_user, trying SELF.session.token:\n') ##pprint(self.session.token) ##sys.stderr.write('> what about just session.token?\n') ##pprint(session.token) # fetch full user info from GitHub, to add/update user data ##pprint('----------- user_json ----------') ##pprint(user_json) ##pprint('----------- auth_user_fields ----------') # remap to our chosen auth_user fields #   required? see https://groups.google.com/forum/#!topic/web2py/yd4_yExPwXg/discussion #   adding more (apparently) standard web2py fields, to make this work.. # skip 'name' if it's None! #password = '<PASSWORD>', ##pprint(auth_user_fields) ##pprint('--------------------------------') # use the class above to build a new login form # specify which auth_user fields can be modified on SECOND and subsequent logins #'registration_id', #'password', # there's no point in offer other user-management actions (we just shadow users in GitHub) ## configure email ## configure auth policy ######################################################################### ## Define your tables below (or better in another model file) for example ## ## >>> db.define_table('mytable',Field('myfield','string')) ## ## Fields can be 'string','text','password','integer','double','boolean' ##       'date','time','datetime','blob','upload', 'reference TABLENAME' ## There is an implicit 'id integer autoincrement' field ## Consult manual for more options, validators, etc. ## ## More API examples for controllers: ## ## >>> db.mytable.insert(myfield='value') ## >>> rows=db(db.mytable.myfield=='value').select(db.mytable.ALL) ## >>> for row in rows: print row.id, row.myfield ######################################################################### ## after defining tables, uncomment below to enable auditing # auth.enable_record_versioning(db)