Example #1
0
def add_social_network():
    """
    An SQL form which stores the information related to a social network.
    Admin can provide data like client_key, secret_key, redirect_url in this
    form to be saved in db table social_network
    :return:
    """
    form = SQLFORM(db.social_network)
    # form['_style'] = 'border:1px solid black; color:#000000'
    form['_class'] = 'table form-horizontal'
    form.add_button('Manage Social Networks', URL('user', 'manage_social_network'))
    if form.process().accepted:
        link = form.vars['redirectUrl']
        form_data = {'vendorId': form.vars['vendorId'],
                     'clientKey': form.vars['clientKey'],
                     'appUrl': form.vars['appUrl'],
                     'redirectUrl': form.vars['redirectUrl'],
                     'authUrl': form.vars['authUrl']}
        session.form_data = form_data
        redirect(link)
    elif form.errors:
        response.flash = 'Form has errors!'
    else:
        response.flash = 'Please fill out the form...'
    return dict(form=form)
Example #2
0
def impersonate():
    if request.args:
        impersonated_id = request.args[0]
        if not auth.has_permission('impersonate', db.user, impersonated_id):
            auth.add_permission(1, 'impersonate', db.user, impersonated_id)
        auth.impersonate(user_id=impersonated_id)
        redirect(URL('dashboard', 'index'))
    return dict()
Example #3
0
def dice_oauth_callback():
    """
    Callback for the implicit flow: https://tools.ietf.org/html/rfc6749#section-4.2.2

    Inputs: access_token, refresh_token, token_type, user_id.

    If no getTalent user exists with the given Dice user_id or email address, will auto-create the user & domain. Then, log them in.
    If a getTalent user is found with the given email but does not have a Dice ID, will still log them in.

    """

    # Input validation
    access_token = request.vars.access_token
    refresh_token = request.vars.refresh_token
    token_type = request.vars.token_type
    dice_user_id = request.vars.user_id
    dice_env = request.vars.environment or 'prod'

    if not access_token or not refresh_token or not token_type or not dice_user_id:
        email_error_to_admins(body="Received a request to dice_oauth_callback with missing parameter",
                              subject="dice_oauth_callback: Missing input")
        redirect("https://www.gettalent.com")

    # Query Dice API for user info
    from TalentDiceClient import query_dice_user_id

    user_info = query_dice_user_id(dice_user_id=dice_user_id, dice_access_token=access_token,
                                   dice_refresh_token=refresh_token, dice_env=dice_env)
    if not user_info:
        logger.error("dice_oauth_callback(%s): Failed to query Dice API", request.vars)
        email_error_to_admins(body="Failed to query Dice API during dice_oauth_callback. See error logs for details",
                              subject="dice_oauth_callback: Querying Dice API")
        redirect("https://www.gettalent.com")
    dice_company_id = user_info['dice_company_id']
    first_name = user_info['first_name']
    last_name = user_info['last_name']
    email = user_info['email']

    # Get or create the user
    from TalentUsers import get_or_create_dice_user

    user_row = get_or_create_dice_user(email, first_name, last_name, dice_user_id, dice_company_id, access_token,
                                       refresh_token, dice_env=dice_env)

    if user_row:
        # Log in user & go to Dashboard
        logger.info("Logging in user %s from Dice", user_row.email)
        auth.login_and_set_dice_tokens(user_row, access_token, refresh_token)
        redirect(URL('web', 'dashboard', 'index'))
        return dict(message='Success')
    else:
        # If user unknown or user creation failed, redirect to gettalent.com
        logger.error("dice_oauth_callback(request.vars=%s): User creation failed", request.vars)
        email_error_to_admins(body="User auto-creation failed in dice_oauth_callback",
                              subject="dice_oauth_callback: Auto-create user")
        redirect("https://www.gettalent.com")
Example #4
0
def request_reset_password():
    if request.env.request_method == 'POST':
        import datetime

        email = request.vars.email
        if email:
            # Check the email existence on the database
            valid_email = db(db.user.email == email).select().first()
            if not valid_email:
                session.flash = 'No user with email %s found!' % email
                redirect(URL('user', 'request_reset_password'))
            # If there is registation key, user has not yet activated the account.
            registration_key = valid_email.registration_key
            # Check the user account activation via registration key.
            if registration_key:
                session.flash = 'Password reset not allowed: Your registration is pending, please check the email to activate the account'
                redirect(URL('user', 'request_reset_password'))
            expiration = valid_email.expiration
            today_date = datetime.datetime.today()
            # Check the expiration has given to the account and with current date
            if expiration and expiration < today_date:
                session.flash = "Your account has expired. Please contact your account administrator for details."
                redirect(URL('user', 'request_reset_password'))

    return dict(form=auth.request_reset_password(next=URL('user', 'request_reset_password')))
Example #5
0
def set_new_password():
    """
    Get registration key from URL params
    Get user email from request params

    If user in db has matching registration key, allow current user to set new password
        If user password matches,
            Set password, then redirect to login screen with message confirming new password change
        else,
            return error message

    """
    registration_key = request.vars.registration_key
    email = request.vars.email

    password1 = request.vars.password1 or ''
    password2 = request.vars.password2 or ''

    # validate password for Caps, Number, and 8-char length
    is_valid_password = len(re.findall(r'[A-Z]', password1)) and len(re.findall(r'[0-9]', password1)) and (
        len(password1) > 7)

    user = db(db.user.email == email).select().first()
    if not user:
        session.flash = 'No user with email %s found!' % email
        redirect(URL('user', 'login'))
    elif user.registration_key == registration_key and user.registration_key:
        if not password1 or not password2:
            # user hasn't submitted their password
            return dict(registration_key=registration_key, email=email)

        elif not is_valid_password:
            response.flash = 'Password is not valid: please follow the password requirements listed below.'
            return dict(registration_key=registration_key, email=email)

        elif password1 == password2:
            password = hash_password(password1)
            user.update_record(password=password, registration_key='')
            # redirect to login page, tell them their new password has been set.
            session.flash = 'New password saved! Please login to continue.'
            redirect(URL('user', 'login'))
        else:
            # passwords don't match, return error message telling them their passwords don't match
            response.flash = 'Your passwords must match! Please re-enter them below.'
            return dict(registration_key=registration_key, email=email)
    else:
        # redirect user to login form, tell them their registration key is incorrect
        session.flash = 'Your registration key is incorrect!'
        redirect(URL('user', 'login'))

    return dict()
Example #6
0
    def apply_method(self, r, **attr):
        """
            Entry point for REST interface

            Args:
                r: the S3Request
                attr: controller attributes
        """

        wizard = r.resource.get_config("wizard") # Should be a sub-class of S3CrudWizard
        if not wizard:
            s3_redirect_default(r.url(method = ""))

        get_vars = r.get_vars
        get_vars_get = get_vars.get

        delete = get_vars_get("delete")
        if delete:
            component = r.component
            if component:
                # Delete a Component record
                tablename = component.tablename
                dresource = current.s3db.resource(tablename, id=delete)

                # Deleting in this resource allowed at all?
                deletable = dresource.get_config("deletable", True)
                if not deletable:
                    r.error(403, current.ERROR.NOT_PERMITTED)

                # Permitted to delete this record?
                authorised = current.auth.s3_has_permission("delete",
                                                            dresource.table,
                                                            record_id = delete)
                if not authorised:
                    r.unauthorised()

                # Delete it
                numrows = dresource.delete(format = r.representation)
                if numrows > 1:
                    message = "%s %s" % (numrows,
                                         current.T("records deleted"))
                elif numrows == 1:
                    message = self.crud_string(tablename,
                                               "msg_record_deleted")
                else:
                    r.error(404, dresource.error)
                del get_vars["delete"]
                current.session.confirmation = message
                redirect(URL(args = r.args,
                             vars = get_vars,
                             ))

        current_page = get_vars_get("page")
        if not current_page:
            # Use the 1st page
            get_vars["page"] = current_page = wizard.pages[0]["page"]

        # Allow the Wizard class access to the Method methods
        wizard.method = self

        # Hide other navigation to keep focus on the workflow
        current.menu.main = ""
        current.menu.options = None

        # Select the View template
        current.response.view = self._view(r, "wizard.html")

        return wizard(r, **attr)
Example #7
0
class NodeManager(ElementManager):
    """Class to be used when interacting with nodes.
    All the node handling / CRUD / .. should pass from this class
    instead of using the DAL directly, in order to correctly handle
    revisions / language and multi-table data storage.
    """

    ## Standard CRUD -----------------------------------------------------------

    def create(self, values, language=None):
        """Create a new node, using values from the ``values`` object.
        
        If ``values`` is a ``NodeEntity``, multiple versions may be created,
        else, just a first revision containing selected data is created
        and set as translation source.
        
        :param values: Values to be stored for the first version of the node.
        :type values: one of (``NodeEntity``, ``NodeVersion``,
            ``gluon.storage.Storage``, ``dict``)
        :param language: The initial language for the node. Defaults
            to ``values._language``, if set, or to the current language.
        :return: the ID of the newly created node
        """
        raise NotImplementedError

    def read(self, node_id, revision=None, language=None):
        """Load a given node object, by id.
        
        :return: A ``NodeEntity`` object containing values for the whole node.
        """

        return NodeEntity(db_row=self.db.node[node_id],
                          cmsdb=self._cmsdb,
                          default_language=language,
                          default_revision=revision)

    def update(self, values, node_id=None):
        """Update the selected node.
        
        :param values: a ``NodeEntity``
        :param node_id: Id of the node to be updated.
            Defaults to ``values._node_id``
        """
        pass

    def delete(self, node_id):
        """Delete a whole node, including all its version / related data.
        
        :param node_id: Id of the node to be deleted
        """
        pass

    ## Versions management =====================================================

    def create_version(self,
                       values,
                       node_id=None,
                       revision_id=None,
                       language=None):
        """Create a new veersion for the node.
        
        :param values: Values to be stored for the new version.
        :type values: ``NodeVersion`` or ``gluon.storage.Storage`` or ``dict``
        :param node_id: Node for which to create version.
            Defaults to ``values._node_id``. This is **requried**
        :param revision_id: The revision ID for which to create new version.
            * If set to ``None``, defaults to latest revision
            * If set to ``-1``, create a new revision
            * If set to an ``int``, check that is a valid revision_id.
        :param language: The language of the new version.
            Defaults to current language.
        """
        pass

    def read_version(self, node_id, revision_id=None, language=None):
        """Gets the selected version for the selected node.
        
        :param node_id: Selected node id.
        :param revision_id: Selected node revision. Defaults to latest
            published version.
        :param language: Selected language. Defaults to the first found in:
            * Current language
            * Default site language (?)
            * Translation source for the revision
        """
        pass

    def update_version(self,
                       values,
                       node_id=None,
                       revision_id=None,
                       language=None):
        """Update the selected node/version/translation.
        
        :param values: Values to be set for the node.
        :type values: ``NodeVersion`` or ``gluon.storage.Storage`` or ``dict``
        :param node_id: Id of the node to be updated
            Defaults to ``values.node_id``
        :param revision_id: Node revision to be updated.
            Defaults to ``values._revision_id``.
        :param language: Language to be updated.
             Defaults to values._language
        
        .. WARNING:: Allowing optional ``revision_id`` and ``language`` is
            potentially risky -> should we allow that?
        """

    def delete_version(self, node_id, revision_id=None, language=None):
        """Delete the selected node version / revision / translation.
        
        :param node_id: The node for which to delete version(s)
        :param revision_id: Limit deletion to versions for this revision
        :param language: Limit deletion to versions for this language
        """
        pass

    ## Querying / searching ====================================================

    def search(self, query=None, orderby=None, language=None):
        """Search for nodes.
        """
        db = self.db
        return [
            NodeEntity(db_row=row, cmsdb=self._cmsdb)
            for row in db(query).select(db.node.ALL, orderby=orderby)
        ]

    ## CRUD functions ==========================================================

    def form_create(self, node_type=None, defaults=None):
        return self.edit_form('create', node_type=node_type, defaults=defaults)

    def form_update(self, node_id, revision_id=None, language=None):
        return self.edit_form('update',
                              node_id=node_id,
                              revision_id=revision_id,
                              language=language)

    def edit_form(self,
                  action,
                  node_type=None,
                  node_id=None,
                  revision_id=None,
                  language=None,
                  defaults=None):
        """Node manipulation form.
        
        :param action: The action to be performed on node:
            one of ``create|update|translate``
        :param node_type: Only for ``create``, the type of node
            to be created
        :param node_id: Only for ``update|translate``, the id of node
            to be updated
        :param revision_id: Only for ``update|translate``, the id
            of the revision on which to work. Defaults to latest revision.
            Must be a valid revision id for this node.
        :param language: The language in which to write/translate the node.
            Defaults to current language or 'neutral'.
        :param defaults: A dict or dict-like of values to be set as
            defaults for node creation.
        """

        db = self.db
        T = current.T

        if not defaults:
            defaults = {}

        ## Validate arguments
        node_types = cms_settings.list_node_types()

        if action == 'create':
            ## We need only a valid node type
            if node_type not in node_types.keys():
                raise ValueError, "Wrong node type %r must be one of %s" % (
                    node_type, ", ".join(node_types.keys()))
        elif action == 'update':
            ## node_id must be a valid node
            ## if specified, revision_id must be a valid revision for this node
            ## if specified, language must exist
            node = self.read(node_id=node_id,
                             revision=revision_id,
                             language=language)
            #revision_id = node.get_revision(revision_id, language)
            defaults.update(node.values)
        elif action == 'translate':
            ## We need a language in which to translate plus a language
            ## to be used as "translation base" to read values from.
            pass

        ## To store components of the form
        _form_components = {}

        ## Tables to be used to generate form.
        ## TODO: Load all the db.tables matching node_fields_* and node_<type>_fields_*
        _component_tables = ['node', 'node_revision', 'node_fields_base']

        ## Set defaults --------------------------------------------------------
        db.node.type.default = node_type
        db.node.type.readable = \
        db.node.type.writable = False

        db.node_revision.node.requires = None
        db.node_revision.node.readable = \
        db.node_revision.node.writable = False

        db.node_fields_base.node_revision.requires = None
        db.node_fields_base.node_revision.readable = \
        db.node_fields_base.node_revision.writable = False

        ##TODO: set defaults from the `defaults` variable.

        ## Retrieve components from tables -------------------------------------
        for table in _component_tables:

            ## Prepare default values for fields
            if defaults.has_key(table):
                for field in db[table].fields:
                    try:
                        db[table][field].default = defaults[table][field]
                    except KeyError, e:
                        pass

            ## Create SQLFORM from the table
            _form_components[table] = SQLFORM.factory(
                db[table],
                buttons=[],
                formstyle='divs' if table not in ['node', 'node_revision'] else
                'table3cols').components

            ## Change field names by adding ``<tablename>--`` prefix
            for ilev, comp in descend_tree(_form_components[table]):
                if isinstance(comp,
                              INPUT) and comp.attributes.has_key('_name'):
                    ## Change field name
                    comp.attributes['_name'] = '%s--%s' % (
                        table, comp.attributes['_name'])

        ## Build the form ------------------------------------------------------

        ## TODO: We need a custom SQLFORM to generate this!

        form = FORM(

            ## Fields from node_fields_base table
            DIV(*_form_components['node_fields_base'],
                _class='expanding-form'),

            ## Standard fields from node/node_revision
            FIELDSET(LEGEND('Node'),
                     DIV(*_form_components['node']),
                     _class='collapsible start-collapsed'),
            FIELDSET(LEGEND('Node revision'),
                     DIV(*_form_components['node_revision']),
                     _class='collapsible start-collapsed'),

            ## Other control fields
            FIELDSET(
                LEGEND('Control fields'),
                *SQLFORM.factory(DAL(None).define_table(
                    'no_table',
                    Field('create_new_revision', 'boolean', default=False),
                    Field('content_language',
                          'string',
                          default=cms_settings.content_default_language,
                          requires=IS_IN_SET(cms_settings.content_languages,
                                             zero=None)),
                ),
                                 buttons=[]).components,
                _class='collapsible start-collapsed'),

            ## Submit button
            INPUT(_type='submit', _value=T('Submit')),

            ## Hidden fields
            hidden={
                'action': action,
                'node_id': node_id,
                'revision_id': revision_id,
                'language': language,
            },
        )

        ## Process the form ----------------------------------------------------
        if form.process().accepted:
            ## Split vars into their original groups
            _var_groups = {}

            for var, val in form.vars.items():
                if var.find('--') > 0:
                    group, var = var.split('--', 2)
                else:
                    group = 'default'
                if not _var_groups.has_key(group):
                    _var_groups[group] = {}
                _var_groups[group][var] = val

            ## Here, insert stuff into tables, etc.
            form.components.append(BEAUTIFY(_var_groups))

            if action == 'create':
                ## Create a new node

                try:
                    ## Create node
                    content_language = _var_groups['default'][
                        'content_language']
                    _var_groups['node']['type'] = node_type
                    node_id = db.node.insert(**_var_groups['node'])

                    _var_groups['node_revision']['node'] = node_id
                    _var_groups['node_revision'][
                        'translation_base'] = content_language
                    node_revision_id = db.node_revision.insert(
                        **_var_groups['node_revision'])

                    ## Create node revision
                    _var_groups['node_fields_base'][
                        'node_revision'] = node_revision_id

                    ## Insert into node_fields_base
                    if content_language:
                        ## Insert data in t9n_node_fields_base too, with new language
                        _vals = {'node_revision': node_revision_id}
                        _t9n_vals = _var_groups['node_fields_base'].copy()

                        ## Create empty record in node_fields_base (language neutral)
                        node_fields_base_id = db.node_fields_base.insert(
                            **_vals)

                        ## Create translated record in t9n_node_fields_base
                        del _t9n_vals['node_revision']
                        _t9n_vals['record'] = node_fields_base_id
                        _t9n_vals['language'] = content_language
                        db.t9n_node_fields_base.insert(**_t9n_vals)
                    else:
                        ## Insert just in node_fields_base (language neutral)
                        _vals = _var_groups['node_fields_base'].copy()
                        db.node_fields_base.insert(**_vals)
                except Exception, e:
                    ## Error while trying to create node.
                    ## Rollback and display error message
                    ## -> we should present prefilled form to the user!
                    current.response.flash = "Something went wrong!"
                    db.rollback()
                    raise
                else:
                    current.session.flash = "New node was created - id %d" % node_id
                    db.commit()
                    ## Go to node page
                    redirect(CMS_URL('node', node_id))

            elif action == 'update':
                ## * Ensure the node exists
                ## * Ensure the node revision exists
                ## * Ensure there already is a version for that language!
                ##   -> this may be tricky.. shoud we handle this or just
                ##      add the new translation for the specified language?
                ##   In the latter case, we don't need the 'translate' action
                ##   anymore..
                ## * If the create_new_revision checkbox is checked,
                ##   we should create a new revision.

                if _var_groups['default']['create_new_revision']:
                    ## Create a new revision
                    pass

                else:
                    ## Just update

                    ## Update the selected node
                    ## Update the node revision record
                    ## Update the extra fields for the selected node

                    pass

                pass

            elif action == 'translate':
                pass
Example #8
0
def redirect404(request, **errorDict):
    return redirect(URL(r=request, c='error404', f='index', vars=errorDict))
Example #9
0
def login():
    if auth.is_logged_in():
        redirect(URL('dashboard', 'index', host=True))

    response.title = "Login"
    response.files.append(URL('static', 'js/jquery.reject.js'))
    response.files.append(URL('static', 'css/jquery.reject.css'))

    # noinspection PyUnusedLocal,PyProtectedMember
    def email_widget(field, value):
        return INPUT(_name=field.name,
                     _id="%s_%s" % (field._tablename, field.name),
                     _class="span12",
                     _type="text",
                     _placeholder="Email Address",
                     requires=field.requires)

    db.user.email.widget = email_widget

    # noinspection PyProtectedMember,PyUnusedLocal
    def password_widget(field, value):
        return INPUT(_name=field.name,
                     _id="%s_%s" % (field._tablename, field.name),
                     _class="span12",
                     _placeholder="Password",
                     _type="password",
                     requires=field.requires)

    db.user.password.widget = password_widget
    if request.vars.email and request.vars.password:
        email = request.vars.email.strip()
        if auth.login_bare(request.vars.email, request.vars.password):
            user = db(db.user.email == email).select(db.user.ALL).first()

            # Get Bearer Token from Talent AuthService
            import requests
            params = dict(grant_type="password", username=request.vars.email, password=request.vars.password)
            try:
                auth_service_token_response = requests.post(current.OAUTH_SERVER,
                                                            params=params, auth=(current.OAUTH_CLIENT_ID, current.OAUTH_CLIENT_SECRET)).json()
                if not (auth_service_token_response.get(u'access_token') and auth_service_token_response.get(u'refresh_token')):
                    logger.error("Either Access Token or Refresh Token is missing")
                else:
                    from TalentUsers import store_auth_service_tokens_in_session
                    store_auth_service_tokens_in_session(auth_service_token_response)
            except Exception as e:
                logger.exception("Couldn't get Bearer Token, %s" % e.message)

            # Check to see if user has already expired
            if user.expiration and user.expiration < datetime.datetime.now():
                session.auth = None
                session.flash = 'Your account has expired. Please contact your account administrator for details.'

                redirect(URL('user', 'login'))
                return dict()

            web_auth_cas = db(db.web_auth_cas.user_id == user.id).select().first()
            if not web_auth_cas:
                # Make new entry in auth_cas table
                ticket = "ST-" + web2py_uuid()
                db.web_auth_cas.update_or_insert(db.web_auth_cas.user_id == user.id, user_id=user.id,
                                                 service='talent_web',
                                                 ticket=ticket, renew='T')
        else:
            # Try logging in with Dice
            auth.dice_login_bare(email, request.vars.password)

    next_login = request.get_vars._next or URL('dashboard', 'index')

    form = auth.login(next=next_login)

    return dict(form=form)