def test_valid_email_change_token(self): u = User(email='*****@*****.**', password='******') db.session.add(u) db.session.commit() token = u.generate_email_change_token('*****@*****.**') self.assertTrue(u.change_email(token)) self.assertTrue(u.email == '*****@*****.**')
def test_valid_reset_token(self): u = User(password='******') db.session.add(u) db.session.commit() token = u.generate_reset_token() self.assertTrue(u.reset_password(token, 'dog')) self.assertTrue(u.verify_password('dog'))
def test_admin_scoped_token_can_create_and_send_email(self, mock_auth, mock_mail): token = ApiOAuth2PersonalToken( owner=self.user, name='Admin Token', scopes='osf.admin' ) mock_cas_resp = CasResponse( authenticated=True, user=self.user._id, attributes={ 'accessToken': token.token_id, 'accessTokenScope': [s for s in token.scopes.split(' ')] } ) mock_auth.return_value = self.user, mock_cas_resp assert_equal(User.find(Q('username', 'eq', self.unconfirmed_email)).count(), 0) res = self.app.post_json_api( '{}?send_email=true'.format(self.base_url), self.data, headers={'Authorization': 'Bearer {}'.format(token.token_id)} ) assert_equal(res.status_code, 201) assert_equal(res.json['data']['attributes']['username'], self.unconfirmed_email) assert_equal(User.find(Q('username', 'eq', self.unconfirmed_email)).count(), 1) assert_equal(mock_mail.call_count, 1)
def redirect_to_twitter(twitter_handle): """Redirect GET requests for /@TwitterHandle/ to respective the OSF user account if it associated with an active account :param uid: uid for requested User :return: Redirect to User's Twitter account page """ try: user = User.find_one(Q('social.twitter', 'iexact', twitter_handle)) except NoResultsFound: raise HTTPError(http.NOT_FOUND, data={ 'message_short': 'User Not Found', 'message_long': 'There is no active user associated with the Twitter handle: {0}.'.format(twitter_handle) }) except MultipleResultsFound: users = User.find(Q('social.twitter', 'iexact', twitter_handle)) message_long = 'There are multiple OSF accounts associated with the ' \ 'Twitter handle: <strong>{0}</strong>. <br /> Please ' \ 'select from the accounts below. <br /><ul>'.format(twitter_handle) for user in users: message_long += '<li><a href="{0}">{1}</a></li>'.format(user.url, user.fullname) message_long += '</ul>' raise HTTPError(http.MULTIPLE_CHOICES, data={ 'message_short': 'Multiple Users Found', 'message_long': message_long }) return redirect(user.url)
def test_expired_confirmation_token(self): u = User(password='******') db.session.add(u) db.session.commit() token = u.generate_confirmation_token(1) time.sleep(2) self.assertFalse(u.confirm(token))
def test_improperly_scoped_token_can_not_create_or_email(self, mock_auth, mock_mail): token = ApiOAuth2PersonalToken( owner=self.user, name='Unauthorized Token', scopes='osf.full_write' ) mock_cas_resp = CasResponse( authenticated=True, user=self.user._id, attributes={ 'accessToken': token.token_id, 'accessTokenScope': [s for s in token.scopes.split(' ')] } ) mock_auth.return_value = self.user, mock_cas_resp assert_equal(User.find(Q('username', 'eq', self.unconfirmed_email)).count(), 0) res = self.app.post_json_api( '{}?send_email=true'.format(self.base_url), self.data, headers={'Authorization': 'Bearer {}'.format(token.token_id)}, expect_errors=True ) assert_equal(res.status_code, 403) assert_equal(User.find(Q('username', 'eq', self.unconfirmed_email)).count(), 0) assert_equal(mock_mail.call_count, 0)
def signup(request): context = {"page":"signup"} if request.method == 'POST': form = SignUpForm(request, data=request.POST) # Check if the form (for sensor) is valid (Django checkup linked to the form) is_valid = form.is_valid() if is_valid: # Get the data from the posted form name = form.cleaned_data['name'] email = form.cleaned_data['email'] password = form.cleaned_data['password'] password2 = form.cleaned_data['password2'] timezone = form.cleaned_data['timezone'] # Create the user user = User(name=name, email=email, password=make_password(password, salt=name+'connect2', hasher='default'), timezone=timezone, prefered_channel="null") # Save it in the database user.save() # Login the user automatically return login(request, user) else: form = SignUpForm() context['login_form'] = form return render(request,'templates/signup.html', context)
def redirect_to_twitter(twitter_handle): """Redirect GET requests for /@TwitterHandle/ to respective the OSF user account if it associated with an active account :param uid: uid for requested User :return: Redirect to User's Twitter account page """ try: user = User.find_one(Q("social.twitter", "iexact", twitter_handle)) except NoResultsFound: raise HTTPError( http.NOT_FOUND, data={ "message_short": "User Not Found", "message_long": "There is no active user associated with the Twitter handle: {0}.".format( twitter_handle ), }, ) except MultipleResultsFound: users = User.find(Q("social.twitter", "iexact", twitter_handle)) message_long = ( "There are multiple OSF accounts associated with the " "Twitter handle: <strong>{0}</strong>. <br /> Please " "select from the accounts below. <br /><ul>".format(markupsafe.escape(twitter_handle)) ) for user in users: message_long += '<li><a href="{0}">{1}</a></li>'.format(user.url, markupsafe.escape(user.fullname)) message_long += "</ul>" raise HTTPError( http.MULTIPLE_CHOICES, data={"message_short": "Multiple Users Found", "message_long": message_long} ) return redirect(user.url)
def test_properly_scoped_token_can_create_without_username_but_not_send_email(self, mock_auth, mock_mail): token = ApiOAuth2PersonalToken( owner=self.user, name='Authorized Token', scopes='osf.users.create' ) mock_cas_resp = CasResponse( authenticated=True, user=self.user._id, attributes={ 'accessToken': token.token_id, 'accessTokenScope': [s for s in token.scopes.split(' ')] } ) mock_auth.return_value = self.user, mock_cas_resp self.data['data']['attributes'] = {'full_name': 'No Email'} assert_equal(User.find(Q('fullname', 'eq', 'No Email')).count(), 0) res = self.app.post_json_api( '{}?send_email=true'.format(self.base_url), self.data, headers={'Authorization': 'Bearer {}'.format(token.token_id)} ) assert_equal(res.status_code, 201) assert_equal(res.json['data']['attributes']['username'], None) assert_equal(User.find(Q('fullname', 'eq', 'No Email')).count(), 1) assert_equal(mock_mail.call_count, 0)
def test_invalid_confirmation_token(self): u1 = User(password='******') u2 = User(password='******') db.session.add(u1) db.session.add(u2) db.session.commit() token = u1.generate_confirmation_token() self.assertFalse(u2.confirm(token))
def test_duplicate_email_change_token(self): u1 = User(email='*****@*****.**', password='******') u2 = User(email='*****@*****.**', password='******') db.session.add(u1) db.session.add(u2) db.session.commit() token = u2.generate_email_change_token('*****@*****.**') self.assertFalse(u2.change_email(token)) self.assertTrue(u2.email == '*****@*****.**')
def test_invalid_reset_token(self): u1 = User(password='******') u2 = User(password='******') db.session.add(u1) db.session.add(u2) db.session.commit() token = u1.generate_reset_token() self.assertFalse(u2.reset_password(token, 'horse')) self.assertTrue(u2.verify_password('dog'))
def test_logged_out_user_cannot_create_other_user_or_send_mail(self, mock_mail): assert_equal(User.find(Q('username', 'eq', self.unconfirmed_email)).count(), 0) res = self.app.post_json_api( '{}?send_email=true'.format(self.base_url), self.data, expect_errors=True ) assert_equal(res.status_code, 401) assert_equal(User.find(Q('username', 'eq', self.unconfirmed_email)).count(), 0) assert_equal(mock_mail.call_count, 0)
def test_finds_user(self): username = '******' user = User(username=username, fullname='Mr Moco') user.affiliated_institutions.append(self.institution) user.save() res = self.app.post(self.url, self.build_payload(username)) assert_equal(res.status_code, 204) user.reload() assert_equal(len(user.affiliated_institutions), 1)
def get_auth(auth, **kwargs): cas_resp = None if not auth.user: # Central Authentication Server OAuth Bearer Token authorization = request.headers.get('Authorization') if authorization and authorization.startswith('Bearer '): client = cas.get_client() try: access_token = cas.parse_auth_header(authorization) cas_resp = client.profile(access_token) except cas.CasError as err: sentry.log_exception() # NOTE: We assume that the request is an AJAX request return json_renderer(err) if cas_resp.authenticated: auth.user = User.load(cas_resp.user) if not auth.user: auth.user = User.from_cookie(request.args.get('cookie')) try: action = request.args['action'] node_id = request.args['nid'] provider_name = request.args['provider'] except KeyError: raise HTTPError(httplib.BAD_REQUEST) node = Node.load(node_id) if not node: raise HTTPError(httplib.NOT_FOUND) check_access(node, auth, action, cas_resp) provider_settings = node.get_addon(provider_name) if not provider_settings: raise HTTPError(httplib.BAD_REQUEST) try: credentials = provider_settings.serialize_waterbutler_credentials() settings = provider_settings.serialize_waterbutler_settings() except exceptions.AddonError: log_exception() raise HTTPError(httplib.BAD_REQUEST) return { 'auth': make_auth(auth.user), # A waterbutler auth dict not an Auth object 'credentials': credentials, 'settings': settings, 'callback_url': node.api_url_for( ('create_waterbutler_log' if not node.is_registration else 'registration_callbacks'), _absolute=True, ), }
def test_game_add_newsfeed(self): """ Check add_newsfeed on Game """ u = User(username="******", email="*****@*****.**") u.save() p2 = Player(user=u, game=self.g, name="hahaha") p2.save() self.assertEqual(Newsfeed.objects.count(), 0) self.g.add_newsfeed(category=Newsfeed.MDC_REPORT, content="something") self.assertEqual(Newsfeed.objects.count(), 1)
def test_game_no_two_players_from_same_user_in_game(self): """ Check if a user can't have 2 players in the same game """ u = User(username="******", email="*****@*****.**") u.save() self.p.user = u self.p.save() p2 = Player(user=u, game=self.g) self.assertRaises(IntegrityError, p2.save)
def test_creates_user(self): username = '******' assert_equal(User.find(Q('username', 'eq', username)).count(), 0) with capture_signals() as mock_signals: res = self.app.post(self.url, self.build_payload(username)) assert_equal(res.status_code, 204) assert_equal(mock_signals.signals_sent(), set([signals.user_confirmed])) user = User.find_one(Q('username', 'eq', username)) assert_true(user) assert_in(self.institution, user.affiliated_institutions)
def test_cookied_requests_can_create_and_email(self, mock_mail): session = Session(data={'auth_user_id': self.user._id}) session.save() cookie = itsdangerous.Signer(settings.SECRET_KEY).sign(session._id) self.app.set_cookie(settings.COOKIE_NAME, str(cookie)) assert_equal(User.find(Q('username', 'eq', self.unconfirmed_email)).count(), 0) res = self.app.post_json_api( '{}?send_email=true'.format(self.base_url), self.data ) assert_equal(res.status_code, 201) assert_equal(User.find(Q('username', 'eq', self.unconfirmed_email)).count(), 1) assert_equal(mock_mail.call_count, 1)
def test_adds_institution(self): username = '******' user = User(username=username, fullname='Mr Moco') user.save() with capture_signals() as mock_signals: res = self.app.post(self.url, self.build_payload(username)) assert_equal(res.status_code, 204) assert_equal(mock_signals.signals_sent(), set()) user.reload() assert_in(self.institution, user.affiliated_institutions)
def send_confirm_email(user, email): """Sends a confirmation email to `user` to a given email. :raises: KeyError if user does not have a confirmation token for the given email. """ confirmation_url = user.get_confirmation_url( email, external=True, force=True, ) try: merge_target = User.find_one(Q('emails', 'eq', email)) except NoResultsFound: merge_target = None mails.send_mail( email, mails.CONFIRM_MERGE if merge_target else mails.CONFIRM_EMAIL, 'plain', user=user, confirmation_url=confirmation_url, email=email, merge_target=merge_target, )
def reset_password_get(auth, uid=None, token=None): """ View for user to land on the reset password page. HTTp Method: GET :param auth: the authentication state :param uid: the user id :param token: the token in verification key :return :raises: HTTPError(http.BAD_REQUEST) if verification key for the user is invalid, has expired or was used """ # if users are logged in, log them out and redirect back to this page if auth.logged_in: return auth_logout(redirect_url=request.url) # Check if request bears a valid pair of `uid` and `token` user_obj = User.load(uid) if not (user_obj and user_obj.verify_password_token(token=token)): error_data = { 'message_short': 'Invalid Request.', 'message_long': 'The requested URL is invalid, has expired, or was already used', } raise HTTPError(http.BAD_REQUEST, data=error_data) # refresh the verification key (v2) user_obj.verification_key_v2 = generate_verification_key(verification_type='password') user_obj.save() return { 'uid': user_obj._id, 'token': user_obj.verification_key_v2['token'], }
def confirm_email_get(**kwargs): """View for email confirmation links. Authenticates and redirects to user settings page if confirmation is successful, otherwise shows an "Expired Link" error. methods: GET """ user = User.load(kwargs['uid']) token = kwargs['token'] if user: if user.confirm_email(token): # Confirm and register the user user.date_last_login = datetime.datetime.utcnow() user.save() # Go to settings page status.push_status_message(language.WELCOME_MESSAGE, 'success') response = redirect('/settings/') return framework.auth.authenticate(user, response=response) # Return data for the error template return { 'code': http.BAD_REQUEST, 'message_short': 'Link Expired', 'message_long': language.LINK_EXPIRED }, http.BAD_REQUEST
def auth_email_logout(token, user): """ When a user is adding an email or merging an account, add the email to the user and log them out. """ redirect_url = cas.get_logout_url(service_url=cas.get_login_url(service_url=web_url_for('index', _absolute=True))) try: unconfirmed_email = user.get_unconfirmed_email_for_token(token) except InvalidTokenError: raise HTTPError(http.BAD_REQUEST, data={ 'message_short': 'Bad token', 'message_long': 'The provided token is invalid.' }) except ExpiredTokenError: status.push_status_message('The private link you used is expired.') raise HTTPError(http.BAD_REQUEST, data={ 'message_short': 'Expired link', 'message_long': 'The private link you used is expired.' }) try: user_merge = User.find_one(Q('emails', 'eq', unconfirmed_email)) except NoResultsFound: user_merge = False if user_merge: remove_sessions_for_user(user_merge) user.email_verifications[token]['confirmed'] = True user.save() remove_sessions_for_user(user) resp = redirect(redirect_url) resp.delete_cookie(settings.COOKIE_NAME, domain=settings.OSF_COOKIE_DOMAIN) return resp
def sync_data_from_mailchimp(**kwargs): """Endpoint that the mailchimp webhook sends its data to""" key = request.args.get("key") if key == settings.MAILCHIMP_WEBHOOK_SECRET_KEY: r = request action = r.values["type"] list_name = mailchimp_utils.get_list_name_from_id(list_id=r.values["data[list_id]"]) username = r.values["data[email]"] try: user = User.find_one(Q("username", "eq", username)) except NoResultsFound: sentry.log_exception() sentry.log_message("A user with this username does not exist.") raise HTTPError( 404, data=dict(message_short="User not found", message_long="A user with this username does not exist") ) if action == "unsubscribe": user.mailchimp_mailing_lists[list_name] = False user.save() elif action == "subscribe": user.mailchimp_mailing_lists[list_name] = True user.save() else: # TODO: get tests to pass with sentry logging # sentry.log_exception() # sentry.log_message("Unauthorized request to the OSF.") raise HTTPError(http.UNAUTHORIZED)
def process_project_search_results(results, **kwargs): """ :param results: list of projects from the modular ODM search :return: we return the entire search result, which is a list of dictionaries. This includes the list of contributors. """ user = kwargs['auth'].user ret = [] for project in results: authors = get_node_contributors_abbrev(project=project, auth=kwargs['auth']) authors_html = '' for author in authors['contributors']: a = User.load(author['user_id']) authors_html += '<a href="%s">%s</a>' % (a.url, a.fullname) authors_html += author['separator'] + ' ' authors_html += ' ' + authors['others_count'] ret.append({ 'id': project._id, 'label': project.title, 'value': project.title, 'category': 'My Projects' if user in project.contributors else 'Public Projects', 'authors': authors_html, }) return ret
def load_user(userid): try: return User.select().where( User._id == int(userid) ).get() except DoesNotExist: return None
def osf_user(self): # import on call to avoid interference w/ django's manage.py commands like collectstatic from website.models import User as OsfUserModel if not self.osf_id: raise RuntimeError('This user does not have an associated Osf User') return OsfUserModel.load(self.osf_id)
def move_subscription(remove_users, source_event, source_node, new_event, new_node): """Moves subscription from old_node to new_node :param remove_users: dictionary of lists of users to remove from the subscription :param source_event: A specific guid event <guid>_file_updated :param source_node: Instance of Node :param new_event: A specific guid event :param new_node: Instance of Node :return: Returns a NOTIFICATION_TYPES list of removed users without permissions """ if source_node == new_node: return old_sub = NotificationSubscription.load(to_subscription_key(source_node._id, source_event)) if not old_sub: return elif old_sub: old_sub.update_fields(_id=to_subscription_key(new_node._id, new_event), event_name=new_event, owner=new_node) new_sub = old_sub # Remove users that don't have permission on the new node. for notification_type in constants.NOTIFICATION_TYPES: if new_sub: for user_id in remove_users[notification_type]: if user_id in getattr(new_sub, notification_type, []): user = User.load(user_id) new_sub.remove_user_from_subscription(user)
def get_events(self, date): """ Get all node logs from a given date for a 24 hour period, ending at the date given. """ super(UserDomainEvents, self).get_events(date) # In the end, turn the date back into a datetime at midnight for queries date = datetime(date.year, date.month, date.day).replace(tzinfo=pytz.UTC) logger.info('Gathering user domains between {} and {}'.format( date, (date + timedelta(1)).isoformat() )) user_query = Q('date_confirmed', 'lt', date + timedelta(1)) & Q('date_confirmed', 'gte', date) users = User.find(user_query) user_domain_events = [] for user in users: user_date = user.date_confirmed.replace(tzinfo=pytz.UTC) event = { 'keen': {'timestamp': user_date.isoformat()}, 'date': user_date.isoformat(), 'domain': user.username.split('@')[-1] } user_domain_events.append(event) logger.info('User domains collected. {} users and their email domains.'.format(len(user_domain_events))) return user_domain_events
def tearDown(self): super(TestUsersCreate, self).tearDown() self.app.reset() # clears cookies User.remove()
def tearDown(self, *args, **kwargs): super(SessionUtilsTestCase, self).tearDown(*args, **kwargs) User.remove() Session.remove()
def get_object(self, queryset=None): return (Node.load(self.kwargs.get('node_id')), User.load(self.kwargs.get('user_id')))
def profile_view_id(uid, auth): user = User.load(uid) is_profile = auth and auth.user == user # Embed node data, so profile node lists can be rendered return _profile_view(user, is_profile, embed_nodes=True)
def search_contributor(query, page=0, size=10, exclude=None, current_user=None): """Search for contributors to add to a project using elastic search. Request must include JSON data with a "query" field. :param query: The substring of the username to search for :param page: For pagination, the page number to use for results :param size: For pagination, the number of results per page :param exclude: A list of User objects to exclude from the search :param current_user: A User object of the current user :return: List of dictionaries, each containing the ID, full name, most recent employment and education, gravatar URL of an OSF user """ start = (page * size) items = re.split(r'[\s-]+', query) exclude = exclude or [] normalized_items = [] for item in items: try: normalized_item = six.u(item) except TypeError: normalized_item = item normalized_item = unicodedata.normalize('NFKD', normalized_item).encode( 'ascii', 'ignore') normalized_items.append(normalized_item) items = normalized_items query = " AND ".join('{}*~'.format(re.escape(item)) for item in items) + \ "".join(' NOT id:"{}"'.format(excluded._id) for excluded in exclude) results = search(build_query(query, start=start, size=size), index=INDEX, doc_type='user') docs = results['results'] pages = math.ceil(results['counts'].get('user', 0) / size) validate_page_num(page, pages) users = [] for doc in docs: # TODO: use utils.serialize_user user = User.load(doc['id']) if current_user and current_user._id == user._id: n_projects_in_common = -1 elif current_user: n_projects_in_common = current_user.n_projects_in_common(user) else: n_projects_in_common = 0 if user is None: logger.error('Could not load user {0}'.format(doc['id'])) continue if user.is_active: # exclude merged, unregistered, etc. current_employment = None education = None if user.jobs: current_employment = user.jobs[0]['institution'] if user.schools: education = user.schools[0]['institution'] users.append({ 'fullname': doc['user'], 'id': doc['id'], 'employment': current_employment, 'education': education, 'n_projects_in_common': n_projects_in_common, 'gravatar_url': gravatar(user, use_ssl=True, size=settings.PROFILE_IMAGE_MEDIUM), 'profile_url': user.profile_url, 'registered': user.is_registered, 'active': user.is_active }) return { 'users': users, 'total': results['counts']['total'], 'pages': pages, 'page': page, }
def external_login_email_post(): """ View to handle email submission for first-time oauth-login user. HTTP Method: POST """ form = ResendConfirmationForm(request.form) session = get_session() if not session.is_external_first_login: raise HTTPError(http.UNAUTHORIZED) external_id_provider = session.data['auth_user_external_id_provider'] external_id = session.data['auth_user_external_id'] fullname = session.data['auth_user_fullname'] if form.validate(): clean_email = form.email.data user = get_user(email=clean_email) external_identity = { external_id_provider: { external_id: None, }, } try: ensure_external_identity_uniqueness(external_id_provider, external_id, user) except ValidationError as e: raise HTTPError(http.FORBIDDEN, e.message) if user: # 1. update user oauth, with pending status external_identity[external_id_provider][external_id] = 'LINK' if external_id_provider in user.external_identity: user.external_identity[external_id_provider].update(external_identity[external_id_provider]) else: user.external_identity.update(external_identity) # 2. add unconfirmed email and send confirmation email user.add_unconfirmed_email(clean_email, external_identity=external_identity) user.save() send_confirm_email(user, clean_email, external_id_provider=external_id_provider, external_id=external_id) # 3. notify user message = language.EXTERNAL_LOGIN_EMAIL_LINK_SUCCESS.format( external_id_provider=external_id_provider, email=user.username ) kind = 'success' # 4. remove session and osf cookie remove_session(session) else: # 1. create unconfirmed user with pending status external_identity[external_id_provider][external_id] = 'CREATE' user = User.create_unconfirmed( username=clean_email, password=str(uuid.uuid4()), fullname=fullname, external_identity=external_identity, campaign=None ) # TODO: [#OSF-6934] update social fields, verified social fields cannot be modified user.save() # 3. send confirmation email send_confirm_email(user, user.username, external_id_provider=external_id_provider, external_id=external_id) # 4. notify user message = language.EXTERNAL_LOGIN_EMAIL_CREATE_SUCCESS.format( external_id_provider=external_id_provider, email=user.username ) kind = 'success' # 5. remove session remove_session(session) status.push_status_message(message, kind=kind, trust=False) else: forms.push_errors_to_status(form.errors) # Don't go anywhere return { 'form': form, 'external_id_provider': external_id_provider }
def tearDown(self): super(CitationsNodeTestCase, self).tearDown() Node.remove() User.remove()
def tearDown(self): User.remove()
def get_gravatar(uid, size=None): return { 'gravatar_url': profile_utils.get_gravatar(User.load(uid), size=size) }
def get_target_user(auth, uid=None): target = User.load(uid) if uid else auth.user if target is None: raise HTTPError(http.NOT_FOUND) return target
def get_profile_summary(user_id, formatter='long'): user = User.load(user_id) return user.get_summary(formatter)
def profile_view_id(uid, auth): user = User.load(uid) is_profile = auth and auth.user == user return _profile_view(user, is_profile)
def get_active_users(extra=None): query = (Q('is_registered', 'eq', True) & Q('password', 'ne', None) & Q('merged_by', 'eq', None) & Q('date_confirmed', 'ne', None) & Q('date_disabled', ' eq', None)) query = query & extra if extra else query return User.find(query)
def get_events(self, date): super(InstitutionSummary, self).get_events(date) institutions = self.get_institutions() counts = [] # Convert to a datetime at midnight for queries and the timestamp timestamp_datetime = datetime(date.year, date.month, date.day).replace(tzinfo=pytz.UTC) query_datetime = timestamp_datetime + timedelta(1) for institution in institutions: user_query = Q('_affiliated_institutions', 'eq', institution.node) node_query = (Q('is_deleted', 'ne', True) & Q('is_folder', 'ne', True) & Q('date_created', 'lt', query_datetime)) registration_query = node_query & Q('is_registration', 'eq', True) non_registration_query = node_query & Q('is_registration', 'eq', False) project_query = non_registration_query & Q('parent_node', 'eq', None) registered_project_query = registration_query & Q( 'parent_node', 'eq', None) public_query = Q('is_public', 'eq', True) private_query = Q('is_public', 'eq', False) node_public_query = non_registration_query & public_query node_private_query = non_registration_query & private_query project_public_query = project_query & public_query project_private_query = project_query & private_query registered_node_public_query = registration_query & public_query registered_node_private_query = registration_query & private_query registered_project_public_query = registered_project_query & public_query registered_project_private_query = registered_project_query & private_query count = { 'institution': { 'id': institution._id, 'name': institution.name, }, 'users': { 'total': User.find(user_query).count(), }, 'nodes': { 'total': Node.find_by_institutions(institution, node_query).count(), 'public': Node.find_by_institutions(institution, node_public_query).count(), 'private': Node.find_by_institutions(institution, node_private_query).count(), }, 'projects': { 'total': Node.find_by_institutions(institution, project_query).count(), 'public': Node.find_by_institutions(institution, project_public_query).count(), 'private': Node.find_by_institutions(institution, project_private_query).count(), }, 'registered_nodes': { 'total': Node.find_by_institutions(institution, registration_query).count(), 'public': Node.find_by_institutions( institution, registered_node_public_query).count(), 'embargoed': Node.find_by_institutions( institution, registered_node_private_query).count(), }, 'registered_projects': { 'total': Node.find_by_institutions( institution, registered_project_query).count(), 'public': Node.find_by_institutions( institution, registered_project_public_query).count(), 'embargoed': Node.find_by_institutions( institution, registered_project_private_query).count(), }, 'keen': { 'timestamp': timestamp_datetime.isoformat() } } logger.info( '{} Nodes counted. Nodes: {}, Projects: {}, Registered Nodes: {}, Registered Projects: {}' .format(count['institution']['name'], count['nodes']['total'], count['projects']['total'], count['registered_nodes']['total'], count['registered_projects']['total'])) counts.append(count) return counts
import os from website import db from website.models import User from website.admin import add_admin from website.exam_admin import add_exam db.reflect() db.drop_all() db.create_all() os.chdir(os.path.join('tests', 'testdata')) add_exam('silly1', 'Silly 1', os.path.join('exams', 'silly1.json'), os.path.join('exams', 'silly1_answers.json')) add_admin('admin', 'pass', 'Admin') user1 = User(username='******', role='examinee', fullname='Thomas Hardy', exam_id='silly1', answer_page='{}') user1.hash_password('pass') db.session.add(user1) user2 = User(username='******', role='examinee', fullname='Franz Kafka', exam_id='silly1', answer_page='{}') user2.hash_password('pass') db.session.add(user2) db.session.commit()
def remove_contributor(request, node_id, user_id): user = User.load(user_id) node = Node.load(node_id) node.remove_contributor(user, None, log=False) # TODO: log on OSF as admin return redirect(reverse_node(node_id))
def search_contributor(query, page=0, size=10, exclude=[], current_user=None): """Search for contributors to add to a project using elastic search. Request must include JSON data with a "query" field. :param query: The substring of the username to search for :param page: For pagination, the page number to use for results :param size: For pagination, the number of results per page :param exclude: A list of User objects to exclude from the search :param current_user: A User object of the current user :return: List of dictionaries, each containing the ID, full name, most recent employment and education, gravatar URL of an OSF user """ start = (page * size) items = re.split(r'[\s-]+', query) query = '' query = " AND ".join('{}*~'.format(re.escape(item)) for item in items) + \ "".join(' NOT "{}"'.format(excluded) for excluded in exclude) results = search(build_query(query, start=start, size=size), index='website', doc_type='user') docs = results['results'] pages = math.ceil(results['counts'].get('user', 0) / size) users = [] for doc in docs: # TODO: use utils.serialize_user user = User.load(doc['id']) if current_user: n_projects_in_common = current_user.n_projects_in_common(user) else: n_projects_in_common = 0 if user is None: logger.error('Could not load user {0}'.format(doc['id'])) continue if user.is_active: # exclude merged, unregistered, etc. current_employment = None education = None if user.jobs: current_employment = user.jobs[0]['institution'] if user.schools: education = user.schools[0]['institution'] users.append({ 'fullname': doc['user'], 'id': doc['id'], 'employment': current_employment, 'education': education, 'n_projects_in_common': n_projects_in_common, 'gravatar_url': gravatar( user, use_ssl=True, size=settings.GRAVATAR_SIZE_ADD_CONTRIBUTOR, ), 'profile_url': user.profile_url, 'registered': user.is_registered, 'active': user.is_active }) return { 'users': users, 'total': results['counts']['total'], 'pages': pages, 'page': page, }
def get_queryset(self): # TODO: sort query = self.get_query_from_request() return User.find(query)
def test_get_targets(self): test = User.find( Q('date_confirmed', 'ne', None) & Q('date_last_login', 'ne', None)) assert test is not None
def create_waterbutler_log(payload, **kwargs): with TokuTransaction(): try: auth = payload['auth'] action = LOG_ACTION_MAP[payload['action']] except KeyError: raise HTTPError(httplib.BAD_REQUEST) user = User.load(auth['id']) if user is None: raise HTTPError(httplib.BAD_REQUEST) auth = Auth(user=user) node = kwargs['node'] or kwargs['project'] if action in (NodeLog.FILE_MOVED, NodeLog.FILE_COPIED): for bundle in ('source', 'destination'): for key in ('provider', 'materialized', 'name', 'nid'): if key not in payload[bundle]: raise HTTPError(httplib.BAD_REQUEST) dest = payload['destination'] src = payload['source'] if src is not None and dest is not None: dest_path = dest['materialized'] src_path = src['materialized'] if dest_path.endswith('/') and src_path.endswith('/'): dest_path = os.path.dirname(dest_path) src_path = os.path.dirname(src_path) if (os.path.split(dest_path)[0] == os.path.split(src_path)[0] and dest['provider'] == src['provider'] and dest['nid'] == src['nid'] and dest['name'] != src['name']): action = LOG_ACTION_MAP['rename'] destination_node = node # For clarity source_node = Node.load(payload['source']['nid']) source = source_node.get_addon(payload['source']['provider']) destination = node.get_addon(payload['destination']['provider']) payload['source'].update({ 'materialized': payload['source']['materialized'].lstrip('/'), 'addon': source.config.full_name, 'url': source_node.web_url_for( 'addon_view_or_download_file', path=payload['source']['path'].lstrip('/'), provider=payload['source']['provider']), 'node': { '_id': source_node._id, 'url': source_node.url, 'title': source_node.title, } }) payload['destination'].update({ 'materialized': payload['destination']['materialized'].lstrip('/'), 'addon': destination.config.full_name, 'url': destination_node.web_url_for( 'addon_view_or_download_file', path=payload['destination']['path'].lstrip('/'), provider=payload['destination']['provider']), 'node': { '_id': destination_node._id, 'url': destination_node.url, 'title': destination_node.title, } }) payload.update({ 'node': destination_node._id, 'project': destination_node.parent_id, }) if not payload.get('errors'): destination_node.add_log(action=action, auth=auth, params=payload) if payload.get('email') is True or payload.get('errors'): mails.send_mail( user.username, mails.FILE_OPERATION_FAILED if payload.get('errors') else mails.FILE_OPERATION_SUCCESS, action=payload['action'], source_node=source_node, destination_node=destination_node, source_path=payload['source']['materialized'], destination_path=payload['source']['materialized'], source_addon=payload['source']['addon'], destination_addon=payload['destination']['addon'], ) if payload.get('errors'): # Action failed but our function succeeded # Bail out to avoid file_signals return {'status': 'success'} else: try: metadata = payload['metadata'] node_addon = node.get_addon(payload['provider']) except KeyError: raise HTTPError(httplib.BAD_REQUEST) if node_addon is None: raise HTTPError(httplib.BAD_REQUEST) metadata['path'] = metadata['path'].lstrip('/') node_addon.create_waterbutler_log(auth, action, metadata) with TokuTransaction(): file_signals.file_updated.send(node=node, user=user, event_type=action, payload=payload) return {'status': 'success'}
def get_targets(): return User.find( Q('date_confirmed', 'eq', None) & Q('date_last_login', 'ne', None))
def tearDown(self): super(TestTokenList, self).tearDown() ApiOAuth2PersonalToken.remove() User.remove()
def create_waterbutler_log(payload, **kwargs): try: auth = payload['auth'] action = LOG_ACTION_MAP[payload['action']] except KeyError: raise HTTPError(httplib.BAD_REQUEST) user = User.load(auth['id']) if user is None: raise HTTPError(httplib.BAD_REQUEST) auth = Auth(user=user) node = kwargs['node'] or kwargs['project'] if action in (NodeLog.FILE_MOVED, NodeLog.FILE_COPIED): for bundle in ('source', 'destination'): for key in ('provider', 'materialized', 'name', 'nid'): if key not in payload[bundle]: raise HTTPError(httplib.BAD_REQUEST) destination_node = node # For clarity source_node = Node.load(payload['source']['nid']) source = source_node.get_addon(payload['source']['provider']) destination = node.get_addon(payload['destination']['provider']) payload['source'].update({ 'materialized': payload['source']['materialized'].lstrip('/'), 'addon': source.config.full_name, 'url': source_node.web_url_for('addon_view_or_download_file', path=payload['source']['path'].lstrip('/'), provider=payload['source']['provider']), 'node': { '_id': source_node._id, 'url': source_node.url, 'title': source_node.title, } }) payload['destination'].update({ 'materialized': payload['destination']['materialized'].lstrip('/'), 'addon': destination.config.full_name, 'url': destination_node.web_url_for( 'addon_view_or_download_file', path=payload['destination']['path'].lstrip('/'), provider=payload['destination']['provider']), 'node': { '_id': destination_node._id, 'url': destination_node.url, 'title': destination_node.title, } }) payload.update({ 'node': destination_node._id, 'project': destination_node.parent_id, }) if not payload.get('errors'): destination_node.add_log(action=action, auth=auth, params=payload) if payload.get('email') is True or payload.get('errors'): mails.send_mail( user.username, mails.FILE_OPERATION_FAILED if payload.get('errors') else mails.FILE_OPERATION_SUCCESS, action=payload['action'], source_node=source_node, destination_node=destination_node, source_path=payload['source']['path'], destination_path=payload['source']['path'], source_addon=payload['source']['addon'], destination_addon=payload['destination']['addon'], ) else: try: metadata = payload['metadata'] node_addon = node.get_addon(payload['provider']) except KeyError: raise HTTPError(httplib.BAD_REQUEST) if node_addon is None: raise HTTPError(httplib.BAD_REQUEST) metadata['path'] = metadata['path'].lstrip('/') node_addon.create_waterbutler_log(auth, action, metadata) return {'status': 'success'}
def get_user_by_id(user_id): return User.get_by_id(get_session(), user_id)
def get_auth(auth, **kwargs): cas_resp = None if not auth.user: # Central Authentication Server OAuth Bearer Token authorization = request.headers.get('Authorization') if authorization and authorization.startswith('Bearer '): client = cas.get_client() try: access_token = cas.parse_auth_header(authorization) cas_resp = client.profile(access_token) except cas.CasError as err: sentry.log_exception() # NOTE: We assume that the request is an AJAX request return json_renderer(err) if cas_resp.authenticated: auth.user = User.load(cas_resp.user) try: data = jwt.decode(request.args.get('payload', ''), settings.WATERBUTLER_JWT_SECRET, options={'require_exp': True}, algorithm=settings.WATERBUTLER_JWT_ALGORITHM)['data'] except (jwt.InvalidTokenError, KeyError): raise HTTPError(httplib.FORBIDDEN) if not auth.user: auth.user = User.from_cookie(data.get('cookie', '')) try: action = data['action'] node_id = data['nid'] provider_name = data['provider'] except KeyError: raise HTTPError(httplib.BAD_REQUEST) node = Node.load(node_id) if not node: raise HTTPError(httplib.NOT_FOUND) check_access(node, auth, action, cas_resp) provider_settings = node.get_addon(provider_name) if not provider_settings: raise HTTPError(httplib.BAD_REQUEST) try: credentials = provider_settings.serialize_waterbutler_credentials() waterbutler_settings = provider_settings.serialize_waterbutler_settings( ) except exceptions.AddonError: log_exception() raise HTTPError(httplib.BAD_REQUEST) return jwt.encode( { 'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=settings.WATERBUTLER_JWT_EXPIRATION), 'data': { 'auth': make_auth( auth.user), # A waterbutler auth dict not an Auth object 'credentials': credentials, 'settings': waterbutler_settings, 'callback_url': node.api_url_for( ('create_waterbutler_log' if not node.is_registration else 'registration_callbacks'), _absolute=True, ), } }, settings.WATERBUTLER_JWT_SECRET, algorithm=settings.WATERBUTLER_JWT_ALGORITHM)
def osfstorage_create_child(file_node, payload, node_addon, **kwargs): parent = file_node # Just for clarity name = payload.get('name') user = User.load(payload.get('user')) is_folder = payload.get('kind') == 'folder' if not (name or user) or '/' in name: raise HTTPError(httplib.BAD_REQUEST) try: if is_folder: created, file_node = True, parent.append_folder(name) else: created, file_node = True, parent.append_file(name) except KeyExistsException: created, file_node = False, parent.find_child_by_name( name, kind=int(not is_folder)) if not created and is_folder: raise HTTPError( httplib.CONFLICT, data={ 'message': 'Cannot create folder "{name}" because a file or folder already exists at path "{path}"' .format( name=file_node.name, path=file_node.materialized_path, ) }) if not is_folder: try: if file_node.checkout is None or file_node.checkout._id == user._id: version = file_node.create_version( user, dict( payload['settings'], **dict( payload['worker'], **{ 'object': payload['metadata']['name'], 'service': payload['metadata']['provider'], })), dict(payload['metadata'], **payload['hashes'])) version_id = version._id archive_exists = version.archive is not None else: raise HTTPError( httplib.FORBIDDEN, data={ 'message_long': 'File cannot be updated due to checkout status.' }) except KeyError: raise HTTPError(httplib.BAD_REQUEST) else: version_id = None archive_exists = False return { 'status': 'success', 'archive': not archive_exists, # Should waterbutler also archive this file 'data': file_node.serialize(), 'version': version_id, }, httplib.CREATED if created else httplib.OK
def confirm_email_get(token, auth=None, **kwargs): """ View for email confirmation links. Authenticates and redirects to user settings page if confirmation is successful, otherwise shows an "Expired Link" error. HTTP Method: GET """ user = User.load(kwargs['uid']) is_merge = 'confirm_merge' in request.args is_initial_confirmation = not user.date_confirmed log_out = request.args.get('logout', None) if user is None: raise HTTPError(http.NOT_FOUND) # if the user is merging or adding an email (they already are an osf user) if log_out: return auth_email_logout(token, user) if auth and auth.user and (auth.user._id == user._id or auth.user._id == user.merged_by._id): if not is_merge: # determine if the user registered through a campaign campaign = campaigns.campaign_for_user(user) if campaign: return redirect(campaigns.campaign_url_for(campaign)) # go to home page with push notification if len(auth.user.emails) == 1 and len(auth.user.email_verifications) == 0: status.push_status_message(language.WELCOME_MESSAGE, kind='default', jumbotron=True, trust=True) if token in auth.user.email_verifications: status.push_status_message(language.CONFIRM_ALTERNATE_EMAIL_ERROR, kind='danger', trust=True) return redirect(web_url_for('index')) status.push_status_message(language.MERGE_COMPLETE, kind='success', trust=False) return redirect(web_url_for('user_account')) try: user.confirm_email(token, merge=is_merge) except exceptions.EmailConfirmTokenError as e: raise HTTPError(http.BAD_REQUEST, data={ 'message_short': e.message_short, 'message_long': e.message_long }) if is_initial_confirmation: user.date_last_login = datetime.datetime.utcnow() user.save() # send out our welcome message mails.send_mail( to_addr=user.username, mail=mails.WELCOME, mimetype='html', user=user ) # new random verification key, allows CAS to authenticate the user w/o password one-time only. user.verification_key = generate_verification_key() user.save() # redirect to CAS and authenticate the user with a verification key. return redirect(cas.get_login_url( request.url, username=user.username, verification_key=user.verification_key ))
def external_login_confirm_email_get(auth, uid, token): """ View for email confirmation links when user first login through external identity provider. HTTP Method: GET :param auth: the auth context :param uid: the user's primary key :param token: the verification token """ user = User.load(uid) if not user: raise HTTPError(http.BAD_REQUEST) if auth and auth.user: if auth.user._id == user._id: new = request.args.get('new', None) if new: status.push_status_message(language.WELCOME_MESSAGE, kind='default', jumbotron=True, trust=True) return redirect(web_url_for('index')) # If user is already logged in, log user out and retry request return auth_logout(redirect_url=request.url) # token is invalid if token not in user.email_verifications: raise HTTPError(http.BAD_REQUEST) verification = user.email_verifications[token] email = verification['email'] provider = verification['external_identity'].keys()[0] provider_id = verification['external_identity'][provider].keys()[0] # wrong provider if provider not in user.external_identity: raise HTTPError(http.BAD_REQUEST) external_status = user.external_identity[provider][provider_id] try: ensure_external_identity_uniqueness(provider, provider_id, user) except ValidationError as e: raise HTTPError(http.FORBIDDEN, e.message) if not user.is_registered: user.set_password(uuid.uuid4(), notify=False) user.register(email) if email.lower() not in user.emails: user.emails.append(email.lower()) user.date_last_logged_in = datetime.datetime.utcnow() user.external_identity[provider][provider_id] = 'VERIFIED' user.social[provider.lower()] = provider_id del user.email_verifications[token] user.verification_key = generate_verification_key() user.save() service_url = request.url if external_status == 'CREATE': mails.send_mail( to_addr=user.username, mail=mails.WELCOME, mimetype='html', user=user ) service_url = service_url + '?new=true' elif external_status == 'LINK': mails.send_mail( user=user, to_addr=user.username, mail=mails.EXTERNAL_LOGIN_LINK_SUCCESS, external_id_provider=provider, ) # redirect to CAS and authenticate the user with the verification key return redirect(cas.get_login_url( service_url, username=user.username, verification_key=user.verification_key ))
def main(): number_users = User.find().count() projects = get_projects() projects_forked = get_projects_forked() projects_registered = get_projects_registered() number_projects = len(projects) projects_public = get_projects_public() number_projects_public = projects_public.count() number_projects_forked = len(projects_forked) number_projects_registered = len(projects_registered) number_downloads_unique, number_downloads_total = get_number_downloads_unique_and_total( ) active_users = get_active_users() active_users_invited = get_active_users(Q('is_invited', 'eq', True)) dropbox_metrics = get_dropbox_metrics() extended_profile_counts = profile.get_profile_counts() private_links = get_private_links() folders = get_folders() downloads_unique, downloads_total = count_file_downloads() node_counts = count_user_nodes(active_users) nodes_at_least_1 = count_at_least(node_counts, 1) nodes_at_least_3 = count_at_least(node_counts, 3) rows = [ ['number_users', number_users], ['number_projects', number_projects], ['number_projects_public', number_projects_public], ['number_projects_forked', number_projects_forked], ['number_projects_registered', number_projects_registered], ['number_downloads_total', number_downloads_total], ['number_downloads_unique', number_downloads_unique], ['active-users', active_users.count()], ['active-users-invited', active_users_invited.count()], ['dropbox-users-enabled', dropbox_metrics['enabled']], ['dropbox-users-authorized', dropbox_metrics['authorized']], ['dropbox-users-linked', dropbox_metrics['linked']], ['profile-edits', extended_profile_counts['any']], ['view-only-links', private_links.count()], ['folders', folders.count()], ['downloads-unique', downloads_unique], ['downloads-total', downloads_total], ['nodes-gte-1', nodes_at_least_1], ['nodes-gte-3', nodes_at_least_3], ] rows.extend(get_log_counts(active_users)) table = tabulate.tabulate( rows, headers=['label', 'value'], ) with open(os.path.join(settings.ANALYTICS_PATH, 'main.txt'), 'w') as fp: fp.write(table) tabulate_emails.main() tabulate_logs.main()
def profile_view_id_json(uid, auth): user = User.load(uid) is_profile = auth and auth.user == user # Do NOT embed nodes, they aren't necessary return _profile_view(user, is_profile, embed_nodes=False)