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)
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()
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")
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')))
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()
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)
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
def redirect404(request, **errorDict): return redirect(URL(r=request, c='error404', f='index', vars=errorDict))
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)