HackAssistant/registration

View on GitHub
organizers/views.py

Summary

Maintainability
F
1 wk
Test Coverage
# Create your views here.
from django.conf import settings
from django.contrib import messages
from django.core.exceptions import ValidationError
from django.db import IntegrityError
from django.db.models import Count, Avg, F, Q
from django.http import Http404, HttpResponseRedirect
from django.urls import reverse
from django.views.generic import TemplateView
from django_filters.views import FilterView
from django_tables2 import SingleTableMixin
from django_tables2.export import ExportMixin

from app import slack
from app.mixins import TabsViewMixin
from app.slack import SlackInvitationException
from applications import emails
from applications.emails import send_batch_emails
from applications.models import APP_PENDING, APP_DUBIOUS, APP_BLACKLISTED
from organizers import models
from organizers.tables import ApplicationsListTable, ApplicationFilter, AdminApplicationsListTable, \
    AdminTeamListTable, InviteFilter, DubiousListTable, DubiousApplicationFilter, VolunteerFilter, \
    VolunteerListTable, MentorListTable, MentorFilter, SponsorListTable, SponsorFilter, SponsorUserListTable, \
    SponsorUserFilter, BlacklistListTable, BlacklistApplicationFilter
from reimbursement.models import Reimbursement, RE_PEND_APPROVAL
from teams.models import Team
from user.mixins import IsOrganizerMixin, IsDirectorMixin, HaveDubiousPermissionMixin, HaveVolunteerPermissionMixin, \
    HaveSponsorPermissionMixin, HaveMentorPermissionMixin, IsBlacklistAdminMixin
from user.models import User, USR_SPONSOR


def add_vote(application, user, tech_rat, pers_rat):
    v = models.Vote()
    v.user = user
    v.application = application
    v.tech = tech_rat
    v.personal = pers_rat
    v.save()
    return v


def add_comment(application, user, text):
    comment = models.ApplicationComment()
    comment.author = user
    comment.set_application(application)
    comment.text = text
    comment.save()
    return comment


def hacker_tabs(user):
    t = [('Application', reverse('app_list'), False), ('Review', reverse('review'),
                                                       'new' if models.HackerApplication.objects.exclude(
                                                           vote__user_id=user.id).filter(status=APP_PENDING) else '')]
    if user.has_dubious_access and getattr(settings, 'DUBIOUS_ENABLED', False):
        t.append(('Dubious', reverse('dubious'),
                  'new' if models.HackerApplication.objects.filter(status=APP_DUBIOUS,
                                                                   contacted=False).count() else ''))
    if user.has_blacklist_access and getattr(settings, 'BLACKLIST_ENABLED', False):
        t.append(('Blacklist', reverse('blacklist'),
                  'new' if models.HackerApplication.objects.filter(status=APP_BLACKLISTED, contacted=False).count()
                  else ''))
    t.append(('Check-in', reverse('check_in_list'), False))
    if getattr(settings, 'REIMBURSEMENT_ENABLED', False):
        t.extend([('Reimbursements', reverse('reimbursement_list'), False),
                  ('Receipts', reverse('receipt_review'), 'new' if Reimbursement.objects.filter(
                      status=RE_PEND_APPROVAL).count() else False), ])
    return t


def sponsor_tabs(user):
    return [('Users', reverse('sponsor_user_list'), False), ('Application', reverse('sponsor_list'), False),
            ('Check-in', reverse('check_in_sponsor_list'), False)]


def volunteer_tabs(user):
    return [('Application', reverse('volunteer_list'), False), ('Check-in', reverse('check_in_volunteer_list'), False)]


def mentor_tabs(user):
    return [('Application', reverse('mentor_list'), False), ('Check-in', reverse('check_in_mentor_list'), False)]


class ApplicationsListView(TabsViewMixin, IsOrganizerMixin, ExportMixin, SingleTableMixin, FilterView):
    template_name = 'applications_list.html'
    table_class = ApplicationsListTable
    filterset_class = ApplicationFilter
    table_pagination = {'per_page': 100}
    exclude_columns = ('detail', 'status', 'vote_avg')
    export_name = 'applications'

    def get_current_tabs(self):
        return hacker_tabs(self.request.user)

    def get_queryset(self):
        return models.HackerApplication.annotate_vote(models.HackerApplication.objects.all())

    def get_context_data(self, **kwargs):
        context = super(ApplicationsListView, self).get_context_data(**kwargs)
        context['otherApplication'] = False
        return context


class InviteListView(TabsViewMixin, IsDirectorMixin, SingleTableMixin, FilterView):
    template_name = 'invite_list.html'
    table_class = AdminApplicationsListTable
    filterset_class = InviteFilter
    table_pagination = {'per_page': 100}

    def get_current_tabs(self):
        return hacker_tabs(self.request.user)

    def get_queryset(self):
        return models.HackerApplication.annotate_vote(models.HackerApplication.objects.filter(status=APP_PENDING))

    def post(self, request, *args, **kwargs):
        ids = request.POST.getlist('selected')
        apps = models.HackerApplication.objects.filter(pk__in=ids).all()
        mails = []
        errors = 0
        for app in apps:
            try:
                app.invite(request.user)
                m = emails.create_invite_email(app, request)
                mails.append(m)
            except ValidationError:
                errors += 1
        if mails:
            send_batch_emails(mails)
            messages.success(request, "%s applications invited" % len(mails))
        else:
            errorMsg = "No applications invited"
            if errors != 0:
                errorMsg = "%s applications not invited" % errors
            messages.error(request, errorMsg)

        return HttpResponseRedirect(reverse('invite_list'))


class ApplicationDetailView(TabsViewMixin, IsOrganizerMixin, TemplateView):
    template_name = 'application_detail.html'

    def get_back_url(self):
        return reverse('app_list')

    def get_context_data(self, **kwargs):
        context = super(ApplicationDetailView, self).get_context_data(**kwargs)
        application = self.get_application(kwargs)
        context['app'] = application
        context['vote'] = self.can_vote()
        context['max_vote'] = dict(models.VOTES)
        context['comments'] = models.ApplicationComment.objects.filter(hacker=application)
        if application and getattr(application.user, 'team', False) and settings.TEAMS_ENABLED:
            context['teammates'] = Team.objects.filter(team_code=application.user.team.team_code) \
                .values('user__name', 'user__email', 'user')

            for mate in context['teammates']:
                if application.user.id == mate['user']:
                    mate['is_me'] = True
                    continue

                mate_app = models.HackerApplication.objects.filter(user=mate['user']).first()
                if mate_app:
                    mate['app_uuid_str'] = mate_app.uuid_str

        return context

    def can_vote(self):
        return False

    def get_application(self, kwargs):
        application_id = kwargs.get('id', None)
        if not application_id:
            raise Http404
        application = models.HackerApplication.objects.filter(uuid=application_id).first()
        if not application:
            raise Http404

        return application

    def post(self, request, *args, **kwargs):
        id_ = request.POST.get('app_id')
        application = models.HackerApplication.objects.get(pk=id_)

        comment_text = request.POST.get('comment_text', None)
        motive_of_ban = request.POST.get('motive_of_ban', None)
        if request.POST.get('add_comment'):
            add_comment(application, request.user, comment_text)
        elif request.POST.get('invite') and request.user.is_director:
            self.invite_application(application)
        elif request.POST.get('confirm') and request.user.is_director:
            self.confirm_application(application)
        elif request.POST.get('cancel') and request.user.is_director:
            self.cancel_application(application)
        elif request.POST.get('waitlist') and request.user.is_director:
            self.waitlist_application(application)
        elif request.POST.get('slack') and request.user.is_organizer:
            self.slack_invite(application)
        elif request.POST.get('set_dubious') and request.user.is_organizer:
            application.set_dubious()
        elif request.POST.get('contact_user') and request.user.has_dubious_access:
            application.set_contacted(request.user)
        elif request.POST.get('unset_dubious') and request.user.has_dubious_access:
            add_comment(application, request.user,
                        "Dubious review result: No problems, hacker allowed to participate in hackathon!")
            application.unset_dubious()
        elif request.POST.get('invalidate') and request.user.has_dubious_access:
            add_comment(application, request.user,
                        "Dubious review result: Hacker is not allowed to participate in hackathon.")
            application.invalidate()
        elif request.POST.get('set_blacklist') and request.user.is_organizer:
            application.set_blacklist()
        elif request.POST.get('unset_blacklist') and request.user.has_blacklist_access:
            add_comment(application, request.user,
                        "Blacklist review result: No problems, hacker allowed to participate in hackathon!")
            application.unset_blacklist()
        elif request.POST.get('confirm_blacklist') and request.user.has_blacklist_access:
            add_comment(application, request.user,
                        "Blacklist review result: Hacker is not allowed to participate in hackathon. " +
                        "Motive of ban: " + motive_of_ban)
            application.confirm_blacklist(request.user, motive_of_ban)

        return HttpResponseRedirect(reverse('app_detail', kwargs={'id': application.uuid_str}))

    def waitlist_application(self, application):
        try:
            application.reject()
            messages.success(self.request, "%s application wait listed" % application.user.email)
        except ValidationError as e:
            messages.error(self.request, e.message)

    def slack_invite(self, application):
        try:
            slack.send_slack_invite(application.user.email)
            messages.success(self.request, "Slack invite sent to %s" % application.user.email)
        except SlackInvitationException as e:
            messages.error(self.request, "Slack error: %s" % str(e))

    def cancel_application(self, application):
        try:
            application.cancel()
            messages.success(self.request, "%s application cancelled" % application.user.email)
        except ValidationError as e:
            messages.error(self.request, e.message)

    def confirm_application(self, application):
        try:
            application.confirm()
            messages.success(self.request, "Ticket to %s successfully sent" % application.user.email)
            m = emails.create_confirmation_email(application, self.request)
            m.send()
        except ValidationError as e:
            messages.error(self.request, e.message)

    def invite_application(self, application):
        try:
            application.invite(self.request.user)
            messages.success(self.request, "Invite to %s successfully sent" % application.user.email)
            m = emails.create_invite_email(application, self.request)
            m.send()
        except ValidationError as e:
            messages.error(self.request, e.message)


class ReviewApplicationView(ApplicationDetailView):
    def get_current_tabs(self):
        return hacker_tabs(self.request.user)

    def get_back_url(self):
        return None

    def get_application(self, kwargs):
        """
        Django model to the rescue. This is transformed to an SQL sentence
        that does exactly what we need
        :return: pending aplication that has not been voted by the current
        user and that has less votes and its older
        """
        max_votes_to_app = getattr(settings, 'MAX_VOTES_TO_APP', 50)
        return models.HackerApplication.objects \
            .exclude(Q(vote__user_id=self.request.user.id) | Q(user_id=self.request.user.id)) \
            .filter(status=APP_PENDING) \
            .annotate(count=Count('vote__calculated_vote')) \
            .filter(count__lte=max_votes_to_app) \
            .order_by('count', 'submission_date') \
            .first()

    def get(self, request, *args, **kwargs):
        r = super(ReviewApplicationView, self).get(request, *args, **kwargs)
        return r

    def post(self, request, *args, **kwargs):
        tech_vote = request.POST.get('tech_rat', None)
        pers_vote = request.POST.get('pers_rat', None)
        comment_text = request.POST.get('comment_text', None)

        application = models.HackerApplication.objects.get(pk=request.POST.get('app_id'))
        try:
            if request.POST.get('skip'):
                add_vote(application, request.user, None, None)
            elif request.POST.get('add_comment'):
                add_comment(application, request.user, comment_text)
            elif request.POST.get('set_dubious'):
                application.set_dubious()
            elif request.POST.get('unset_dubious'):
                application.unset_dubious()
            elif request.POST.get('set_blacklist') and request.user.is_organizer:
                application.set_blacklist()
            elif request.POST.get('unset_blacklist') and request.user.has_blacklist_access:
                add_comment(application, request.user,
                            "Blacklist review result: No problems, hacker allowed to participate in hackathon!")
                application.unset_blacklist()
            else:
                add_vote(application, request.user, tech_vote, pers_vote)
        # If application has already been voted -> Skip and bring next
        # application
        except IntegrityError:
            pass
        return HttpResponseRedirect(reverse('review'))

    def can_vote(self):
        return True


class InviteTeamListView(TabsViewMixin, IsDirectorMixin, SingleTableMixin, TemplateView):
    template_name = 'invite_list.html'
    table_class = AdminTeamListTable
    table_pagination = {'per_page': 100}

    def get_current_tabs(self):
        return hacker_tabs(self.request.user)

    def get_queryset(self):
        return models.HackerApplication.objects.filter(status=APP_PENDING) \
            .exclude(user__team__team_code__isnull=True).values('user__team__team_code').order_by() \
            .annotate(vote_avg=Avg('vote__calculated_vote'),
                      team=F('user__team__team_code'),
                      members=Count('user', distinct=True))

    def get_context_data(self, **kwargs):
        c = super(InviteTeamListView, self).get_context_data(**kwargs)
        c.update({'teams': True})
        return c

    def post(self, request, *args, **kwargs):
        ids = request.POST.getlist('selected')
        apps = models.HackerApplication.objects.filter(user__team__team_code__in=ids).all()
        mails = []
        errors = 0
        for app in apps:
            try:
                app.invite(request.user)
                m = emails.create_invite_email(app, request)
                mails.append(m)
            except ValidationError:
                errors += 1
        if mails:
            send_batch_emails(mails)
            messages.success(request, "%s applications invited" % len(mails))
        else:
            errorMsg = "No applications invited"
            if errors != 0:
                errorMsg = "%s applications not invited" % errors
            messages.error(request, errorMsg)

        return HttpResponseRedirect(reverse('invite_teams_list'))


class DubiousApplicationsListView(TabsViewMixin, HaveDubiousPermissionMixin, ExportMixin, SingleTableMixin,
                                  FilterView):
    template_name = 'dubious_list.html'
    table_class = DubiousListTable
    filterset_class = DubiousApplicationFilter
    table_pagination = {'per_page': 100}
    exclude_columns = ('status', 'vote_avg')
    export_name = 'dubious_applications'

    def get_current_tabs(self):
        return hacker_tabs(self.request.user)

    def get_queryset(self):
        return models.HackerApplication.objects.filter(status=APP_DUBIOUS)


class BlacklistApplicationsListView(TabsViewMixin, IsBlacklistAdminMixin, ExportMixin, SingleTableMixin, FilterView):
    template_name = 'blacklist_list.html'
    table_class = BlacklistListTable
    filterset_class = BlacklistApplicationFilter
    table_pagination = {'per_page': 100}
    exclude_columns = ('status', 'vote_avg')
    export_name = 'blacklist_applications'

    def get_current_tabs(self):
        return hacker_tabs(self.request.user)

    def get_queryset(self):
        return models.HackerApplication.objects.filter(status=APP_BLACKLISTED)


class _OtherApplicationsListView(TabsViewMixin, ExportMixin, SingleTableMixin, FilterView):
    template_name = 'applications_list.html'
    table_pagination = {'per_page': 100}
    exclude_columns = ('detail', 'status')
    export_name = 'applications'

    def get_context_data(self, **kwargs):
        context = super(_OtherApplicationsListView, self).get_context_data(**kwargs)
        context['otherApplication'] = True
        context['emailCopy'] = True
        list_email = ""
        for u in self.object_list.values('user__email'):
            list_email += "%s, " % u['user__email']
        context['emails'] = list_email
        return context


class VolunteerApplicationsListView(HaveVolunteerPermissionMixin, _OtherApplicationsListView):
    table_class = VolunteerListTable
    filterset_class = VolunteerFilter

    def get_queryset(self):
        return models.VolunteerApplication.objects.all()

    def get_current_tabs(self):
        return volunteer_tabs(self.request.user)


class SponsorApplicationsListView(HaveSponsorPermissionMixin, _OtherApplicationsListView):
    table_class = SponsorListTable
    filterset_class = SponsorFilter

    def get_queryset(self):
        return models.SponsorApplication.objects.all()

    def get_context_data(self, **kwargs):
        context = super(SponsorApplicationsListView, self).get_context_data(**kwargs)
        context['otherApplication'] = True
        context['emailCopy'] = False
        return context

    def get_current_tabs(self):
        return sponsor_tabs(self.request.user)


class SponsorUserListView(HaveSponsorPermissionMixin, TabsViewMixin, ExportMixin, SingleTableMixin, FilterView):
    template_name = 'applications_list.html'
    table_pagination = {'per_page': 100}
    exclude_columns = ('detail', 'status')
    export_name = 'applications'
    table_class = SponsorUserListTable
    filterset_class = SponsorUserFilter

    def get_current_tabs(self):
        return sponsor_tabs(self.request.user)

    def get_context_data(self, **kwargs):
        context = super(SponsorUserListView, self).get_context_data(**kwargs)
        context['otherApplication'] = True
        context['emailCopy'] = False
        context['createUser'] = True
        return context

    def get_queryset(self):
        return User.objects.filter(type=USR_SPONSOR)


class MentorApplicationsListView(HaveMentorPermissionMixin, _OtherApplicationsListView):
    table_class = MentorListTable
    filterset_class = MentorFilter

    def get_queryset(self):
        return models.MentorApplication.objects.all()

    def get_current_tabs(self):
        return mentor_tabs(self.request.user)


class ReviewVolunteerApplicationView(TabsViewMixin, HaveVolunteerPermissionMixin, TemplateView):
    template_name = 'other_application_detail.html'

    def get_application(self, kwargs):
        application_id = kwargs.get('id', None)
        if not application_id:
            raise Http404
        application = models.VolunteerApplication.objects.filter(uuid=application_id).first()
        if not application:
            raise Http404

        return application

    def post(self, request, *args, **kwargs):
        id_ = request.POST.get('app_id')
        comment_text = request.POST.get('comment_text', None)
        application = models.VolunteerApplication.objects.get(pk=id_)
        if request.POST.get('invite') and request.user.is_organizer:
            application.invite(request.user)
            application.save()
            m = emails.create_invite_email(application, self.request)
            m.send()
            messages.success(request, 'Volunteer invited!')
        elif request.POST.get('cancel_invite') and request.user.is_organizer:
            application.move_to_pending()
            messages.success(request, 'Volunteer invite canceled')
        elif request.POST.get('add_comment'):
            add_comment(application, request.user, comment_text)
            messages.success(request, 'Comment added')

        return HttpResponseRedirect(reverse('volunteer_detail', kwargs={'id': application.uuid_str}))

    def get_back_url(self):
        return reverse('volunteer_list')

    def get_context_data(self, **kwargs):
        context = super(ReviewVolunteerApplicationView, self).get_context_data(**kwargs)
        application = self.get_application(kwargs)
        context['app'] = application
        context['comments'] = models.ApplicationComment.objects.filter(volunteer=application)
        return context


class ReviewSponsorApplicationView(TabsViewMixin, HaveSponsorPermissionMixin, TemplateView):
    template_name = 'other_application_detail.html'

    def get_application(self, kwargs):
        application_id = kwargs.get('id', None)
        if not application_id:
            raise Http404
        application = models.SponsorApplication.objects.filter(uuid=application_id).first()
        if not application:
            raise Http404

        return application

    def get_back_url(self):
        return reverse('sponsor_list')

    def post(self, request, *args, **kwargs):
        id_ = request.POST.get('app_id')
        comment_text = request.POST.get('comment_text', None)
        application = models.SponsorApplication.objects.get(pk=id_)
        if request.POST.get('add_comment'):
            add_comment(application, request.user, comment_text)
            messages.success(request, 'Comment added')

        return HttpResponseRedirect(reverse('sponsor_detail', kwargs={'id': application.uuid_str}))

    def get_context_data(self, **kwargs):
        context = super(ReviewSponsorApplicationView, self).get_context_data(**kwargs)
        application = self.get_application(kwargs)
        context['app'] = application
        context['comments'] = models.ApplicationComment.objects.filter(sponsor=application)
        return context


class ReviewMentorApplicationView(TabsViewMixin, HaveMentorPermissionMixin, TemplateView):
    template_name = 'other_application_detail.html'

    def get_application(self, kwargs):
        application_id = kwargs.get('id', None)
        if not application_id:
            raise Http404
        application = models.MentorApplication.objects.filter(uuid=application_id).first()
        if not application:
            raise Http404

        return application

    def post(self, request, *args, **kwargs):
        id_ = request.POST.get('app_id')
        application = models.MentorApplication.objects.get(pk=id_)
        comment_text = request.POST.get('comment_text', None)
        if request.POST.get('invite') and request.user.is_organizer:
            application.invite(request.user)
            application.save()
            m = emails.create_invite_email(application, self.request)
            m.send()
            messages.success(request, 'sponsor invited!')
        elif request.POST.get('cancel_invite') and request.user.is_organizer:
            application.move_to_pending()
            messages.success(request, 'Sponsor invite canceled')
        elif request.POST.get('add_comment'):
            add_comment(application, request.user, comment_text)
            messages.success(request, 'comment added')

        return HttpResponseRedirect(reverse('mentor_detail', kwargs={'id': application.uuid_str}))

    def get_back_url(self):
        return reverse('mentor_list')

    def get_context_data(self, **kwargs):
        context = super(ReviewMentorApplicationView, self).get_context_data(**kwargs)
        application = self.get_application(kwargs)
        context['app'] = application
        context['comments'] = models.ApplicationComment.objects.filter(mentor=application)
        return context