Beispiel #1
0
 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
Beispiel #2
0
 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
Beispiel #3
0
 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/')
Beispiel #4
0
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
Beispiel #5
0
    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,
            )
        )
Beispiel #6
0
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