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)
Example #2
0
    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)
Example #3
0
    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)
Example #4
0
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
Example #5
0
    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()
Example #6
0
    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)
Example #7
0
    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)
Example #8
0
    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)
Example #9
0
    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 _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()
Example #11
0
    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)
Example #12
0
 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()
Example #13
0
    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)
Example #14
0
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
Example #15
0
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))
Example #16
0
    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)
Example #17
0
    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}))
        }