Exemple #1
0
    def post_config_override(self):
        """Handles 'override' property action."""
        name = self.request.get('name')

        # Find item in registry.
        item = None
        if name and name in config.Registry.registered.keys():
            item = config.Registry.registered[name]
        if not item:
            self.redirect('/admin?action=settings')

        # Add new entity if does not exist.
        try:
            entity = config.ConfigPropertyEntity.get_by_key_name(name)
        except db.BadKeyError:
            entity = None
        if not entity:
            entity = config.ConfigPropertyEntity(key_name=name)
            entity.value = str(item.value)
            entity.is_draft = True
            entity.put()

        models.EventEntity.record(
            'override-property', users.get_current_user(),
            transforms.dumps({
                'name': name,
                'value': str(entity.value)
            }))

        self.redirect('/admin?%s' % urllib.urlencode({
            'action': 'config_edit',
            'name': name
        }))
    def test_dont_lose_existing_icon(self):
        entity = config.ConfigPropertyEntity(
            key_name=settings.COURSE_EXPLORER_SETTINGS.name)
        entity.value = transforms.dumps({
            'title': 'The Title',
            'logo_alt_text': 'alt',
            'institution_name': u'🐱Institution',
            'institution_url': 'http://example.com',
            'logo_bytes_base64': 'logo-contents',
            'logo_mime_type': 'image/png',
        })
        entity.is_draft = False
        entity.put()

        self.post_settings({
            'title': 'Another Title',
            'logo': '',
            'logo_alt_text': 'alt',
            'institution_name': u'New 🐱Institution',
            'institution_url': 'http://example.com',
        })

        self.assertEqual(
            transforms.loads(settings.COURSE_EXPLORER_SETTINGS.value), {
            'title': 'Another Title',
            'logo_alt_text': 'alt',
            'institution_name': u'New 🐱Institution',
            'institution_url': 'http://example.com',
            'logo_bytes_base64': 'logo-contents',
            'logo_mime_type': 'image/png',
        })
Exemple #3
0
    def test_config_visible_from_any_namespace(self):
        """Test that ConfigProperty is visible from any namespace."""

        assert (
            config.UPDATE_INTERVAL_SEC.value ==
            config.UPDATE_INTERVAL_SEC.default_value)
        new_value = config.UPDATE_INTERVAL_SEC.default_value + 5

        # Add datastore override for known property.
        prop = config.ConfigPropertyEntity(
            key_name=config.UPDATE_INTERVAL_SEC.name)
        prop.value = str(new_value)
        prop.is_draft = False
        prop.put()

        # Check visible from default namespace.
        config.Registry.last_update_time = 0
        assert config.UPDATE_INTERVAL_SEC.value == new_value

        # Check visible from another namespace.
        old_namespace = namespace_manager.get_namespace()
        try:
            namespace_manager.set_namespace(
                'ns-test_config_visible_from_any_namespace')

            config.Registry.last_update_time = 0
            assert config.UPDATE_INTERVAL_SEC.value == new_value
        finally:
            namespace_manager.set_namespace(old_namespace)
Exemple #4
0
    def post(self):
        name = COURSE_EXPLORER_SETTINGS.name
        request = transforms.loads(self.request.get('request'))

        if not self.assert_xsrf_token_or_fail(request, self.ACTION, {}):
            return

        if not roles.Roles.is_course_admin(self.app_context):
            transforms.send_json_response(self, 401, 'Access denied.', {})
            return

        raw_data = transforms.loads(request.get('payload'))
        raw_data.pop('logo', None)
        try:
            data = transforms.json_to_dict(
                raw_data,
                schema_provider(None).get_json_schema_dict())
        except (TypeError, ValueError) as err:
            self.validation_error(err.replace('\n', ' '))
            return

        logo = self.request.POST.get('logo')
        logo_uploaded = isinstance(logo, cgi.FieldStorage)
        if logo_uploaded:
            data['logo_bytes_base64'] = base64.b64encode(logo.file.read())
            data['logo_mime_type'] = logo.type

        with common_utils.Namespace(appengine_config.DEFAULT_NAMESPACE_NAME):
            entity = config.ConfigPropertyEntity.get_by_key_name(name)

            if entity is None:
                entity = config.ConfigPropertyEntity(key_name=name)
                old_value = None
            else:
                old_value = entity.value

            # Don't delete the logo.
            if not logo_uploaded and old_value:
                old_dict = transforms.loads(old_value)
                if ('logo_bytes_base64' in old_dict
                        and 'logo_mime_type' in old_dict):
                    data['logo_bytes_base64'] = old_dict['logo_bytes_base64']
                    data['logo_mime_type'] = old_dict['logo_mime_type']

            entity.value = transforms.dumps(data)
            entity.is_draft = False
            entity.put()

            # is this necessary?
            models.EventEntity.record(
                'put-property', users.get_current_user(),
                transforms.dumps({
                    'name': name,
                    'before': str(old_value),
                    'after': str(entity.value)
                }))

        transforms.send_file_upload_response(self, 200, 'Saved.')
Exemple #5
0
def set_report_allowed(value):
    with common_utils.Namespace(appengine_config.DEFAULT_NAMESPACE_NAME):
        entity = config.ConfigPropertyEntity.get_by_key_name(
            REPORT_ALLOWED.name)
        if not entity:
            entity = config.ConfigPropertyEntity(key_name=REPORT_ALLOWED.name)
        entity.value = str(value)
        entity.is_draft = False
        entity.put()
Exemple #6
0
    def test_non_admin_has_no_access(self):
        """Test non admin has no access to pages or REST endpoints."""

        email = '*****@*****.**'
        actions.login(email)

        # Add datastore override.
        prop = config.ConfigPropertyEntity(
            key_name='gcb_config_update_interval_sec')
        prop.value = '5'
        prop.is_draft = False
        prop.put()

        # Check user has no access to specific pages and actions.
        response = self.testapp.get('/admin?action=settings')
        assert_equals(response.status_int, 302)

        response = self.testapp.get(
            '/admin?action=config_edit&name=gcb_admin_user_emails')
        assert_equals(response.status_int, 302)

        response = self.testapp.post(
            '/admin?action=config_reset&name=gcb_admin_user_emails')
        assert_equals(response.status_int, 302)

        # Check user has no rights to GET verb.
        response = self.testapp.get(
            '/rest/config/item?key=gcb_config_update_interval_sec')
        assert_equals(response.status_int, 200)
        json_dict = json.loads(response.body)
        assert json_dict['status'] == 401
        assert json_dict['message'] == 'Access denied.'

        # Check user has no rights to PUT verb.
        payload_dict = {}
        payload_dict['value'] = '666'
        payload_dict['is_draft'] = False
        request = {}
        request['key'] = 'gcb_config_update_interval_sec'
        request['payload'] = json.dumps(payload_dict)

        # Check XSRF token is required.
        response = self.testapp.put('/rest/config/item?%s' % urllib.urlencode(
            {'request': json.dumps(request)}), {})
        assert_equals(response.status_int, 200)
        assert_contains('"status": 403', response.body)

        # Check user still has no rights to PUT verb even if he somehow
        # obtained a valid XSRF token.
        request['xsrf_token'] = XsrfTokenManager.create_xsrf_token(
            'config-property-put')
        response = self.testapp.put('/rest/config/item?%s' % urllib.urlencode(
            {'request': json.dumps(request)}), {})
        assert_equals(response.status_int, 200)
        json_dict = json.loads(response.body)
        assert json_dict['status'] == 401
        assert json_dict['message'] == 'Access denied.'
Exemple #7
0
 def test_in_db_but_not_registered_while_registering_modules(self):
     try:
         appengine_config.MODULE_REGISTRATION_IN_PROGRESS = True
         config.ConfigPropertyEntity(key_name='foo', value='foo_value').put()
         # Trigger load from DB
         models.CAN_USE_MEMCACHE.value  # pylint: disable=pointless-statement
         self.assertLogContains(
             'INFO: Property is not registered (skipped): foo')
     finally:
         appengine_config.MODULE_REGISTRATION_IN_PROGRESS = False
 def set_service_enabled(self, is_enabled):
     with common_utils.Namespace(appengine_config.DEFAULT_NAMESPACE_NAME):
         name = 'gcb_gql_service_enabled'
         try:
             entity = config.ConfigPropertyEntity.get_by_key_name(name)
         except db.BadKeyError:
             entity = None
         if not entity:
             entity = config.ConfigPropertyEntity(key_name=name)
         entity.value = str(is_enabled)
         entity.is_draft = False
         entity.put()
    def test_settings_values(self):
        entity = config.ConfigPropertyEntity(
            key_name=settings.COURSE_EXPLORER_SETTINGS.name)
        entity.value = transforms.dumps({
            'title': 'The Title',
            'logo_alt_text': 'alt',
            'institution_name': u'🐱Institution',
            'institution_url': 'http://example.com',
            'logo_bytes_base64': 'logo-contents',
            'logo_mime_type': 'image/png',
        })
        entity.is_draft = False
        entity.put()

        self.assertEqual(
            self.get_response("""
            {
                site {
                    title,
                    logo {
                        url,
                        altText
                    },
                    courseExplorer {
                        extraContent
                    }
                }
            }
            """),
            {
                'errors': [],
                'data': {
                    'site': {
                        'title': 'The Title',
                        'logo': {
                            'url': 'data:image/png;base64,logo-contents',
                            'altText': 'alt',
                        },
                        'courseExplorer': {
                            'extraContent': None,
                        }
                    }
                }
            }
        )
Exemple #10
0
    def _get_random_installation_id(cls):
        """If not yet chosen, pick a random identifier for the installation."""

        cfg = _INSTALLATION_IDENTIFIER
        if not cfg.value or cfg.value == cfg.default_value:
            with common_utils.Namespace(
                appengine_config.DEFAULT_NAMESPACE_NAME):

                entity = config.ConfigPropertyEntity.get_by_key_name(cfg.name)
                if not entity:
                    entity = config.ConfigPropertyEntity(key_name=cfg.name)
                ret = str(uuid.uuid4())
                entity.value = ret
                entity.is_draft = False
                entity.put()
        else:
            ret = cfg.value
        return ret
Exemple #11
0
    def test_admin_list(self):
        """Test delegation of admin access to another user."""

        email = '*****@*****.**'
        actions.login(email)

        # Add environment variable override.
        os.environ['gcb_admin_user_emails'] = '[%s]' % email

        # Add datastore override.
        prop = config.ConfigPropertyEntity(
            key_name='gcb_config_update_interval_sec')
        prop.value = '5'
        prop.is_draft = False
        prop.put()

        # Check user has access now.
        response = self.testapp.get('/admin?action=settings')
        assert_equals(response.status_int, 200)

        # Check overrides are active and have proper management actions.
        assert_contains('gcb_admin_user_emails', response.body)
        assert_contains('[[email protected]]', response.body)
        assert_contains(
            '/admin?action=config_override&name=gcb_admin_user_emails',
            response.body)
        assert_contains(
            '/admin?action=config_edit&name=gcb_config_update_interval_sec',
            response.body)

        # Check editor page has proper actions.
        response = self.testapp.get(
            '/admin?action=config_edit&name=gcb_config_update_interval_sec')
        assert_equals(response.status_int, 200)
        assert_contains('/admin?action=config_reset', response.body)
        assert_contains('name=gcb_config_update_interval_sec', response.body)

        # Remove override.
        del os.environ['gcb_admin_user_emails']

        # Check user has no access.
        response = self.testapp.get('/admin?action=settings')
        assert_equals(response.status_int, 302)
Exemple #12
0
    def _init_secret_if_none(cls, cfg, length):

        # Any non-default value is fine.
        if cfg.value and cfg.value != cfg.default_value:
            return

        # All property manipulations must run in the default namespace.
        with utils.Namespace(appengine_config.DEFAULT_NAMESPACE_NAME):

            # Look in the datastore directly.
            entity = config.ConfigPropertyEntity.get_by_key_name(cfg.name)
            if not entity:
                entity = config.ConfigPropertyEntity(key_name=cfg.name)

            # Any non-default non-None value is fine.
            if (entity.value and not entity.is_draft and
                (str(entity.value) != str(cfg.default_value))):
                return

            # Initialize to random value.
            entity.value = base64.urlsafe_b64encode(
                os.urandom(int(length * 0.75)))
            entity.is_draft = False
            entity.put()
Exemple #13
0
 def test_in_db_but_not_registered_not_registering_modules(self):
     config.ConfigPropertyEntity(key_name='foo', value='foo_value').put()
     # Trigger load from DB
     models.CAN_USE_MEMCACHE.value  # pylint: disable=pointless-statement
     self.assertLogContains(
         'WARNING: Property is not registered (skipped): foo')
    def put(self):
        """Handles REST PUT verb with JSON payload."""
        request = transforms.loads(self.request.get('request'))
        key = request.get('key')

        if not self.assert_xsrf_token_or_fail(request, 'config-property-put',
                                              {'key': key}):
            return

        if not ConfigPropertyRights.can_edit():
            transforms.send_json_response(self, 401, 'Access denied.',
                                          {'key': key})
            return

        item = None
        if key and key in config.Registry.registered.keys():
            item = config.Registry.registered[key]
        if not item:
            self.redirect('/admin?action=settings')

        try:
            entity = config.ConfigPropertyEntity.get_by_key_name(key)
        except db.BadKeyError:
            transforms.send_json_response(self, 404, 'Object not found.',
                                          {'key': key})
            return
        if not entity:
            entity = config.ConfigPropertyEntity(key_name=key)
            old_value = None
        else:
            old_value = entity.value

        payload = request.get('payload')
        json_object = transforms.loads(payload)
        new_value = item.value_type(json_object['value'])

        # Validate the value.
        errors = []
        if item.validator:
            item.validator(new_value, errors)
        if errors:
            transforms.send_json_response(self, 412, '\n'.join(errors))
            return

        # Update entity.

        entity.value = str(new_value)
        entity.is_draft = False
        entity.put()
        if item.after_change:
            item.after_change(item, old_value)

        models.EventEntity.record(
            'put-property', users.get_current_user(),
            transforms.dumps({
                'name': key,
                'before': str(old_value),
                'after': str(entity.value)
            }))

        transforms.send_json_response(self, 200, 'Saved.')