def test_store_complex_object(self): request = HttpRequest() request.session = {} store = RedisSessionStore(request, "test-store") store.regenerate({"some_value": {"deep_object": "value"}}) store2 = RedisSessionStore(request, "test-store") assert store2.some_value["deep_object"] == "value" store.clear()
def test_uninitialized_store(self): request = HttpRequest() request.session = {} store = RedisSessionStore(request, 'test-store') assert not store.is_valid() assert store.get_state() is None assert store.some_key is None store.setting_but_no_state = 'anything' assert store.setting_but_no_state is None store.clear()
def test_store_complex_object(self): request = HttpRequest() request.session = {} store = RedisSessionStore(request, 'test-store') store.regenerate({ 'some_value': {'deep_object': 'value'}, }) store2 = RedisSessionStore(request, 'test-store') assert store2.some_value['deep_object'] == 'value' store.clear()
def test_store_values(self): request = HttpRequest() request.session = {} store = RedisSessionStore(request, 'test-store') store.regenerate() assert 'store:test-store' in request.session store.some_value = 'test_value' store2 = RedisSessionStore(request, 'test-store') assert store2.is_valid() assert store2.some_value == 'test_value' with self.assertRaises(AttributeError): store.missing_key store.clear()
class Pipeline(object): """ Pipeline provides a mechanism to guide the user through a request 'pipeline', where each view may be completed by calling the ``next_step`` pipeline method to traverse through the pipe. The pipeline works with a PipelineProvider object which provides the pipeline views and is made available to the views through the passed in pipeline. :provider_manager: A class property that must be specified to allow for lookup of a provider implementation object given it's key. :provider_model_cls: The Provider model object represents the instance of an object implementing the PipelineProvider interface. This is used to look up the instance when constructing an in progress pipleine (get_for_request). :config: A object that specifies additional pipeline and provider runtime configurations. An example of usage is for OAuth Identity providers, for overriding the scopes. The config object will be passed into the provider using the ``set_config`` method. """ pipeline_name = None provider_manager = None provider_model_cls = None @classmethod def get_for_request(cls, request): state = RedisSessionStore(request, cls.pipeline_name) if not state.is_valid(): return None provider_model = None if state.provider_model_id: provider_model = cls.provider_model_cls.objects.get( id=state.provider_model_id) organization = None if state.org_id: organization = Organization.objects.get(id=state.org_id) provider_key = state.provider_key config = state.config return cls(request, organization=organization, provider_key=provider_key, provider_model=provider_model, config=config) def __init__(self, request, provider_key, organization=None, provider_model=None, config=None): if config is None: config = {} self.request = request self.organization = organization self.state = RedisSessionStore(request, self.pipeline_name) self.provider = self.provider_manager.get(provider_key) self.provider_model = provider_model self.config = config self.provider.set_pipeline(self) self.provider.set_config(config) self.pipeline_views = self.get_pipeline_views() # we serialize the pipeline to be ['fqn.PipelineView', ...] which # allows us to determine if the pipeline has changed during the auth # flow or if the user is somehow circumventing a chunk of it pipe_ids = [ u'{}.{}'.format(type(v).__module__, type(v).__name__) for v in self.pipeline_views ] self.signature = md5_text(*pipe_ids).hexdigest() def get_pipeline_views(self): """ Retrieve the pipeline views from the provider. You may wish to override this method to provide views that all providers should inherit, or customize the provider method called to retrieve the views. """ return self.provider.get_pipeline_views() def is_valid(self): return self.state.is_valid() and self.state.signature == self.signature def initialize(self): self.state.regenerate({ 'uid': self.request.user.id if self.request.user.is_authenticated() else None, 'provider_model_id': self.provider_model.id if self.provider_model else None, 'provider_key': self.provider.key, 'org_id': self.organization.id if self.organization else None, 'step_index': 0, 'signature': self.signature, 'config': self.config, 'data': {}, }) def clear_session(self): self.state.clear() def current_step(self): """ Render the current step. """ step_index = self.state.step_index if step_index == len(self.pipeline_views): return self.finish_pipeline() step = self.pipeline_views[step_index] # support late binding steps if isinstance(step, LambdaType): step = step() return step.dispatch( request=self.request, pipeline=self, ) def error(self, message): context = {'error': message} return render_to_response('sentry/pipeline-error.html', context, self.request) def next_step(self): """ Render the next step. """ self.state.step_index += 1 return self.current_step() def finish_pipeline(self): """ Called when the pipeline completes the final step. """ raise NotImplementedError def bind_state(self, key, value): data = self.state.data data[key] = value self.state.data = data def fetch_state(self, key=None): return self.state.data if key is None else self.state.data.get(key)
class Pipeline(object): """ Pipeline provides a mechanism to guide the user through a request 'pipeline', where each view may be completed by calling the ``next_step`` pipeline method to traverse through the pipe. The pipeline works with a PipelineProvider object which provides the pipeline views and is made available to the views through the passed in pipeline. :provider_manager: A class property that must be specified to allow for lookup of a provider implementation object given it's key. :provider_model_cls: The Provider model object represents the instance of an object implementing the PipelineProvider interface. This is used to look up the instance when constructing an in progress pipleine (get_for_request). :config: A object that specifies additional pipeline and provider runtime configurations. An example of usage is for OAuth Identity providers, for overriding the scopes. The config object will be passed into the provider using the ``set_config`` method. """ pipeline_name = None provider_manager = None provider_model_cls = None @classmethod def get_for_request(cls, request): state = RedisSessionStore(request, cls.pipeline_name) if not state.is_valid(): return None provider_model = None if state.provider_model_id: provider_model = cls.provider_model_cls.objects.get(id=state.provider_model_id) organization = None if state.org_id: organization = Organization.objects.get(id=state.org_id) provider_key = state.provider_key config = state.config return cls(request, organization=organization, provider_key=provider_key, provider_model=provider_model, config=config) def __init__(self, request, provider_key, organization=None, provider_model=None, config=None): if config is None: config = {} self.request = request self.organization = organization self.state = RedisSessionStore(request, self.pipeline_name) self.provider = self.provider_manager.get(provider_key) self.provider_model = provider_model self.config = config self.provider.set_pipeline(self) self.provider.set_config(config) self.pipeline_views = self.get_pipeline_views() # we serialize the pipeline to be ['fqn.PipelineView', ...] which # allows us to determine if the pipeline has changed during the auth # flow or if the user is somehow circumventing a chunk of it pipe_ids = [u'{}.{}'.format(type(v).__module__, type(v).__name__) for v in self.pipeline_views] self.signature = md5_text(*pipe_ids).hexdigest() def get_pipeline_views(self): """ Retrieve the pipeline views from the provider. You may wish to override this method to provide views that all providers should inherit, or customize the provider method called to retrieve the views. """ return self.provider.get_pipeline_views() def is_valid(self): return self.state.is_valid() and self.state.signature == self.signature def initialize(self): self.state.regenerate({ 'uid': self.request.user.id if self.request.user.is_authenticated() else None, 'provider_model_id': self.provider_model.id if self.provider_model else None, 'provider_key': self.provider.key, 'org_id': self.organization.id if self.organization else None, 'step_index': 0, 'signature': self.signature, 'config': self.config, 'data': {}, }) def clear_session(self): self.state.clear() def current_step(self): """ Render the current step. """ step_index = self.state.step_index if step_index == len(self.pipeline_views): return self.finish_pipeline() step = self.pipeline_views[step_index] # support late binding steps if isinstance(step, LambdaType): step = step() return step.dispatch( request=self.request, pipeline=self, ) def error(self, message): context = {'error': message} return render_to_response('sentry/pipeline-error.html', context, self.request) def next_step(self): """ Render the next step. """ self.state.step_index += 1 return self.current_step() def finish_pipeline(self): """ Called when the pipeline completes the final step. """ raise NotImplementedError def bind_state(self, key, value): data = self.state.data data[key] = value self.state.data = data def fetch_state(self, key=None): return self.state.data if key is None else self.state.data.get(key)