# Kod źródłowy modułu tasks.views

    from urllib.parse import urlparse, parse_qs

    from articles.models import StaticVideo
    from django.db.models.aggregates import Sum
    from django.db.models.expressions import Case, When
    from django.db.models.fields import IntegerField
    from django.db.models.query import Prefetch
    from django.db.models.query_utils import Q
    from django.http.response import HttpResponseRedirect
    from django.shortcuts import redirect
    from django.urls.base import reverse_lazy
    from django.views.generic.base import TemplateView, ContextMixin
    from django.views.generic.detail import DetailView
    from django.views.generic.edit import FormView
    from exercises.models import Exercise
    from exercises.views import NotificationContent
    from tasks.constants import IntroPopupType, IntroPopupData, NotificationType
    from tasks.forms import ApprenticeTaskAnswerForm
    from tasks.models import Path, Task, ApprenticeTaskAnswer, ExerciseTaskPosition
    from users.decorators import apprentice_login_required
    from utils.general import progress_percent

    class IntroPopupContextMixin(ContextMixin):
        intro_popup_type = None

        def get_context_data(self, **kwargs):
            context = super(IntroPopupContextMixin, self).get_context_data(**kwargs)
            if self.intro_popup_type is not None and self.intro_popup_type not in self.request.user.intro_videos:
                if self.request.user.intro_videos:
                    self.request.user.intro_videos.append(self.intro_popup_type)
                else:
                    self.request.user.intro_videos = [self.intro_popup_type]
                self.request.user.save()

                static_video = StaticVideo.objects.filter(system_id=self.intro_popup_type).last()
                if static_video:
                    url_data = urlparse(static_video.yt_video)
                    query = parse_qs(url_data.query)
                    video_id = query["v"][0]
                    text = static_video.text
                else:
                    popup_data = IntroPopupData.POPUP_DATA.get(self.intro_popup_type)
                    video_id = popup_data.get('video_id')
                    text = popup_data.get('text')

                if video_id:
                    context['intro_popup_video_id'] = video_id
                    context['intro_popup_text'] = text
            return context

    class ActivePathsContextMixin(ContextMixin):
        """Mixin uzupełniający context o dostępne ścieżki"""

        def get_context_data(self, **kwargs):
            context = super(ActivePathsContextMixin, self).get_context_data(**kwargs)
            context['active_paths'] = Path.objects.active()
            return context

    @apprentice_login_required
    class PathListView(TemplateView, ActivePathsContextMixin, IntroPopupContextMixin):
        """Widok reprezentujący moduł Ucz się. Umożliwiającą przejście do wybranej ścieżki"""
        template_name = 'tasks/path_list.html'
        intro_popup_type = IntroPopupType.PATHS

        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context['active_paths'] = context['active_paths'].annotate(
                completed=Sum(Case(When(tasks__answers__apprentice=self.request.user, then=1), default=0),
                              output_field=IntegerField()))
            return context

    @apprentice_login_required
    class PathDetailView(DetailView, ActivePathsContextMixin):
        """Widok reprezentujący wybraną ścieżkę"""
        template_name = 'tasks/path.html'
        pk_url_kwarg = 'path_id'
        context_object_name = 'selected_path'

        def get_queryset(self):
            return Path.objects.active()

        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            apprentice = self.request.user
            tasks = self.object.tasks.active(). \
                prefetch_related(Prefetch('exercise_task_positions',
                                          queryset=ExerciseTaskPosition.objects.active().annotate(done=Sum(
                                              Case(When(exercise__apprentices=apprentice, then=1), default=0,
                                                   output_field=IntegerField()))),
                                          to_attr='exercise_task_positions_by_apprentice')).annotate(done_count=Sum(
                Case(When(exercise_task_positions__exercise__apprentices=apprentice, then=1), default=0,
                     output_field=IntegerField()))).prefetch_related(
                Prefetch('answers', queryset=ApprenticeTaskAnswer.objects.filter(apprentice=apprentice)))

            context['tasks'] = tasks
            context['all_exercises_count'] = Exercise.objects.from_path_count(self.object)
            context['done_exercises_count'] = Exercise.objects.from_path(self.object). \
                annotated_with_done_by_apprentice_count(self.request.user)
            available_tasks = self.object.tasks.active().count()
            context['available_tasks'] = available_tasks
            completed_tasks = ApprenticeTaskAnswer.objects.from_path(self.object).by_apprentice(
                self.request.user).completed().count()
            context['completed_tasks'] = completed_tasks
            context['path_progress'] = progress_percent(completed_tasks, available_tasks)
            return context

    @apprentice_login_required
    class TaskAnswerListView(TemplateView, IntroPopupContextMixin, ActivePathsContextMixin):
        """Widok reprezentujący listę odpowiedzi na zadania (moje filmy oraz oceniaj)"""
        template_name = 'tasks/task_answer_list.html'
        intro_popup_type = IntroPopupType.VIDEO_LIST
        elements_quant = 9

        def process_with_query_attributes(self, queryset):
            attributes = self.request.GET
            query_context = {}
            query = attributes.get('query')
            if query:
                queryset = queryset.filter(
                    Q(custom_title__icontains=query) | Q(task__title__icontains=query) | Q(task__subtitle__icontains=query))
                query_context['query'] = query
            try:
                selected_path = int(attributes.get('selected_path'))
                if selected_path:
                    queryset = queryset.filter(task__path_id=selected_path)
                    query_context['selected_path'] = selected_path
            except (ValueError, TypeError):
                pass
            sort = attributes.get('sort')
            if sort:
                sort_type = 'created' if sort == 'newest' else '-created'
                queryset = queryset.order_by(sort_type)
                query_context['sort'] = sort
            else:
                queryset = queryset.order_by('created')
            count = attributes.get('count')
            if count:
                try:
                    count = int(count)
                    more = attributes.get('more')
                    if more:
                        count += self.elements_quant
                except (ValueError, TypeError):
                    count = self.elements_quant
            else:
                count = self.elements_quant
            query_context['count'] = count
            query_context['show_more'] = True if count < queryset.count() else False

            return queryset, query_context

        def get_context_data(self, **kwargs):
            context = super(TaskAnswerListView, self).get_context_data(**kwargs)
            context['notification_context'] = NotificationContent.from_type(NotificationType.TASK_ANSWER_LIST_GOTO)
            context['no_task_answers_notification_context'] = NotificationContent.from_type(
                NotificationType.NO_TASK_ANSWERS)
            context['navigation_item'] = self.request.resolver_match.url_name

            apprentice = self.request.user
            if self.request.resolver_match.url_name == 'own-video-list':
                answers = ApprenticeTaskAnswer.objects.own(apprentice)
            elif self.request.resolver_match.url_name == 'other-video-list':
                answers = ApprenticeTaskAnswer.objects.others(apprentice)
            else:
                answers = ApprenticeTaskAnswer.objects.none()
            answers, query_context = self.process_with_query_attributes(answers)
            context['task_answers'] = answers
            context.update(query_context)
            return context

    @apprentice_login_required
    class TaskAnswerDetailView(DetailView):
        """Widok reprezentujący odpowiedz do zadania, szczegoly z widoku moje filmy i oceniaj"""
        template_name = 'tasks/task_answer.html'
        pk_url_kwarg = 'task_answer_id'
        context_object_name = 'selected_task_answer'

        def get_context_data(self, **kwargs):
            context = super(TaskAnswerDetailView, self).get_context_data(**kwargs)
            apprentice = self.request.user
            own_videos = self.object.apprentice == apprentice
            context['navigation_item'] = 'own-video-list' if own_videos else 'other-video-list'
            context['vote_list'] = True if own_videos or self.request.user in \
                                                         self.object.video_2.apprentices.all() else False
            context['random_task_answer_from_task'] = ApprenticeTaskAnswer.objects.random_from_task_answer(self.object, 3)
            return context

        def get_queryset(self):
            return ApprenticeTaskAnswer.objects.completed()

    class TaskNotificationsContentContextMixin(ContextMixin):
        def get_context_data(self, **kwargs):
            context = super(TaskNotificationsContentContextMixin, self).get_context_data(**kwargs)
            context['vote_notification_context'] = NotificationContent.from_type(NotificationType.TASK_ANSWER_VOTE)
            context['mentor_notification_context'] = NotificationContent.from_type(NotificationType.TASK_ANSWER_MENTOR)
            context['articles_notification_context'] = NotificationContent.from_type(NotificationType.TASK_ANSWER_ARTICLES)
            context['exercises_notification_context'] = NotificationContent.from_type(
                NotificationType.TASK_ANSWER_EXERCISES)
            return context

    @apprentice_login_required
    class TaskDetailView(DetailView, FormView, ActivePathsContextMixin, TaskNotificationsContentContextMixin):
        """Widok reprezentujący wybrane zadanie"""
        template_name = 'tasks/task.html'
        pk_url_kwarg = 'task_id'
        context_object_name = 'selected_task'
        form_class = ApprenticeTaskAnswerForm

        def dispatch(self, request, *args, **kwargs):
            apprentice = request.user
            self.object = self.get_object()
            task = self.object
            if task.path.is_path_blocking:
                try:
                    task_answer = ApprenticeTaskAnswer.objects.get(task=task, apprentice=apprentice)
                    return redirect(reverse_lazy('tasks:task-submit-detail', kwargs={'task_answer_slug': task_answer.slug(),
                                                                                     'task_answer_id': task_answer.id}))
                except ApprenticeTaskAnswer.MultipleObjectsReturned:
                    return redirect(reverse_lazy('path:path-list'))
                    # TODO: LOG
                except ApprenticeTaskAnswer.DoesNotExist:
                    if not task.get_in_path_position() - 1 == apprentice.answers.completed().filter(
                            task__position__lt=task.position, task__path=task.path).count():
                        return redirect(reverse_lazy('tasks:path-detail', kwargs={'path_slug': task.path.slug(),
                                                                                  'path_id': task.path.id}))
            return super(TaskDetailView, self).dispatch(request, *args, **kwargs)

        def get_queryset(self):
            return Task.objects.active()

        def get(self, request, *args, **kwargs):
            context = self.get_context_data(object=self.object)
            return self.render_to_response(context)

        def form_valid(self, form):
            apprentice = self.request.user
            task = self.get_object()
            if task.path.is_path_blocking:
                try:
                    task_answer = ApprenticeTaskAnswer.objects.get(apprentice=apprentice, task=task)
                    # Przypadek w którym ścieżka jest blokująca i istnieje już jedna odpowiedz do tego zadania a mimo to
                    # ktos probuje wgrac kolejna - nastepuje przekierowanie do tej istniejacej juz instancji
                    # TODO: LOG
                    return HttpResponseRedirect(reverse_lazy('tasks:task-submit-detail',
                                                             kwargs={'task_answer_slug': task_answer.slug(),
                                                                     'task_answer_id': task_answer.id}))
                except ApprenticeTaskAnswer.MultipleObjectsReturned:
                    return HttpResponseRedirect(reverse_lazy('tasks:path-detail',
                                                             kwargs={'path_slug': task.path.slug(),
                                                                     'path_id': task.path.id}))
                    # TODO: LOG
                except ApprenticeTaskAnswer.DoesNotExist:
                    pass
                    # Ok, to znaczy, że dodajemy odpowiedź do tego zadania
            apprentice_video, custom_title = form.save()
            task_answer = ApprenticeTaskAnswer.objects.create(apprentice=apprentice, task=task,
                                                              video_1=apprentice_video,
                                                              custom_title=custom_title)
            self.request.session['first_submit'] = True
            return HttpResponseRedirect(reverse_lazy('tasks:task-submit-detail',
                                                     kwargs={'task_answer_slug': task_answer.slug(),
                                                             'task_answer_id': task_answer.id}))

        def get_context_data(self, **kwargs):
            context = super(TaskDetailView, self).get_context_data(**kwargs)
            apprentice = self.request.user
            tasks = self.object.path.tasks.active().prefetch_related(
                Prefetch('answers', queryset=ApprenticeTaskAnswer.objects.filter(apprentice=apprentice)))
            context['tasks'] = tasks
            context['task_progress'] = 0
            return context

    @apprentice_login_required
    class TaskAnswerSubmittingView(DetailView, FormView, ActivePathsContextMixin, TaskNotificationsContentContextMixin):
        """Widok reprezentujący wybrane zadanie"""
        template_name = 'tasks/task.html'
        pk_url_kwarg = 'task_answer_id'
        context_object_name = 'task_answer'
        model = ApprenticeTaskAnswer
        form_class = ApprenticeTaskAnswerForm

        def post(self, request, *args, **kwargs):
            self.object = self.get_object()
            form = self.get_form()
            if form.is_valid():
                return self.form_valid(form)
            else:
                return self.form_invalid(form)

        def get_queryset(self):
            return ApprenticeTaskAnswer.objects.filter(apprentice=self.request.user)

        def form_valid(self, form):
            apprentice_video, custom_title = form.save()
            task_answer = self.object
            task_answer.video_2 = apprentice_video
            task_answer.custom_title = custom_title
            task_answer.save()
            self.request.session['second_submit'] = True
            return HttpResponseRedirect(reverse_lazy('tasks:task-submit-detail',
                                                     kwargs={'task_answer_slug': task_answer.slug(),
                                                             'task_answer_id': task_answer.id}))

        def get_context_data(self, **kwargs):
            context = super(TaskAnswerSubmittingView, self).get_context_data(**kwargs)
            apprentice = self.request.user
            tasks = self.object.task.path.tasks.active().prefetch_related(
                Prefetch('answers', queryset=ApprenticeTaskAnswer.objects.filter(apprentice=apprentice)))
            context['tasks'] = tasks
            context['first_submit'] = self.request.session.pop('first_submit', None)
            context['second_submit'] = self.request.session.pop('second_submit', None)
            context['selected_task'] = self.object.task
            context['exercise_task_positions'] = self.object.task.exercise_task_positions. \
                annotated_with_done_by_apprentice(self.request.user)
            context['task_progress'] = self.object.get_task_process()
            context['all_exercises_done'] = self.object.task.all_exercises_done(self.request.user)
            context['random_task_answer_from_task_answer'] = ApprenticeTaskAnswer.objects.random_from_task_answer(
                self.object, 3)
            return context