def claim_user_post(node, **kwargs): """View for claiming a user from the X-editable form on a project page. """ reqdata = request.json # Unreg user user = User.load(reqdata['pk']) unclaimed_data = user.get_unclaimed_record(node._primary_key) # Submitted through X-editable if 'value' in reqdata: # Submitted email address email = reqdata['value'].lower().strip() claimer = get_user(email=email) if claimer and claimer.is_registered: send_claim_registered_email(claimer=claimer, unreg_user=user, node=node) else: send_claim_email(email, user, node, notify=True) # TODO(sloria): Too many assumptions about the request data. Just use elif 'claimerId' in reqdata: # User is logged in and confirmed identity claimer_id = reqdata['claimerId'] claimer = User.load(claimer_id) send_claim_registered_email(claimer=claimer, unreg_user=user, node=node) email = claimer.username else: raise HTTPError(http.BAD_REQUEST) return { 'status': 'success', 'email': email, 'fullname': unclaimed_data['name'] }
def claim_user_post(node, **kwargs): """ View for claiming a user from the X-editable form on a project page. :param node: the project node :return: """ request_data = request.json # The unclaimed user unclaimed_user = User.load(request_data["pk"]) unclaimed_data = unclaimed_user.get_unclaimed_record(node._primary_key) # Claimer is not logged in and submit her/his email through X-editable, stored in `request_data['value']` if "value" in request_data: email = request_data["value"].lower().strip() claimer = get_user(email=email) # registered user if claimer and claimer.is_registered: send_claim_registered_email(claimer, unclaimed_user, node) # unregistered user else: send_claim_email(email, unclaimed_user, node, notify=True) # Claimer is logged in with confirmed identity stored in `request_data['claimerId']` elif "claimerId" in request_data: claimer_id = request_data["claimerId"] claimer = User.load(claimer_id) send_claim_registered_email(claimer, unclaimed_user, node) email = claimer.username else: raise HTTPError(http.BAD_REQUEST) return {"status": "success", "email": email, "fullname": unclaimed_data["name"]}
def get_most_in_common_contributors(auth, node, **kwargs): node_contrib_ids = set(node.contributors._to_primary_keys()) try: n_contribs = int(request.args.get('max', None)) except (TypeError, ValueError): n_contribs = settings.MAX_MOST_IN_COMMON_LENGTH contrib_counts = Counter(contrib_id for node in auth.user.node__contributed for contrib_id in node.contributors._to_primary_keys() if contrib_id not in node_contrib_ids) active_contribs = itertools.ifilter( lambda c: User.load(c[0]).is_active, contrib_counts.most_common() ) limited = itertools.islice(active_contribs, n_contribs) contrib_objs = [(User.load(_id), count) for _id, count in limited] contribs = [ utils.add_contributor_json(most_contrib, auth.user) for most_contrib, count in sorted(contrib_objs, key=lambda t: (-t[1], t[0].fullname)) ] return {'contributors': contribs}
def do_registrar(): """ """ _auth = Auth() if not _auth.is_login: errors = [] #errores #validacion de campos vacios _username = request.forms.get('username') if _username == "": errors.append("El campo Usuario esta vacio") #validacion de contrasenias _password = request.forms.get('password') repassword = request.forms.get('repassword') if len(_password) < 8 or len(_password) >= 16: errors.append("la contrasenia debe tener entre 8 y 16 caracteres") if _password != repassword: errors.append("Las contrasenias no coinciden") _name = request.forms.get('name') if _name == "": errors.append("El campo Nombre esta vacio") _email = request.forms.get('email') if _email == "": errors.append("El campo Email esta vacio") if len(errors) == 0: #validacion de que no exista el usuario query = db.GqlQuery("SELECT * FROM User WHERE username = :1", _username) if query.count() != 0: errors.append("El nombre de usuarios \"%s\" ya existe" %_username) form_error = True else: user = User( username = _username, password = _password, name = _name, email = _email, ) user.put() return template("auth/registrar-ok.html") else: form_error = True #si llego hasta aqui hay algun tipo de errors data = { "errors" : errors, "form_error": form_error, "username": _username, "name": _name, "email": _email, } return template("auth/registrar.html", data) else: message = "Error ya has iniciado Session con la cuenta \"%s\" " %_auth.is_login() message += "en caso de querer proceder por fabor cierra la session actual." return template("message.html", {'message': message} )
def get_most_in_common_contributors(auth, node, **kwargs): node_contrib_ids = set(node.contributors._to_primary_keys()) try: n_contribs = int(request.args.get('max', None)) except (TypeError, ValueError): n_contribs = settings.MAX_MOST_IN_COMMON_LENGTH contrib_counts = Counter( contrib_id for node in auth.user.node__contributed for contrib_id in node.contributors._to_primary_keys() if contrib_id not in node_contrib_ids) active_contribs = itertools.ifilter(lambda c: User.load(c[0]).is_active, contrib_counts.most_common()) limited = itertools.islice(active_contribs, n_contribs) contrib_objs = [(User.load(_id), count) for _id, count in limited] contribs = [ profile_utils.add_contributor_json(most_contrib, auth.user) for most_contrib, count in sorted(contrib_objs, key=lambda t: (-t[1], t[0].fullname)) ] return {'contributors': contribs}
def set_node_many_to_many_on_users(page_size=5000): print 'Starting {}...'.format(sys._getframe().f_code.co_name) user_count = 0 m2m_count = 0 start = datetime.now() total = MODMUser.find(build_query(m2m_node_fields, MODMUser)).count() print '{} Users'.format(total) while user_count < total: with transaction.atomic(): for modm_user in MODMUser.find( build_query(m2m_node_fields, MODMUser)).sort( '-date_registered')[user_count:page_size + user_count]: django_user = User.objects.get( pk=modm_to_django[modm_user._id]) for m2m_node_field in m2m_node_fields: try: attr = getattr(django_user, m2m_node_field) except AttributeError as ex: # node field doesn't exist on user pass else: # node field exists, do the stuff django_pks = [] for modm_m2m_value in getattr(modm_user, m2m_node_field, []): if isinstance(modm_m2m_value, MODMNode): django_pks.append( modm_to_django[modm_m2m_value._id]) elif isinstance(modm_m2m_value, basestring): django_pks.append( modm_to_django[modm_m2m_value]) elif isinstance(modm_m2m_value, Pointer): django_pks.append( modm_to_django[modm_m2m_value.node._id]) else: # wth print '\a' # bells! print '\a' print '\a' print '\a' print '\a' print '\a' print '\a' import bpdb bpdb.set_trace() if len(django_pks) > 0: attr.add(*django_pks) m2m_count += len(django_pks) user_count += 1 if user_count % page_size == 0 or user_count == total: print 'Through {} users and {} m2m'.format( user_count, m2m_count) print 'Done with {} in {} seconds...'.format( sys._getframe().f_code.co_name, (datetime.now() - start).total_seconds())
def set_node_many_to_many_on_users(page_size=5000): print 'Starting {}...'.format(sys._getframe().f_code.co_name) user_count = 0 m2m_count = 0 start = datetime.now() total = MODMUser.find(build_query(m2m_node_fields, MODMUser)).count() print '{} Users'.format(total) while user_count < total: with transaction.atomic(): for modm_user in MODMUser.find(build_query( m2m_node_fields, MODMUser)).sort('-date_registered')[ user_count:page_size + user_count]: django_user = User.objects.get( pk=modm_to_django[modm_user._id]) for m2m_node_field in m2m_node_fields: try: attr = getattr(django_user, m2m_node_field) except AttributeError as ex: # node field doesn't exist on user pass else: # node field exists, do the stuff django_pks = [] for modm_m2m_value in getattr(modm_user, m2m_node_field, []): if isinstance(modm_m2m_value, MODMNode): django_pks.append(modm_to_django[ modm_m2m_value._id]) elif isinstance(modm_m2m_value, basestring): django_pks.append(modm_to_django[ modm_m2m_value]) elif isinstance(modm_m2m_value, Pointer): django_pks.append(modm_to_django[ modm_m2m_value.node._id]) else: # wth print '\a' # bells! print '\a' print '\a' print '\a' print '\a' print '\a' print '\a' import bpdb bpdb.set_trace() if len(django_pks) > 0: attr.add(*django_pks) m2m_count += len(django_pks) user_count += 1 if user_count % page_size == 0 or user_count == total: print 'Through {} users and {} m2m'.format(user_count, m2m_count) print 'Done with {} in {} seconds...'.format( sys._getframe().f_code.co_name, (datetime.now() - start).total_seconds())
def deserialize_contributors(node, user_dicts, auth): """View helper that returns a list of User objects from a list of serialized users (dicts). The users in the list may be registered or unregistered users. e.g. ``[{'id': 'abc123', 'registered': True, 'fullname': ..}, {'id': None, 'registered': False, 'fullname'...}, {'id': '123ab', 'registered': False, 'fullname': ...}] If a dict represents an unregistered user without an ID, creates a new unregistered User record. :param Node node: The node to add contributors to :param list(dict) user_dicts: List of serialized users in the format above. :param Auth auth: """ # Add the registered contributors contribs = [] for contrib_dict in user_dicts: fullname = contrib_dict['fullname'] visible = contrib_dict['visible'] email = contrib_dict.get('email') if contrib_dict['id']: contributor = User.load(contrib_dict['id']) else: try: contributor = User.create_unregistered(fullname=fullname, email=email) contributor.save() except ValidationValueError: contributor = get_user(username=email) # Add unclaimed record if necessary if (not contributor.is_registered and node._primary_key not in contributor.unclaimed_records): contributor.add_unclaimed_record(node=node, referrer=auth.user, given_name=fullname, email=email) contributor.save() unreg_contributor_added.send(node, contributor=contributor, auth=auth) contribs.append({ 'user': contributor, 'visible': visible, 'permissions': expand_permissions(contrib_dict.get('permission')) }) return contribs
def main(): total = MODMUser.find().count() count = 0 page_size = 1000 while count < total: modm_users = MODMUser.find()[count:count + page_size] for modm_user in modm_users: django_user = get_or_create_user(modm_user) count += 1 print 'Count: {}'.format(count)
def deserialize_contributors(node, user_dicts, auth, validate=False): """View helper that returns a list of User objects from a list of serialized users (dicts). The users in the list may be registered or unregistered users. e.g. ``[{'id': 'abc123', 'registered': True, 'fullname': ..}, {'id': None, 'registered': False, 'fullname'...}, {'id': '123ab', 'registered': False, 'fullname': ...}] If a dict represents an unregistered user without an ID, creates a new unregistered User record. :param Node node: The node to add contributors to :param list(dict) user_dicts: List of serialized users in the format above. :param Auth auth: :param bool validate: Whether to validate and sanitize fields (if necessary) """ # Add the registered contributors contribs = [] for contrib_dict in user_dicts: fullname = contrib_dict["fullname"] visible = contrib_dict["visible"] email = contrib_dict.get("email") if validate is True: # Validate and sanitize inputs as needed. Email will raise error if invalid. # TODO Edge case bug: validation and saving are performed in same loop, so all in list # up to the invalid entry will be saved. (communicate to the user what needs to be retried) fullname = sanitize.strip_html(fullname) if not fullname: raise ValidationValueError("Full name field cannot be empty") if email: validate_email(email) # Will raise a ValidationError if email invalid if contrib_dict["id"]: contributor = User.load(contrib_dict["id"]) else: try: contributor = User.create_unregistered(fullname=fullname, email=email) contributor.save() except ValidationValueError: ## FIXME: This suppresses an exception if ID not found & new validation fails; get_user will return None contributor = get_user(email=email) # Add unclaimed record if necessary if not contributor.is_registered and node._primary_key not in contributor.unclaimed_records: contributor.add_unclaimed_record(node=node, referrer=auth.user, given_name=fullname, email=email) contributor.save() contribs.append( {"user": contributor, "visible": visible, "permissions": expand_permissions(contrib_dict.get("permission"))} ) return contribs
def save_bare_users(page_size=20000): print 'Starting {}...'.format(sys._getframe().f_code.co_name) count = 0 start = datetime.now() total = MODMUser.find().count() while count < total: with transaction.atomic(): users = [] for modm_user in MODMUser.find().sort( '-date_registered')[count:count + page_size]: guid = Guid.objects.get(guid=modm_user._id) user_fields = dict(_guid_id=guid.pk, **modm_user.to_storage()) cleaned_user_fields = { key: user_fields[key] for key in user_fields if key not in user_key_blacklist } for k, v in cleaned_user_fields.iteritems(): if isinstance(v, datetime): cleaned_user_fields[k] = pytz.utc.localize(v) cleaned_user_fields = { k: v for k, v in cleaned_user_fields.iteritems() if v is not None } users.append(User(**cleaned_user_fields)) count += 1 if count % page_size == 0 or count == total: then = datetime.now() print 'Saving users {} through {}...'.format( count - page_size, count) woot = User.objects.bulk_create(users) for wit in woot: modm_to_django[wit._guid.guid] = wit.pk now = datetime.now() print 'Done with {} users in {} seconds...'.format( len(woot), (now - then).total_seconds()) users = None woot = None guid = None user_fields = None cleaned_user_fields = None trash = gc.collect() print 'Took out {} trashes'.format(trash) print 'Modm Users: {}'.format(total) print 'django Users: {}'.format(User.objects.all().count()) print 'Done with {} in {} seconds...'.format( sys._getframe().f_code.co_name, (datetime.now() - start).total_seconds())
def find_inactive_users_with_no_inactivity_email_sent_or_queued(): inactive_users = User.find( (Q('date_last_login', 'lt', datetime.utcnow() - settings.NO_LOGIN_WAIT_TIME) & Q('osf4m', 'ne', 'system_tags')) | (Q('date_last_login', 'lt', datetime.utcnow() - settings.NO_LOGIN_OSF4M_WAIT_TIME) & Q('osf4m', 'eq', 'system_tags')) ) inactive_emails = mails.QueuedMail.find(Q('email_type', 'eq', mails.NO_LOGIN_TYPE)) #This is done to prevent User query returns comparison to User, as equality fails #on datetime fields due to pymongo rounding. Instead here _id is compared. users_sent_id = [email.user._id for email in inactive_emails] inactive_ids = [user._id for user in inactive_users if user.is_active] users_to_send = [User.load(id) for id in (set(inactive_ids) - set(users_sent_id))] return users_to_send
def find_inactive_users_with_no_inactivity_email_sent_or_queued(): inactive_users = User.find( (Q('date_last_login', 'lt', timezone.now() - settings.NO_LOGIN_WAIT_TIME) & Q('tags__name', 'ne', 'osf4m')) | (Q('date_last_login', 'lt', timezone.now() - settings.NO_LOGIN_OSF4M_WAIT_TIME) & Q('tags__name', 'eq', 'osf4m')) ) inactive_emails = mails.QueuedMail.find(Q('email_type', 'eq', mails.NO_LOGIN_TYPE)) #This is done to prevent User query returns comparison to User, as equality fails #on datetime fields due to pymongo rounding. Instead here _id is compared. users_sent_id = [email.user._id for email in inactive_emails] inactive_ids = [user._id for user in inactive_users if user.is_active] users_to_send = [User.load(id) for id in (set(inactive_ids) - set(users_sent_id))] return users_to_send
def save_bare_users(page_size=20000): print 'Starting {}...'.format(sys._getframe().f_code.co_name) count = 0 start = datetime.now() total = MODMUser.find().count() while count < total: with transaction.atomic(): users = [] for modm_user in MODMUser.find().sort('-date_registered')[ count:count + page_size]: guid = Guid.objects.get(guid=modm_user._id) user_fields = dict(_guid_id=guid.pk, **modm_user.to_storage()) cleaned_user_fields = {key: user_fields[key] for key in user_fields if key not in user_key_blacklist} for k, v in cleaned_user_fields.iteritems(): if isinstance(v, datetime): cleaned_user_fields[k] = pytz.utc.localize(v) cleaned_user_fields = {k: v for k, v in cleaned_user_fields.iteritems() if v is not None} users.append(User(**cleaned_user_fields)) count += 1 if count % page_size == 0 or count == total: then = datetime.now() print 'Saving users {} through {}...'.format( count - page_size, count) woot = User.objects.bulk_create(users) for wit in woot: modm_to_django[wit._guid.guid] = wit.pk now = datetime.now() print 'Done with {} users in {} seconds...'.format( len(woot), (now - then).total_seconds()) users = None woot = None guid = None user_fields = None cleaned_user_fields = None trash = gc.collect() print 'Took out {} trashes'.format(trash) print 'Modm Users: {}'.format(total) print 'django Users: {}'.format(User.objects.all().count()) print 'Done with {} in {} seconds...'.format( sys._getframe().f_code.co_name, (datetime.now() - start).total_seconds())
def deserialize_contributors(node, user_dicts, auth): """View helper that returns a list of User objects from a list of serialized users (dicts). The users in the list may be registered or unregistered users. e.g. ``[{'id': 'abc123', 'registered': True, 'fullname': ..}, {'id': None, 'registered': False, 'fullname'...}, {'id': '123ab', 'registered': False, 'fullname': ...}] If a dict represents an unregistered user without an ID, creates a new unregistered User record. :param Node node: The node to add contributors to :param list(dict) user_dicts: List of serialized users in the format above. :param Auth auth: """ # Add the registered contributors contribs = [] for contrib_dict in user_dicts: fullname = contrib_dict['fullname'] visible = contrib_dict['visible'] email = contrib_dict.get('email') if contrib_dict['id']: contributor = User.load(contrib_dict['id']) else: try: contributor = User.create_unregistered( fullname=fullname, email=email) contributor.save() except ValidationValueError: contributor = get_user(email=email) # Add unclaimed record if necessary if (not contributor.is_registered and node._primary_key not in contributor.unclaimed_records): contributor.add_unclaimed_record(node=node, referrer=auth.user, given_name=fullname, email=email) contributor.save() unreg_contributor_added.send(node, contributor=contributor, auth=auth) contribs.append({ 'user': contributor, 'visible': visible, 'permissions': expand_permissions(contrib_dict.get('permission')) }) return contribs
def get_user_from_cas_resp(cas_resp): """ Given a CAS service validation response, attempt to retrieve user information and next action. :param cas_resp: the cas service validation response :return: the user, the external_credential, and the next action """ if cas_resp.user: user = User.load(cas_resp.user) # cas returns a valid OSF user id if user: return user, None, 'authenticate' # cas does not return a valid OSF user id else: external_credential = validate_external_credential(cas_resp.user) # invalid cas response if not external_credential: return None, None, None # cas returns a valid external credential user = get_user( external_id_provider=external_credential['provider'], external_id=external_credential['id']) # existing user found if user: return user, external_credential, 'authenticate' # user first time login through external identity provider else: return None, external_credential, 'external_first_login'
def send_claim_registered_email(claimer, unreg_user, node, throttle=24 * 3600): unclaimed_record = unreg_user.get_unclaimed_record(node._primary_key) referrer = User.load(unclaimed_record['referrer_id']) claim_url = web_url_for( 'claim_user_registered', uid=unreg_user._primary_key, pid=node._primary_key, token=unclaimed_record['token'], _external=True, ) timestamp = unclaimed_record.get('last_sent') if throttle_period_expired(timestamp, throttle): # Send mail to referrer, telling them to forward verification link to claimer mails.send_mail( referrer.username, mails.FORWARD_INVITE_REGiSTERED, user=unreg_user, referrer=referrer, node=node, claim_url=claim_url, fullname=unclaimed_record['name'], ) unclaimed_record['last_sent'] = get_timestamp() unreg_user.save() # Send mail to claimer, telling them to wait for referrer mails.send_mail( claimer.username, mails.PENDING_VERIFICATION_REGISTERED, fullname=claimer.fullname, referrer=referrer, node=node, )
def save_bare_system_tags(page_size=10000): print 'Starting save_bare_system_tags...' start = datetime.now() things = list(MODMNode.find(MQ('system_tags', 'ne', [])).sort( '-_id')) + list(MODMUser.find(MQ('system_tags', 'ne', [])).sort( '-_id')) system_tag_ids = [] for thing in things: for system_tag in thing.system_tags: system_tag_ids.append(system_tag) unique_system_tag_ids = set(system_tag_ids) total = len(unique_system_tag_ids) system_tags = [] for system_tag_id in unique_system_tag_ids: system_tags.append(Tag(_id=system_tag_id, lower=system_tag_id.lower(), system=True)) woot = Tag.objects.bulk_create(system_tags) print 'MODM System Tags: {}'.format(total) print 'django system tags: {}'.format(Tag.objects.filter(system= True).count()) print 'Done with {} in {} seconds...'.format( sys._getframe().f_code.co_name, (datetime.now() - start).total_seconds())
def setUpClass(cls): super(TestVarnish, cls).setUpClass() username = uuid.uuid4() cls.user = User.create_confirmed(username='******'.format( str(username)), password='******', fullname='Mocha Test User') cls.user.save() cls.authorization = HTTPBasicAuth(cls.user.username, 'password') small = 5 large = 10 components = [[[ range(small, random.randint(small, large)) for x in range(small, random.randint(small, large)) ] for y in range(small, random.randint(small, large))] for z in range(small, random.randint(small, large))] number_of_projects = random.randint(1, 11) number_of_tags = random.randint(1, 11) number_of_users = random.randint(1, 11) for i in range(number_of_projects): name = '' create_fake_project(cls.user, number_of_users, random.choice(['public', 'private']), components, name, number_of_tags, None, False)
def setUpClass(cls): super(TestVarnish, cls).setUpClass() username = uuid.uuid4() cls.user = User.create_confirmed( username='******'.format(str(username)), password='******', fullname='Mocha Test User') cls.user.save() cls.authorization = HTTPBasicAuth(cls.user.username, 'password') small = 5 large = 10 components = [[[range(small, random.randint(small, large)) for x in range(small, random.randint(small, large))] for y in range(small, random.randint(small, large))] for z in range(small, random.randint(small, large))] number_of_projects = random.randint(1, 11) number_of_tags = random.randint(1, 11) number_of_users = random.randint(1, 11) for i in range(number_of_projects): name = '' create_fake_project(cls.user, number_of_users, random.choice(['public', 'private']), components, name, number_of_tags, None, False)
def get_node_contributors_abbrev(auth, node, **kwargs): anonymous = has_anonymous_link(node, auth) formatter = "surname" max_count = kwargs.get("max_count", 3) if "user_ids" in kwargs: users = [User.load(user_id) for user_id in kwargs["user_ids"] if user_id in node.visible_contributor_ids] else: users = node.visible_contributors if anonymous or not node.can_view(auth): raise HTTPError(http.FORBIDDEN) contributors = [] n_contributors = len(users) others_count = "" for index, user in enumerate(users[:max_count]): if index == max_count - 1 and len(users) > max_count: separator = " &" others_count = str(n_contributors - 3) elif index == len(users) - 1: separator = "" elif index == len(users) - 2: separator = " &" else: separator = "," contributor = user.get_summary(formatter) contributor["user_id"] = user._primary_key contributor["separator"] = separator contributors.append(contributor) return {"contributors": contributors, "others_count": others_count}
def project_removecontributor(auth, node, **kwargs): contributor = User.load(request.json['id']) if contributor is None: raise HTTPError(http.BAD_REQUEST) # Forbidden unless user is removing herself if not node.has_permission(auth.user, 'admin'): if auth.user != contributor: raise HTTPError(http.FORBIDDEN) outcome = node.remove_contributor( contributor=contributor, auth=auth, ) if outcome: if auth.user == contributor: status.push_status_message('Removed self from project', 'info') return {'redirectUrl': web_url_for('dashboard')} status.push_status_message('Contributor removed', 'info') return {} raise HTTPError( http.BAD_REQUEST, data={ 'message_long': ( '{0} must have at least one contributor with admin ' 'rights'.format( node.project_or_component.capitalize() ) ) } )
def project_before_remove_contributor(auth, node, **kwargs): contributor = User.load(request.json.get('id')) # Forbidden unless user is removing herself if not node.has_permission(auth.user, 'admin'): if auth.user != contributor: raise HTTPError(http.FORBIDDEN) if len(node.visible_contributor_ids) == 1 \ and node.visible_contributor_ids[0] == contributor._id: raise HTTPError(http.FORBIDDEN, data={ 'message_long': 'Must have at least one bibliographic contributor' }) prompts = node.callback( 'before_remove_contributor', removed=contributor, ) if auth.user == contributor: prompts.insert( 0, 'Are you sure you want to remove yourself from this project?' ) return {'prompts': prompts}
def get_user_from_cas_resp(cas_resp): """ Given a CAS service validation response, attempt to retrieve user information and next action. :param cas_resp: the cas service validation response :return: the user, the external_credential, and the next action """ if cas_resp.user: user = User.load(cas_resp.user) # cas returns a valid OSF user id if user: return user, None, 'authenticate' # cas does not return a valid OSF user id else: external_credential = validate_external_credential(cas_resp.user) # invalid cas response if not external_credential: return None, None, None # cas returns a valid external credential user = get_user(external_id_provider=external_credential['provider'], external_id=external_credential['id']) # existing user found if user: return user, external_credential, 'authenticate' # user first time login through external identity provider else: return None, external_credential, 'external_first_login'
def project_before_remove_contributor(auth, node, **kwargs): contributor = User.load(request.json.get('id')) # Forbidden unless user is removing herself if not node.has_permission(auth.user, 'admin'): if auth.user != contributor: raise HTTPError(http.FORBIDDEN) if len(node.visible_contributor_ids) == 1 \ and node.visible_contributor_ids[0] == contributor._id: raise HTTPError(http.FORBIDDEN, data={ 'message_long': 'Must have at least one bibliographic contributor' }) prompts = node.callback( 'before_remove_contributor', removed=contributor, ) if auth.user == contributor: prompts.insert( 0, 'Are you sure you want to remove yourself from this project?') return {'prompts': prompts}
def save_bare_system_tags(page_size=10000): print 'Starting save_bare_system_tags...' start = datetime.now() things = list(MODMNode.find(MQ( 'system_tags', 'ne', [])).sort('-_id')) + list( MODMUser.find(MQ('system_tags', 'ne', [])).sort('-_id')) system_tag_ids = [] for thing in things: for system_tag in thing.system_tags: system_tag_ids.append(system_tag) unique_system_tag_ids = set(system_tag_ids) total = len(unique_system_tag_ids) system_tags = [] for system_tag_id in unique_system_tag_ids: system_tags.append( Tag(_id=system_tag_id, lower=system_tag_id.lower(), system=True)) woot = Tag.objects.bulk_create(system_tags) print 'MODM System Tags: {}'.format(total) print 'django system tags: {}'.format( Tag.objects.filter(system=True).count()) print 'Done with {} in {} seconds...'.format( sys._getframe().f_code.co_name, (datetime.now() - start).total_seconds())
def send_claim_registered_email(claimer, unclaimed_user, node, throttle=24 * 3600): """ A registered user claiming the unclaimed user account as an contributor to a project. Send an email for claiming the account to the referrer and notify the claimer. :param claimer: the claimer :param unclaimed_user: the user account to claim :param node: the project node where the user account is claimed :param throttle: the time period in seconds before another claim for the account can be made :return: :raise: http.BAD_REQUEST """ unclaimed_record = unclaimed_user.get_unclaimed_record(node._primary_key) # check throttle timestamp = unclaimed_record.get('last_sent') if not throttle_period_expired(timestamp, throttle): raise HTTPError(http.BAD_REQUEST, data=dict( message_long='User account can only be claimed with an existing user once every 24 hours' )) # roll the valid token for each email, thus user cannot change email and approve a different email address verification_key = generate_verification_key(verification_type='claim') unclaimed_record['token'] = verification_key['token'] unclaimed_record['expires'] = verification_key['expires'] unclaimed_record['claimer_email'] = claimer.username unclaimed_user.save() referrer = User.load(unclaimed_record['referrer_id']) claim_url = web_url_for( 'claim_user_registered', uid=unclaimed_user._primary_key, pid=node._primary_key, token=unclaimed_record['token'], _external=True, ) # Send mail to referrer, telling them to forward verification link to claimer mails.send_mail( referrer.username, mails.FORWARD_INVITE_REGISTERED, user=unclaimed_user, referrer=referrer, node=node, claim_url=claim_url, fullname=unclaimed_record['name'], ) unclaimed_record['last_sent'] = get_timestamp() unclaimed_user.save() # Send mail to claimer, telling them to wait for referrer mails.send_mail( claimer.username, mails.PENDING_VERIFICATION_REGISTERED, fullname=claimer.fullname, referrer=referrer, node=node, )
def send_claim_email(email, user, node, notify=True, throttle=24 * 3600): """Send an email for claiming a user account. Either sends to the given email or the referrer's email, depending on the email address provided. :param str email: The address given in the claim user form :param User user: The User record to claim. :param Node node: The node where the user claimed their account. :param bool notify: If True and an email is sent to the referrer, an email will also be sent to the invited user about their pending verification. :param int throttle: Time period (in seconds) after the referrer is emailed during which the referrer will not be emailed again. """ claimer_email = email.lower().strip() unclaimed_record = user.get_unclaimed_record(node._primary_key) referrer = User.load(unclaimed_record['referrer_id']) claim_url = user.get_claim_url(node._primary_key, external=True) # If given email is the same provided by user, just send to that email if unclaimed_record.get('email') == claimer_email: mail_tpl = mails.INVITE to_addr = claimer_email unclaimed_record['claimer_email'] = claimer_email user.save() else: # Otherwise have the referrer forward the email to the user # roll the valid token for each email, thus user cannot change email and approve a different email address timestamp = unclaimed_record.get('last_sent') if not throttle_period_expired(timestamp, throttle): raise HTTPError(400, data=dict( message_long='User account can only be claimed with an existing user once every 24 hours' )) unclaimed_record['last_sent'] = get_timestamp() unclaimed_record['token'] = generate_confirm_token() unclaimed_record['claimer_email'] = claimer_email user.save() claim_url = user.get_claim_url(node._primary_key, external=True) if notify: pending_mail = mails.PENDING_VERIFICATION mails.send_mail( claimer_email, pending_mail, user=user, referrer=referrer, fullname=unclaimed_record['name'], node=node ) mail_tpl = mails.FORWARD_INVITE to_addr = referrer.username mails.send_mail( to_addr, mail_tpl, user=user, referrer=referrer, node=node, claim_url=claim_url, email=claimer_email, fullname=unclaimed_record['name'] ) return to_addr
def test_register(self): auth.register('*****@*****.**', 'gattaca', fullname="Rosie Franklin") user = User.find_one(Q('username', 'eq', '*****@*****.**')) # The password should be set assert_true(user.check_password('gattaca')) assert_equal(user.fullname, "Rosie Franklin") assert_equal(user.username, '*****@*****.**') assert_in("*****@*****.**", user.emails)
def claim_user_registered(auth, node, **kwargs): """View that prompts user to enter their password in order to claim contributorship on a project. A user must be logged in. """ current_user = auth.user sign_out_url = web_url_for('auth_login', logout=True, next=request.url) if not current_user: return redirect(sign_out_url) # Logged in user should not be a contributor the project if node.is_contributor(current_user): logout_url = web_url_for('auth_logout', redirect_url=request.url) data = { 'message_short': 'Already a contributor', 'message_long': ('The logged-in user is already a contributor to this ' 'project. Would you like to <a href="{}">log out</a>?').format(logout_url) } raise HTTPError(http.BAD_REQUEST, data=data) uid, pid, token = kwargs['uid'], kwargs['pid'], kwargs['token'] unreg_user = User.load(uid) if not verify_claim_token(unreg_user, token, pid=node._primary_key): raise HTTPError(http.BAD_REQUEST) # Store the unreg_user data on the session in case the user registers # a new account session.data['unreg_user'] = { 'uid': uid, 'pid': pid, 'token': token } form = PasswordForm(request.form) if request.method == 'POST': if form.validate(): if current_user.check_password(form.password.data): node.replace_contributor(old=unreg_user, new=current_user) node.save() status.push_status_message( 'You are now a contributor to this project.', kind='success', trust=False ) return redirect(node.url) else: status.push_status_message(language.LOGIN_FAILED, kind='warning', trust=False) else: forms.push_errors_to_status(form.errors) if is_json_request(): form_ret = forms.utils.jsonify(form) user_ret = profile_utils.serialize_user(current_user, full=False) else: form_ret = form user_ret = current_user return { 'form': form_ret, 'user': user_ret, 'signOutUrl': sign_out_url }
def claim_user_form(auth, **kwargs): """ View for rendering the set password page for a claimed user. Must have ``token`` as a querystring argument. Renders the set password form, validates it, and sets the user's password. HTTP Method: GET, POST """ uid, pid = kwargs['uid'], kwargs['pid'] token = request.form.get('token') or request.args.get('token') user = User.load(uid) # If unregistered user is not in database, or url bears an invalid token raise HTTP 400 error if not user or not verify_claim_token(user, token, pid): error_data = { 'message_short': 'Invalid url.', 'message_long': 'Claim user does not exists, the token in the URL is invalid or has expired.' } raise HTTPError(http.BAD_REQUEST, data=error_data) # If user is logged in, redirect to 're-enter password' page if auth.logged_in: return redirect(web_url_for('claim_user_registered', uid=uid, pid=pid, token=token)) unclaimed_record = user.unclaimed_records[pid] user.fullname = unclaimed_record['name'] user.update_guessed_names() # The email can be the original referrer email if no claimer email has been specified. claimer_email = unclaimed_record.get('claimer_email') or unclaimed_record.get('email') form = SetEmailAndPasswordForm(request.form, token=token) if request.method == 'POST': if not form.validate(): forms.push_errors_to_status(form.errors) elif settings.RECAPTCHA_SITE_KEY and not validate_recaptcha(request.form.get('g-recaptcha-response'), remote_ip=request.remote_addr): status.push_status_message('Invalid captcha supplied.', kind='error') else: username, password = claimer_email, form.password.data user.register(username=username, password=password) # Clear unclaimed records user.unclaimed_records = {} user.verification_key = generate_verification_key() user.save() # Authenticate user and redirect to project page status.push_status_message(language.CLAIMED_CONTRIBUTOR, kind='success', trust=True) # Redirect to CAS and authenticate the user with a verification key. return redirect(cas.get_login_url( web_url_for('view_project', pid=pid, _absolute=True), username=user.username, verification_key=user.verification_key )) return { 'firstname': user.given_name, 'email': claimer_email if claimer_email else '', 'fullname': user.fullname, 'form': forms.utils.jsonify(form) if is_json_request() else form, }
def claim_user_form(auth, **kwargs): """View for rendering the set password page for a claimed user. Must have ``token`` as a querystring argument. Renders the set password form, validates it, and sets the user's password. """ uid, pid = kwargs['uid'], kwargs['pid'] token = request.form.get('token') or request.args.get('token') # If user is logged in, redirect to 're-enter password' page if auth.logged_in: return redirect( web_url_for('claim_user_registered', uid=uid, pid=pid, token=token)) user = User.load(uid) # The unregistered user # user ID is invalid. Unregistered user is not in database if not user: raise HTTPError(http.BAD_REQUEST) # If claim token not valid, redirect to registration page if not verify_claim_token(user, token, pid): return redirect(web_url_for('auth_login')) unclaimed_record = user.unclaimed_records[pid] user.fullname = unclaimed_record['name'] user.update_guessed_names() # The email can be the original referrer email if no claimer email has been specified. claimer_email = unclaimed_record.get( 'claimer_email') or unclaimed_record.get('email') form = SetEmailAndPasswordForm(request.form, token=token) if request.method == 'POST': if form.validate(): username, password = claimer_email, form.password.data user.register(username=username, password=password) # Clear unclaimed records user.unclaimed_records = {} user.verification_key = security.random_string(20) user.save() # Authenticate user and redirect to project page node = Node.load(pid) status.push_status_message( language.CLAIMED_CONTRIBUTOR.format(node=node), kind='success', trust=True) # Redirect to CAS and authenticate the user with a verification key. return redirect( cas.get_login_url(web_url_for('user_profile', _absolute=True), auto=True, username=user.username, verification_key=user.verification_key)) else: forms.push_errors_to_status(form.errors) return { 'firstname': user.given_name, 'email': claimer_email if claimer_email else '', 'fullname': user.fullname, 'form': forms.utils.jsonify(form) if is_json_request() else form, }
def claim_user_form(auth, **kwargs): """ View for rendering the set password page for a claimed user. Must have ``token`` as a querystring argument. Renders the set password form, validates it, and sets the user's password. HTTP Method: GET, POST """ uid, pid = kwargs['uid'], kwargs['pid'] token = request.form.get('token') or request.args.get('token') user = User.load(uid) # If unregistered user is not in database, or url bears an invalid token raise HTTP 400 error if not user or not verify_claim_token(user, token, pid): error_data = { 'message_short': 'Invalid url.', 'message_long': 'Claim user does not exists, the token in the URL is invalid or has expired.' } raise HTTPError(http.BAD_REQUEST, data=error_data) # If user is logged in, redirect to 're-enter password' page if auth.logged_in: return redirect(web_url_for('claim_user_registered', uid=uid, pid=pid, token=token)) unclaimed_record = user.unclaimed_records[pid] user.fullname = unclaimed_record['name'] user.update_guessed_names() # The email can be the original referrer email if no claimer email has been specified. claimer_email = unclaimed_record.get('claimer_email') or unclaimed_record.get('email') form = SetEmailAndPasswordForm(request.form, token=token) if request.method == 'POST': if form.validate(): username, password = claimer_email, form.password.data user.register(username=username, password=password) # Clear unclaimed records user.unclaimed_records = {} user.verification_key = generate_verification_key() user.save() # Authenticate user and redirect to project page status.push_status_message(language.CLAIMED_CONTRIBUTOR, kind='success', trust=True) # Redirect to CAS and authenticate the user with a verification key. return redirect(cas.get_login_url( web_url_for('view_project', pid=pid, _absolute=True), username=user.username, verification_key=user.verification_key )) else: forms.push_errors_to_status(form.errors) return { 'firstname': user.given_name, 'email': claimer_email if claimer_email else '', 'fullname': user.fullname, 'form': forms.utils.jsonify(form) if is_json_request() else form, }
def claim_user_form(auth, **kwargs): """View for rendering the set password page for a claimed user. Must have ``token`` as a querystring argument. Renders the set password form, validates it, and sets the user's password. """ uid, pid = kwargs['uid'], kwargs['pid'] token = request.form.get('token') or request.args.get('token') # If user is logged in, redirect to 're-enter password' page if auth.logged_in: return redirect(web_url_for('claim_user_registered', uid=uid, pid=pid, token=token)) user = User.load(uid) # The unregistered user # user ID is invalid. Unregistered user is not in database if not user: raise HTTPError(http.BAD_REQUEST) # If claim token not valid, redirect to registration page if not verify_claim_token(user, token, pid): return redirect(web_url_for('auth_login')) unclaimed_record = user.unclaimed_records[pid] user.fullname = unclaimed_record['name'] user.update_guessed_names() # The email can be the original referrer email if no claimer email has been specified. claimer_email = unclaimed_record.get('claimer_email') or unclaimed_record.get('email') form = SetEmailAndPasswordForm(request.form, token=token) if request.method == 'POST': if form.validate(): username, password = claimer_email, form.password.data user.register(username=username, password=password) # Clear unclaimed records user.unclaimed_records = {} user.verification_key = security.random_string(20) user.save() # Authenticate user and redirect to project page node = Node.load(pid) status.push_status_message(language.CLAIMED_CONTRIBUTOR.format(node=node), kind='success', trust=True) # Redirect to CAS and authenticate the user with a verification key. return redirect(cas.get_login_url( web_url_for('user_profile', _absolute=True), auto=True, username=user.username, verification_key=user.verification_key )) else: forms.push_errors_to_status(form.errors) return { 'firstname': user.given_name, 'email': claimer_email if claimer_email else '', 'fullname': user.fullname, 'form': forms.utils.jsonify(form) if is_json_request() else form, }
def claim_user_registered(auth, node, **kwargs): """ View that prompts user to enter their password in order to claim being a contributor on a project. A user must be logged in. """ current_user = auth.user sign_out_url = web_url_for("auth_register", logout=True, next=request.url) if not current_user: return redirect(sign_out_url) # Logged in user should not be a contributor the project if node.is_contributor(current_user): logout_url = web_url_for("auth_logout", redirect_url=request.url) data = { "message_short": "Already a contributor", "message_long": ( "The logged-in user is already a contributor to this " 'project. Would you like to <a href="{}">log out</a>?' ).format(logout_url), } raise HTTPError(http.BAD_REQUEST, data=data) uid, pid, token = kwargs["uid"], kwargs["pid"], kwargs["token"] unreg_user = User.load(uid) if not verify_claim_token(unreg_user, token, pid=node._primary_key): error_data = { "message_short": "Invalid url.", "message_long": "The token in the URL is invalid or has expired.", } raise HTTPError(http.BAD_REQUEST, data=error_data) # Store the unreg_user data on the session in case the user registers # a new account session.data["unreg_user"] = {"uid": uid, "pid": pid, "token": token} form = PasswordForm(request.form) if request.method == "POST": if form.validate(): if current_user.check_password(form.password.data): node.replace_contributor(old=unreg_user, new=current_user) node.save() status.push_status_message("You are now a contributor to this project.", kind="success", trust=False) return redirect(node.url) else: status.push_status_message(language.LOGIN_FAILED, kind="warning", trust=False) else: forms.push_errors_to_status(form.errors) if is_json_request(): form_ret = forms.utils.jsonify(form) user_ret = profile_utils.serialize_user(current_user, full=False) else: form_ret = form user_ret = current_user return {"form": form_ret, "user": user_ret, "signOutUrl": sign_out_url}
def project_remove_contributor(auth, **kwargs): """Remove a contributor from a list of nodes. :param Auth auth: Consolidated authorization :raises: HTTPError(400) if contributors to be removed are not in list or if no admin users would remain after changes were applied """ contributor_id = request.get_json()['contributorID'] node_ids = request.get_json()['nodeIDs'] contributor = User.load(contributor_id) if contributor is None: raise HTTPError(http.BAD_REQUEST, data={'message_long': 'Contributor not found.'}) redirect_url = {} parent_id = node_ids[0] for node_id in node_ids: # Update permissions and order node = Node.load(node_id) # Forbidden unless user is removing herself if not node.has_permission(auth.user, 'admin'): if auth.user != contributor: raise HTTPError(http.FORBIDDEN) if len(node.visible_contributor_ids) == 1 \ and node.visible_contributor_ids[0] == contributor._id: raise HTTPError( http.FORBIDDEN, data={ 'message_long': 'Must have at least one bibliographic contributor' }) nodes_removed = node.remove_contributor(contributor, auth=auth) # remove_contributor returns false if there is not one admin or visible contributor left after the move. if not nodes_removed: raise HTTPError( http.BAD_REQUEST, data={'message_long': 'Could not remove contributor.'}) # On parent node, if user has removed herself from project, alert; redirect to user # dashboard if node is private, else node dashboard if not node.is_contributor(auth.user) and node_id == parent_id: status.push_status_message( 'You have removed yourself as a contributor from this project', kind='success', trust=False) if node.is_public: redirect_url = {'redirectUrl': node.url} # Else stay on current page else: redirect_url = {'redirectUrl': web_url_for('dashboard')} return redirect_url
def migrate_users(index): logger.info("Migrating users to index: {}".format(index)) n_migr = 0 n_iter = 0 for user in User.find(): if user.is_active: search.update_user(user, index=index) n_migr += 1 n_iter += 1 logger.info('Users iterated: {0}\nUsers migrated: {1}'.format(n_iter, n_migr))
def migrate_users(index): logger.info("Migrating users to index: {}".format(index)) n_migr = 0 n_iter = 0 for user in User.find(): if user.is_active: search.update_user(user, index=index) n_migr += 1 n_iter += 1 logger.info('Users iterated: {0}\nUsers migrated: {1}'.format( n_iter, n_migr))
def send_claim_email(email, user, node, notify=True, throttle=24 * 3600): """Send an email for claiming a user account. Either sends to the given email or the referrer's email, depending on the email address provided. :param str email: The address given in the claim user form :param User user: The User record to claim. :param Node node: The node where the user claimed their account. :param bool notify: If True and an email is sent to the referrer, an email will also be sent to the invited user about their pending verification. :param int throttle: Time period (in seconds) after the referrer is emailed during which the referrer will not be emailed again. """ invited_email = email.lower().strip() unclaimed_record = user.get_unclaimed_record(node._primary_key) referrer = User.load(unclaimed_record['referrer_id']) claim_url = user.get_claim_url(node._primary_key, external=True) # If given email is the same provided by user, just send to that email if unclaimed_record.get('email', None) == invited_email: mail_tpl = mails.INVITE to_addr = invited_email else: # Otherwise have the referrer forward the email to the user if notify: pending_mail = mails.PENDING_VERIFICATION mails.send_mail( invited_email, pending_mail, user=user, referrer=referrer, fullname=unclaimed_record['name'], node=node ) timestamp = unclaimed_record.get('last_sent') if throttle_period_expired(timestamp, throttle): unclaimed_record['last_sent'] = get_timestamp() user.save() else: # Don't send the email to the referrer return mail_tpl = mails.FORWARD_INVITE to_addr = referrer.username mails.send_mail( to_addr, mail_tpl, user=user, referrer=referrer, node=node, claim_url=claim_url, email=invited_email, fullname=unclaimed_record['name'] ) return to_addr
def claim_user_post(node, **kwargs): """ View for claiming a user from the X-editable form on a project page. :param node: the project node :return: """ request_data = request.json # The unclaimed user unclaimed_user = User.load(request_data['pk']) unclaimed_data = unclaimed_user.get_unclaimed_record(node._primary_key) # Claimer is not logged in and submit her/his email through X-editable, stored in `request_data['value']` if 'value' in request_data: email = request_data['value'].lower().strip() claimer = get_user(email=email) # registered user if claimer and claimer.is_registered: send_claim_registered_email(claimer, unclaimed_user, node) # unregistered user else: send_claim_email(email, unclaimed_user, node, notify=True) # Claimer is logged in with confirmed identity stored in `request_data['claimerId']` elif 'claimerId' in request_data: claimer_id = request_data['claimerId'] claimer = User.load(claimer_id) send_claim_registered_email(claimer, unclaimed_user, node) email = claimer.username else: raise HTTPError(http.BAD_REQUEST) return { 'status': 'success', 'email': email, 'fullname': unclaimed_data['name'] }
def project_remove_contributor(auth, **kwargs): """Remove a contributor from a list of nodes. :param Auth auth: Consolidated authorization :raises: HTTPError(400) if contributors to be removed are not in list or if no admin users would remain after changes were applied """ contributor_id = request.get_json()['contributorID'] node_ids = request.get_json()['nodeIDs'] contributor = User.load(contributor_id) if contributor is None: raise HTTPError(http.BAD_REQUEST, data={'message_long': 'Contributor not found.'}) redirect_url = {} parent_id = node_ids[0] for node_id in node_ids: # Update permissions and order node = Node.load(node_id) # Forbidden unless user is removing herself if not node.has_permission(auth.user, 'admin'): if auth.user != contributor: raise HTTPError(http.FORBIDDEN) if len(node.visible_contributor_ids) == 1 \ and node.visible_contributor_ids[0] == contributor._id: raise HTTPError(http.FORBIDDEN, data={ 'message_long': 'Must have at least one bibliographic contributor' }) nodes_removed = node.remove_contributor(contributor, auth=auth) # remove_contributor returns false if there is not one admin or visible contributor left after the move. if not nodes_removed: raise HTTPError(http.BAD_REQUEST, data={ 'message_long': 'Could not remove contributor.'}) # On parent node, if user has removed herself from project, alert; redirect to user # dashboard if node is private, else node dashboard if not node.is_contributor(auth.user) and node_id == parent_id: status.push_status_message( 'You have removed yourself as a contributor from this project', kind='success', trust=False ) if node.is_public: redirect_url = {'redirectUrl': node.url} # Else stay on current page else: redirect_url = {'redirectUrl': web_url_for('dashboard')} return redirect_url
def claim_user_form(auth, **kwargs): """View for rendering the set password page for a claimed user. Must have ``token`` as a querystring argument. Renders the set password form, validates it, and sets the user's password. """ uid, pid = kwargs['uid'], kwargs['pid'] token = request.form.get('token') or request.args.get('token') # If user is logged in, redirect to 're-enter password' page if auth.logged_in: return redirect( web_url_for('claim_user_registered', uid=uid, pid=pid, token=token)) user = User.load(uid) # The unregistered user # user ID is invalid. Unregistered user is not in database if not user: raise HTTPError(http.BAD_REQUEST) # If claim token not valid, redirect to registration page if not verify_claim_token(user, token, pid): return redirect('/account/') unclaimed_record = user.unclaimed_records[pid] user.fullname = unclaimed_record['name'] user.update_guessed_names() email = unclaimed_record['email'] form = SetEmailAndPasswordForm(request.form, token=token) if request.method == 'POST': if form.validate(): username, password = form.username.data, form.password.data user.register(username=username, password=password) # Clear unclaimed records user.unclaimed_records = {} user.save() # Authenticate user and redirect to project page response = redirect('/settings/') node = Node.load(pid) status.push_status_message( language.CLAIMED_CONTRIBUTOR.format(node=node), 'success') return authenticate(user, response) else: forms.push_errors_to_status(form.errors) return { 'firstname': user.given_name, 'email': email if email else '', 'fullname': user.fullname, 'form': forms.utils.jsonify(form) if is_json_request() else form, }
def replace_unclaimed_user_with_registered(user): """Listens for the user_registered signal. If unreg_user is stored in the session, then the current user is trying to claim themselves as a contributor. Replaces the old, unregistered contributor with the newly registered account. """ unreg_user_info = session.data.get("unreg_user") if unreg_user_info: unreg_user = User.load(unreg_user_info["uid"]) pid = unreg_user_info["pid"] node = Node.load(pid) node.replace_contributor(old=unreg_user, new=user) node.save() status.push_status_message("Successfully claimed contributor.", kind="success", trust=False)
def claim_user_form(auth, **kwargs): """View for rendering the set password page for a claimed user. Must have ``token`` as a querystring argument. Renders the set password form, validates it, and sets the user's password. """ uid, pid = kwargs['uid'], kwargs['pid'] token = request.form.get('token') or request.args.get('token') # If user is logged in, redirect to 're-enter password' page if auth.logged_in: return redirect(web_url_for('claim_user_registered', uid=uid, pid=pid, token=token)) user = User.load(uid) # The unregistered user # user ID is invalid. Unregistered user is not in database if not user: raise HTTPError(http.BAD_REQUEST) # If claim token not valid, redirect to registration page if not verify_claim_token(user, token, pid): return redirect('/account/') unclaimed_record = user.unclaimed_records[pid] user.fullname = unclaimed_record['name'] user.update_guessed_names() email = unclaimed_record['email'] form = SetEmailAndPasswordForm(request.form, token=token) if request.method == 'POST': if form.validate(): username, password = email, form.password.data user.register(username=username, password=password) # Clear unclaimed records user.unclaimed_records = {} user.save() # Authenticate user and redirect to project page response = redirect('/settings/') node = Node.load(pid) status.push_status_message(language.CLAIMED_CONTRIBUTOR.format(node=node), 'success') return authenticate(user, response) else: forms.push_errors_to_status(form.errors) return { 'firstname': user.given_name, 'email': email if email else '', 'fullname': user.fullname, 'form': forms.utils.jsonify(form) if is_json_request() else form, }
def replace_unclaimed_user_with_registered(user): """Listens for the user_registered signal. If unreg_user is stored in the session, then the current user is trying to claim themselves as a contributor. Replaces the old, unregistered contributor with the newly registered account. """ unreg_user_info = session.data.get('unreg_user') if unreg_user_info: unreg_user = User.load(unreg_user_info['uid']) pid = unreg_user_info['pid'] node = Node.load(pid) node.replace_contributor(old=unreg_user, new=user) node.save() status.push_status_message( 'Successfully claimed contributor.', kind='success', trust=False)
def make_response_from_ticket(ticket, service_url): """Given a CAS ticket and service URL, attempt to the user and return a proper redirect response. """ service_furl = furl.furl(service_url) if 'ticket' in service_furl.args: service_furl.args.pop('ticket') client = get_client() cas_resp = client.service_validate(ticket, service_furl.url) if cas_resp.authenticated: user = User.load(cas_resp.user) # if we successfully authenticate and a verification key is present, invalidate it if user.verification_key: user.verification_key = None user.save() return authenticate(user, access_token=cas_resp.attributes['accessToken'], response=redirect(service_furl.url)) # Ticket could not be validated, unauthorized. return redirect(service_furl.url)
def project_before_remove_contributor(auth, node, **kwargs): contributor = User.load(request.json.get('id')) # Forbidden unless user is removing herself if not node.has_permission(auth.user, 'admin'): if auth.user != contributor: raise HTTPError(http.FORBIDDEN) prompts = node.callback( 'before_remove_contributor', removed=contributor, ) if auth.user == contributor: prompts.insert( 0, 'Are you sure you want to remove yourself from this project?') return {'prompts': prompts}
def get_node_contributors_abbrev(auth, **kwargs): node = kwargs['node'] or kwargs['project'] anonymous = has_anonymous_link(node, auth) max_count = kwargs.get('max_count', 3) if 'user_ids' in kwargs: users = [ User.load(user_id) for user_id in kwargs['user_ids'] if user_id in node.visible_contributor_ids ] else: users = node.visible_contributors if anonymous or not node.can_view(auth): raise HTTPError(http.FORBIDDEN) contributors = [] n_contributors = len(users) others_count = '' for index, user in enumerate(users[:max_count]): if index == max_count - 1 and len(users) > max_count: separator = ' &' others_count = str(n_contributors - 3) elif index == len(users) - 1: separator = '' elif index == len(users) - 2: separator = ' &' else: separator = ',' contributors.append({ 'user_id': user._primary_key, 'separator': separator, }) return { 'contributors': contributors, 'others_count': others_count, }
def send_claim_registered_email(claimer, unreg_user, node, throttle=24 * 3600): unclaimed_record = unreg_user.get_unclaimed_record(node._primary_key) # roll the valid token for each email, thus user cannot change email and approve a different email address timestamp = unclaimed_record.get('last_sent') if not throttle_period_expired(timestamp, throttle): raise HTTPError( 400, data=dict( message_long= 'User account can only be claimed with an existing user once every 24 hours' )) unclaimed_record['token'] = generate_confirm_token() unclaimed_record['claimer_email'] = claimer.username unreg_user.save() referrer = User.load(unclaimed_record['referrer_id']) claim_url = web_url_for( 'claim_user_registered', uid=unreg_user._primary_key, pid=node._primary_key, token=unclaimed_record['token'], _external=True, ) # Send mail to referrer, telling them to forward verification link to claimer mails.send_mail( referrer.username, mails.FORWARD_INVITE_REGiSTERED, user=unreg_user, referrer=referrer, node=node, claim_url=claim_url, fullname=unclaimed_record['name'], ) unclaimed_record['last_sent'] = get_timestamp() unreg_user.save() # Send mail to claimer, telling them to wait for referrer mails.send_mail( claimer.username, mails.PENDING_VERIFICATION_REGISTERED, fullname=claimer.fullname, referrer=referrer, node=node, )
def get_node_contributors_abbrev(auth, node, **kwargs): anonymous = has_anonymous_link(node, auth) formatter = 'surname' max_count = kwargs.get('max_count', 3) if 'user_ids' in kwargs: users = [ User.load(user_id) for user_id in kwargs['user_ids'] if user_id in node.visible_contributor_ids ] else: users = node.visible_contributors if anonymous or not node.can_view(auth): raise HTTPError(http.FORBIDDEN) contributors = [] n_contributors = len(users) others_count = '' for index, user in enumerate(users[:max_count]): if index == max_count - 1 and len(users) > max_count: separator = ' &' others_count = str(n_contributors - 3) elif index == len(users) - 1: separator = '' elif index == len(users) - 2: separator = ' &' else: separator = ',' contributor = user.get_summary(formatter) contributor['user_id'] = user._primary_key contributor['separator'] = separator contributors.append(contributor) return { 'contributors': contributors, 'others_count': others_count, }