def push(self, request, fsmName, stateData=None, startArgs=None, activity=None, **kwargs): """ Start running a new FSM instance (layer). """ stateData = stateData or {} startArgs = startArgs or {} fsm = FSM.objects.select_related('startNode').get(name=fsmName) activity = None if not activity and self.state and fsmName not in self.CHAT_NAMES: activity = self.state.activity self.state = FSMState(user=request.user, fsmNode=fsm.startNode, parentState=self.state, activity=activity, title=fsm.title, hideTabs=fsm.hideTabs, hideLinks=fsm.hideLinks, hideNav=fsm.hideNav, **kwargs) path = self.state.start_fsm(self, request, stateData, **startArgs) if fsmName not in self.CHAT_NAMES: request.session['fsmID'] = self.state.pk return path
def push(self, request, fsmName, stateData=None, startArgs=None, activity=None, **kwargs): """ Start running a new FSM instance (layer). """ stateData = stateData or {} startArgs = startArgs or {} fsm = FSM.objects.select_related('startNode').get(name=fsmName) activity = None if not activity and self.state and fsmName not in self.CHAT_NAMES: activity = self.state.activity self.state = FSMState( user=request.user, fsmNode=fsm.startNode, parentState=self.state, activity=activity, title=fsm.title, hideTabs=fsm.hideTabs, hideLinks=fsm.hideLinks, hideNav=fsm.hideNav, **kwargs ) path = self.state.start_fsm(self, request, stateData, **startArgs) if fsmName not in self.CHAT_NAMES: request.session['fsmID'] = self.state.pk return path
def test_trivial_plugin(self): """ Check trivial plugin import and call. """ f = FSM.save_graph(self.fsmDict, self.nodeDict, self.edgeDict, 'jacob') request = FakeRequest(self.user) fsmStack = FSMStack(request) fsmStack.state = FSMState(user=self.user, fsmNode=f.startNode) self.assertEqual(f.startNode.event(fsmStack, request, 'start'), '/ct/about/') self.assertEqual(f.startNode.get_path(fsmStack.state, request), '/ct/some/where/else/')
class FSMStack(object): """ Main interface to our current FSM if any. """ CHAT_NAMES = ('chat', 'additional', 'courselet_preview') def __init__(self, request, **kwargs): try: fsmID = request.session['fsmID'] except KeyError: self.state = None return try: self.state = FSMState.objects.select_related('fsmNode')\ .prefetch_related('fsmNode__outgoing').get(pk=fsmID) except FSMState.DoesNotExist: del request.session['fsmID'] self.state = None return for edge in self.state.fsmNode.outgoing.all(): # detect selection edges if edge.name.startswith('select_'): setattr(self, edge.name, edge) # make available to HTML templates def event(self, request, eventName='next', pageData=None, **kwargs): """Top-level interface for passing event to a running FSM instance If FSM handles this event, return a redirect that over-rides the generic UI behavior. Otherwise return None, indicating NO over-ride of generic UI behavior. """ if self.state is None: # no ongoing activity return state = self.state # remember current state path = self.state.event( self, request, eventName, pageData=pageData, **kwargs ) if self.state and self.state != state: # pushed or popped path = self.state.path # use path of new FSM if self.state.fsmNode.node_name_is_one_of('END'): # reached terminal state pageData.set_refresh_timer(request, False) # reset timer if on if self.state.fsmNode.help: # save its help message request.session['statusMessage'] = self.state.fsmNode.help parentPath = self.pop(request, pageData=pageData) if parentPath: # let parent FSM redirect us to its current state return parentPath return path def push(self, request, fsmName, stateData=None, startArgs=None, activity=None, **kwargs): """ Start running a new FSM instance (layer). """ stateData = stateData or {} startArgs = startArgs or {} fsm = FSM.objects.select_related('startNode').get(name=fsmName) activity = None if not activity and self.state and fsmName not in self.CHAT_NAMES: activity = self.state.activity self.state = FSMState( user=request.user, fsmNode=fsm.startNode, parentState=self.state, activity=activity, title=fsm.title, hideTabs=fsm.hideTabs, hideLinks=fsm.hideLinks, hideNav=fsm.hideNav, **kwargs ) path = self.state.start_fsm(self, request, stateData, **startArgs) if fsmName not in self.CHAT_NAMES: request.session['fsmID'] = self.state.pk return path def pop(self, request, eventName='return', pageData=None, **kwargs): """ Pop current FSM state and pass event to next stack state if any. """ nextState = self.state.parentState if '.live.' in self.state.fsmNode.funcName: for child in self.state.linkChildren.all(): child.linkState = None child.save() self.state.delete() self.state = nextState if nextState is not None: request.session['fsmID'] = nextState.pk return self.event(request, eventName, pageData, **kwargs) else: del request.session['fsmID'] def resume(self, request, stateID): """ Resume an orphaned activity. """ state = FSMState.objects.get(pk=int(stateID)) if state.user_id != request.user.id: raise FSMBadUserError('user mismatch!!') elif state.children.count() > 0: raise FSMStackResumeError('can only resume innermost stack level') self.state = state request.session['fsmID'] = self.state.pk return self.get_current_url() def get_current_url(self): """ Get URL for resuming at current FSM state. """ if self.state: return self.state.path
def get(self, request, course_id): """Show list of courselets in a course with proper context""" course = get_object_or_404(Course, pk=course_id) liveSession = FSMState.find_live_sessions(request.user).filter( activity__course=course ).first() if liveSession: liveSession.live_instructor_name = ( liveSession.user.get_full_name() or liveSession.user.username ) try: liveSession.live_instructor_icon = ( liveSession.user.instructor.icon_url or static('img/student/avatar-teacher.jpg') ) except AttributeError: liveSession.live_instructor_icon = static('img/student/avatar-teacher.jpg') courselets = self.get_courselets(request, course) live_sessions_history = Chat.objects.filter( user=request.user, is_live=True, enroll_code__courseUnit__course=course, # state__isnull=True ) # .annotate( # lessons_done=models.Sum( # models.Case( # models.When( # message__contenttype='unitlesson', # message__kind='orct', # message__type='message', # message__owner=request.user, # then=1 # ), # default=0, # output_field=models.IntegerField() # ) # ) # ) # live_sessions_history.filter(lessons_done=0).delete() # TODO: once django updated to version >=1.8 change next lines to # TODO: .annotate(lessons_count=models.Case()). # TODO: http://stackoverflow.com/questions/30752268/how-to-filter-objects-for-count-annotation-in-django # for chat in live_sessions_history: chat_prog_ser = ChatProgressSerializer() lessons = chat_prog_ser.get_breakpoints(chat) chat.lessons_done = len([i for i in lessons if i['isDone']]) chat.total_lessons = len(lessons) if not chat.lessons_done: chat.delete() return render( request, self.template_name, dict( course=course, liveSession=liveSession, courslets=courselets, livesessions=live_sessions_history, ) )
class FSMStack(object): """ Main interface to our current FSM if any. """ CHAT_NAMES = ('chat', 'additional', 'courselet_preview', 'faq') def __init__(self, request, **kwargs): try: fsmID = request.session['fsmID'] except KeyError: self.state = None return try: self.state = FSMState.objects.select_related('fsmNode')\ .prefetch_related('fsmNode__outgoing').get(pk=fsmID) except FSMState.DoesNotExist: del request.session['fsmID'] self.state = None return for edge in self.state.fsmNode.outgoing.all( ): # detect selection edges if edge.name.startswith('select_'): setattr(self, edge.name, edge) # make available to HTML templates def event(self, request, eventName='next', pageData=None, **kwargs): """Top-level interface for passing event to a running FSM instance If FSM handles this event, return a redirect that over-rides the generic UI behavior. Otherwise return None, indicating NO over-ride of generic UI behavior. """ if self.state is None: # no ongoing activity return state = self.state # remember current state path = self.state.event(self, request, eventName, pageData=pageData, **kwargs) if self.state and self.state != state: # pushed or popped path = self.state.path # use path of new FSM if self.state.fsmNode.node_name_is_one_of( 'END'): # reached terminal state pageData.set_refresh_timer(request, False) # reset timer if on if self.state.fsmNode.help: # save its help message request.session['statusMessage'] = self.state.fsmNode.help parentPath = self.pop(request, pageData=pageData) if parentPath: # let parent FSM redirect us to its current state return parentPath return path def push(self, request, fsmName, stateData=None, startArgs=None, activity=None, **kwargs): """ Start running a new FSM instance (layer). """ stateData = stateData or {} startArgs = startArgs or {} fsm = FSM.objects.select_related('startNode').get(name=fsmName) activity = None if not activity and self.state and fsmName not in self.CHAT_NAMES: activity = self.state.activity self.state = FSMState(user=request.user, fsmNode=fsm.startNode, parentState=self.state, activity=activity, title=fsm.title, hideTabs=fsm.hideTabs, hideLinks=fsm.hideLinks, hideNav=fsm.hideNav, **kwargs) path = self.state.start_fsm(self, request, stateData, **startArgs) if fsmName not in self.CHAT_NAMES: request.session['fsmID'] = self.state.pk return path def pop(self, request, eventName='return', pageData=None, **kwargs): """ Pop current FSM state and pass event to next stack state if any. """ nextState = self.state.parentState if '.live.' in self.state.fsmNode.funcName: for child in self.state.linkChildren.all(): child.linkState = None child.save() self.state.delete() self.state = nextState if nextState is not None: request.session['fsmID'] = nextState.pk return self.event(request, eventName, pageData, **kwargs) else: del request.session['fsmID'] def resume(self, request, stateID): """ Resume an orphaned activity. """ state = FSMState.objects.get(pk=int(stateID)) if state.user_id != request.user.id: raise FSMBadUserError('user mismatch!!') elif state.children.count() > 0: raise FSMStackResumeError('can only resume innermost stack level') self.state = state request.session['fsmID'] = self.state.pk return self.get_current_url() def get_current_url(self): """ Get URL for resuming at current FSM state. """ if self.state: return self.state.path