def _add_global_test_data(session): global_passwords['contributor'] = 'super pass' global_passwords['contributor2'] = 'better pass' global_passwords['moderator'] = 'even better pass' contributor_profile = UserProfile( categories=['amateur'], locales=[ DocumentLocale(title='', description='Me', lang='en'), DocumentLocale(title='', description='Moi', lang='fr')], geometry=DocumentGeometry(geom='SRID=3857;POINT(635956 5723604)')) contributor = User( name='Contributor', username='******', email='*****@*****.**', forum_username='******', password='******', email_validated=True, profile=contributor_profile) contributor2_profile = UserProfile( categories=['amateur'], locales=[DocumentLocale(title='...', lang='en')]) contributor2 = User( name='Contributor 2', username='******', email='*****@*****.**', forum_username='******', password='******', email_validated=True, profile=contributor2_profile) moderator_profile = UserProfile( categories=['mountain_guide'], locales=[DocumentLocale(title='', lang='en')]) moderator = User( name='Moderator', username='******', email='*****@*****.**', forum_username='******', moderator=True, password='******', email_validated=True, profile=moderator_profile) users = [moderator, contributor, contributor2] session.add_all(users) session.flush() key = settings['jwtauth.master_secret'] algorithm = 'HS256' now = datetime.datetime.utcnow() exp = now + datetime.timedelta(weeks=10) for user in [moderator, contributor, contributor2]: claims = create_claims(user, exp) token = jwt.encode(claims, key=key, algorithm=algorithm). \ decode('utf-8') add_or_retrieve_token(token, exp, user.id) global_userids[user.username] = user.id global_tokens[user.username] = token
def setUp(self): # noqa BaseTestCase.setUp(self) self.waypoint1 = Waypoint(waypoint_type='summit') self.waypoint2 = Waypoint(waypoint_type='summit') self.route1 = Route(activities=['hiking']) self.route2 = Route(activities=['hiking']) self.user_profile1 = UserProfile() self.user_profile2 = UserProfile() self.session.add_all([ self.waypoint1, self.waypoint2, self.route1, self.route2, self.user_profile1, self.user_profile2 ]) self.session.flush()
def test_last_modified(self): """Check that the last modified field is set. """ profile = UserProfile() self.session.add(profile) self.session.flush() user = User(id=profile.document_id, username='******', name='user', forum_username='******', email_validated=True, email='*****@*****.**', password='******') self.session.add(user) self.session.flush() self.session.refresh(user) self.assertIsNotNone(user.last_modified) user.name = 'changed' self.session.flush() self.session.refresh(user) self.assertIsNotNone(user.last_modified)
def test_update_cache_version_user_document_version(self): """ Test that a document is invalidated if a user name of a user that edited one of the document versions is changed. """ waypoint = Waypoint(waypoint_type='summit', elevation=2203, locales=[ WaypointLocale(lang='en', title='...', description='...') ]) user_profile = UserProfile() user = User(name='test_user', username='******', email='*****@*****.**', forum_username='******', password='******', email_validated=True, profile=user_profile) self.session.add_all([waypoint, user_profile, user]) self.session.flush() DocumentRest.create_new_version(waypoint, user.id) update_cache_version(user_profile) cache_version_user_profile = self.session.query(CacheVersion).get( user_profile.document_id) cache_version_waypoint = self.session.query(CacheVersion).get( waypoint.document_id) self.assertEqual(cache_version_waypoint.version, 2) self.assertEqual(cache_version_user_profile.version, 2)
def test_to_archive(self): user_profile = UserProfile(document_id=1, categories=['amateur'], locales=[ DocumentLocale(id=2, lang='en', title='Me', summary='...'), DocumentLocale(id=3, lang='fr', title='Moi', summary='...'), ]) user_profile_archive = user_profile.to_archive() self.assertIsNone(user_profile_archive.id) self.assertEqual(user_profile_archive.document_id, user_profile.document_id) self.assertEqual(user_profile_archive.categories, user_profile.categories) archive_locals = user_profile.get_archive_locales() self.assertEqual(len(archive_locals), 2) locale = user_profile.locales[0] locale_archive = archive_locals[0] self.assertIsNot(locale_archive, locale) self.assertIsNone(locale_archive.id) self.assertEqual(locale_archive.lang, locale.lang) self.assertEqual(locale_archive.title, locale.title)
def post(self): user = schema_create_user.objectify(self.request.validated) user.password = self.request.validated['password'] user.update_validation_nonce(Purpose.registration, VALIDATION_EXPIRE_DAYS) # directly create the user profile, the document id of the profile # is the user id lang = user.lang user.profile = UserProfile( categories=['amateur'], locales=[DocumentLocale(lang=lang, title='')]) DBSession.add(user) try: DBSession.flush() except: log.warning('Error persisting user', exc_info=True) raise HTTPInternalServerError('Error persisting user') # also create a version for the profile DocumentRest.create_new_version(user.profile, user.id) # The user needs validation email_service = get_email_service(self.request) nonce = user.validation_nonce settings = self.request.registry.settings link = settings['mail.validate_register_url_template'] % nonce email_service.send_registration_confirmation(user, link) return to_json_dict(user, schema_user)
def test_check_changes_on_user_deletion_error(self): """try to delete a user that is still referenced in a "change" """ user = User(name='test', username='******', email='*****@*****.**', forum_username='******', moderator=True, password='******', email_validated=True, profile=UserProfile(categories=['amateur'])) self.session.add(user) self.session.flush() user_ids = [user.id] change = DocumentChange(user=self.user1, change_type='created', document=self.waypoint, document_type=WAYPOINT_TYPE, area_ids=[], user_ids=user_ids) self.session.add(change) self.session.flush() try: self.session.delete(user) self.session.flush() except Exception as exc: self.assertTrue('still references user id' in exc.orig.pgerror) else: self.fail('user is still referenced in change')
def migrate(self): super(MigrateUserProfiles, self).migrate() # some users to do not have a profile, create an empty profile so that # the users can be imported. with transaction.manager: last_locale_id = self.connection_source.execute( text('select max(document_i18n_archive_id) ' 'from app_documents_i18n_archives;')).fetchone()[0] last_archive_id = self.connection_source.execute( text('select max(document_archive_id) ' 'from app_documents_archives;')).fetchone()[0] profileless_users = self.connection_source.execute( text(MigrateUserProfiles.query_profileless_users)) for row in profileless_users: user_id = row[0] last_locale_id += 1 last_archive_id += 1 locale = DocumentLocale(id=last_locale_id, document_id=user_id, lang='fr', title='') profile = UserProfile(document_id=user_id, locales=[locale]) locale_archive = locale.to_archive() locale_archive.id = last_locale_id profile_archive = profile.to_archive() profile_archive.id = last_archive_id self.session_target.add(profile) self.session_target.add(locale) self.session_target.flush() self.session_target.add(locale_archive) self.session_target.add(profile_archive)
def _add_test_data(self): user_id = self.global_userids['contributor'] self.profile1 = self.session.query(UserProfile).get(user_id) self.locale_en = self.profile1.get_locale('en') self.locale_fr = self.profile1.get_locale('fr') DocumentRest.create_new_version(self.profile1, user_id) self.profile2 = UserProfile(categories=['amateur']) self.session.add(self.profile2) self.profile3 = UserProfile(categories=['amateur']) self.session.add(self.profile3) self.profile4 = UserProfile(categories=['amateur']) self.profile4.locales.append( DocumentLocale(lang='en', description='You', title='')) self.profile4.locales.append( DocumentLocale(lang='fr', description='Toi', title='')) self.session.add(self.profile4) self.session.flush() # create users for the profiles self.user2 = User(name='user2', username='******', email='*****@*****.**', forum_username='******', password='******', email_validated=True, profile=self.profile2) self.user3 = User(name='user3', username='******', email='*****@*****.**', forum_username='******', password='******', email_validated=False, profile=self.profile3) self.user4 = User(name='user4', username='******', email='*****@*****.**', forum_username='******', password='******', email_validated=True, profile=self.profile4) self.session.add_all([self.user2, self.user3, self.user4]) self.session.flush()
def test_check_changes_on_user_deletion_ok(self): """try to delete a user that is not referenced in a "change" """ user = User(name='test', username='******', email='*****@*****.**', forum_username='******', moderator=True, password='******', email_validated=True, profile=UserProfile(categories=['amateur'])) self.session.add(user) self.session.flush() self.session.delete(user) self.session.flush()
def test_update_cache_version_user(self): """ Test that outings are invalidated if an user name changes. """ outing = Outing(activities=['skitouring'], date_start=datetime.date(2016, 2, 1), date_end=datetime.date(2016, 2, 1)) user_profile = UserProfile() self.session.add_all([outing, user_profile]) self.session.flush() self.session.add(Association.create(user_profile, outing)) self.session.flush() update_cache_version(user_profile) cache_version_user_profile = self.session.query(CacheVersion).get( user_profile.document_id) cache_version_outing = self.session.query(CacheVersion).get( outing.document_id) self.assertEqual(cache_version_outing.version, 2) self.assertEqual(cache_version_user_profile.version, 2)
def _add_global_test_data(session): global_passwords['contributor'] = 'super pass' global_passwords['contributor2'] = 'better pass' global_passwords['moderator'] = 'even better pass' global_passwords['robot'] = 'bombproof pass' contributor_profile = UserProfile( categories=['amateur'], locales=[ DocumentLocale(title='', description='Me', lang='en'), DocumentLocale(title='', description='Moi', lang='fr')], geometry=DocumentGeometry(geom='SRID=3857;POINT(635956 5723604)')) contributor = User( name='Contributor', username='******', email='*****@*****.**', forum_username='******', password='******', email_validated=True, profile=contributor_profile) contributor2_profile = UserProfile( categories=['amateur'], locales=[DocumentLocale(title='...', lang='en')]) contributor2 = User( name='Contributor 2', username='******', email='*****@*****.**', forum_username='******', password='******', email_validated=True, profile=contributor2_profile) contributor3_profile = UserProfile( categories=['amateur'], locales=[DocumentLocale(title='...', lang='en')]) contributor3 = User( name='Contributor 3', username='******', email='*****@*****.**', forum_username='******', password='******', email_validated=True, profile=contributor3_profile) moderator_profile = UserProfile( categories=['mountain_guide'], locales=[DocumentLocale(title='', lang='en')]) moderator = User( name='Moderator', username='******', email='*****@*****.**', forum_username='******', moderator=True, password='******', email_validated=True, profile=moderator_profile) robot_profile = UserProfile( locales=[DocumentLocale(title='', lang='en')]) robot = User( name='Robot', username='******', email='*****@*****.**', forum_username='******', robot=True, password='******', email_validated=True, profile=robot_profile) users = [robot, moderator, contributor, contributor2, contributor3] session.add_all(users) session.flush() domain = 'www.somewhere.com' sso_key = SsoKey( domain=domain, key=domain ) session.add(sso_key) sso_external_id = SsoExternalId( domain=domain, external_id='1', user=contributor, token='token', expire=utc.localize(datetime.datetime.utcnow()), ) session.add(sso_external_id) session.flush() key = settings['jwtauth.master_secret'] algorithm = 'HS256' now = datetime.datetime.utcnow() exp = now + datetime.timedelta(weeks=10) for user in [robot, moderator, contributor, contributor2, contributor3]: claims = create_claims(user, exp) token = jwt.encode(claims, key=key, algorithm=algorithm). \ decode('utf-8') add_or_retrieve_token(token, exp, user.id) global_userids[user.username] = user.id global_tokens[user.username] = token
def main(argv=sys.argv): settings_file = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'loadtests.ini') settings = get_appsettings(settings_file) engine = engine_from_config(settings, 'sqlalchemy.') logging.basicConfig() logging.getLogger('sqlalchemy.engine').setLevel(logging.WARN) Session = sessionmaker() # noqa register(Session) session = Session(bind=engine) with transaction.manager: for i in range(1, NB_USERS_TO_CREATE + 1): username = BASE_USERNAME + str(i) password = username email = username + '@foo.bar' lang = 'fr' profile = UserProfile( categories=['amateur'], geometry=DocumentGeometry( version=1, geom=None, geom_detail=None), locales=[DocumentLocale(lang=lang, title='')] ) user = User( username=username, forum_username=username, name=username, email=email, lang=lang, password=password, profile=profile ) # make sure user account is directly validated user.clear_validation_nonce() user.email_validated = True session.add(user) session.flush() # also create a version for the profile # code from DocumentRest.create_new_version archive = user.profile.to_archive() archive_locales = user.profile.get_archive_locales() archive_geometry = user.profile.get_archive_geometry() meta_data = HistoryMetaData(comment='creation', user_id=user.id) versions = [] for locale in archive_locales: version = DocumentVersion( document_id=user.profile.document_id, lang=locale.lang, document_archive=archive, document_locales_archive=locale, document_geometry_archive=archive_geometry, history_metadata=meta_data ) versions.append(version) session.add(archive) session.add_all(archive_locales) session.add(meta_data) session.add_all(versions) session.flush() print('Created %d users with base username `%s`' % ( NB_USERS_TO_CREATE, BASE_USERNAME))
def setUp(self): super(TestChangesDocumentRest, self).setUp() self._prefix = '/documents/changes' contributor_id = self.global_userids['contributor'] self.waypoint1 = Waypoint( waypoint_type='summit', elevation=2000, geometry=DocumentGeometry(geom='SRID=3857;POINT(635956 5723604)'), locales=[ WaypointLocale(lang='fr', title='Dent de Crolles', description='...', summary='La Dent de Crolles') ]) self.session.add(self.waypoint1) self.session.flush() DocumentRest.create_new_version(self.waypoint1, contributor_id) self.session.flush() self.waypoint2 = Waypoint( waypoint_type='summit', elevation=4985, geometry=DocumentGeometry(geom='SRID=3857;POINT(635956 5723604)'), locales=[ WaypointLocale(lang='en', title='Mont Blanc', description='...', summary='The heighest point in Europe') ]) self.session.add(self.waypoint2) self.session.flush() DocumentRest.create_new_version(self.waypoint2, contributor_id) self.session.flush() self.waypoint3 = Waypoint( waypoint_type='summit', elevation=4985, redirects_to=self.waypoint1.document_id, geometry=DocumentGeometry(geom='SRID=3857;POINT(635956 5723604)'), locales=[ WaypointLocale(lang='en', title='Mont Blanc', description='...', summary='The heighest point in Europe') ]) self.session.add(self.waypoint3) self.session.flush() DocumentRest.create_new_version(self.waypoint3, contributor_id) self.session.flush() self.route1 = Route(activities=['skitouring'], elevation_max=1500, elevation_min=700, main_waypoint_id=self.waypoint1.document_id, locales=[ RouteLocale(lang='fr', title='Mont Blanc du ciel', description='...', summary='Ski') ]) self.session.add(self.route1) self.session.flush() DocumentRest.create_new_version(self.route1, contributor_id) self.session.flush() self.outing = Outing(activities=['skitouring'], date_start=datetime.date(2016, 1, 1), date_end=datetime.date(2016, 1, 1), elevation_max=1500, elevation_min=700, height_diff_up=800, height_diff_down=800) self.session.add(self.outing) self.session.flush() DocumentRest.create_new_version(self.outing, contributor_id) self.session.flush() self.profile2 = UserProfile(categories=['amateur']) self.session.add(self.profile2) self.session.flush() version_count = self.session.query(DocumentVersion).count() self.assertEqual(4, version_count) hist_meta_count = self.session.query(HistoryMetaData).count() self.assertEqual(5, hist_meta_count)
def post(self): """ Synchronize user details and return authentication url. Important: Email addresses need to be validated by external site. """ request = self.request sso_key = request.validated['sso_key'] sso_external_id = request.validated['sso_external_id'] user = request.validated['sso_user'] if user is None: # create new user user = User( username=request.validated['username'], name=request.validated['name'], forum_username=request.validated['forum_username'], email=request.validated['email'], email_validated=True, # MUST be validated by external site lang=request.validated['lang'], password=generate_token() # random password ) # directly create the user profile, the document id of the profile # is the user id lang = user.lang user.profile = UserProfile( categories=['amateur'], locales=[DocumentLocale(lang=lang, title='')], ) DBSession.add(user) DBSession.flush() if sso_external_id is None: sso_external_id = SsoExternalId( domain=sso_key.domain, external_id=request.validated['external_id'], user=user, ) DBSession.add(sso_external_id) sso_external_id.token = generate_token() sso_external_id.expire = sso_expire_from_now() client = get_discourse_client(request.registry.settings) discourse_userid = call_discourse(get_discourse_userid, client, user.id) if discourse_userid is None: call_discourse(client.sync_sso, user) discourse_userid = client.get_userid(user.id) # From cache # Groups are added to discourse, not removed group_ids = [] discourse_groups = None groups = request.validated['groups'] or '' for group_name in groups.split(','): if group_name == '': continue group_id = None if discourse_groups is None: discourse_groups = call_discourse(client.client.groups) group_id = None for discourse_group in discourse_groups: if discourse_group['name'] == group_name: group_id = discourse_group['id'] if group_id is None: # If group is not found, we ignore it as we want to return # a valid token for user authentication pass else: group_ids.append(group_id) for group_id in group_ids: call_discourse(client.client.add_user_to_group, group_id, discourse_userid) return { 'url': '{}/sso-login?no_redirect&{}'.format( request.registry.settings['ui.url'], urlencode({'token': sso_external_id.token})) }