def applications_view(request, pk):
    """
    Display all applicants for session user's open projects.

    pk: Session user's id.
    """
    show_messages(request)
    user = User.objects.get(id=pk)
    if identify(request, user):
        return HttpResponseRedirect(reverse('home'))
    project_list = user.projects.all()
    position_list = []
    for project in project_list:
        for position in project.positions.all():
            position_list.append(position)

    applicants = Applicant.objects.filter(position__in=position_list)

    context = {
        'user': user,
        'applicants': applicants,
        'positions': position_list,
        'term': ''
    }

    return render(request, 'accounts/applications.html', context)
def applications_view_bystatus(request, pk, term):
    """
    Filter applicants by application status.

    pk: Session user's id.
    term:
        'a': accepted
        'r': rejected
        'u': undecided
    """
    show_messages(request)
    user = User.objects.get(id=pk)
    if identify(request, user):
        return HttpResponseRedirect(reverse('home'))
    position_list = []
    project_list = user.projects.all()
    for project in project_list:
        for position in project.positions.all():
            position_list.append(position)
    applicants = Applicant.objects.filter(
        position__in=position_list
    ).filter(status=term)
    context = {
        'user': user,
        'applicants': applicants,
        'positions': position_list,
        'term': term
    }
    return render(request, 'accounts/applications.html', context)
def applications_view_byposition(request, pk, term):
    """
    Filter applicants by position they've applied for.

    pk: Session user's id.
    term: Name of position or positions.
    """
    show_messages(request)
    user = User.objects.get(id=pk)
    if identify(request, user):
        return HttpResponseRedirect(reverse('home'))
    position_list = []
    project_list = user.projects.all()
    for project in project_list:
        for position in project.positions.all():
            if position.name == term:
                position_list.append(position)
    applicants = Applicant.objects.filter(position__in=position_list)
    context = {
        'user': user,
        'applicants': applicants,
        'positions': position_list,
        'term': term
    }
    return render(request, 'accounts/applications.html', context)
def avatar_edit_view(request, pk):
    """
    If session user is target user, allow user to transform their avatar.

    pk: Target user's id.
    """
    target_user = User.objects.get(id=pk)
    avaname = target_user.username
    if identify(request, target_user):
        return HttpResponseRedirect(reverse('home'))
    if not target_user.avatar:
        return redirect('accounts:updatephoto', pk=pk)
    avatype = target_user.avatar.path[-4:]
    # Check for file suffix.
    if os.path.exists('media/avatars/{}{}'.format(avaname, avatype)):
        avatar = Image.open('media/avatars/{}{}'.format(avaname, avatype))
        temp_path = 'media/avatars/{}{}'.format(avaname, avatype)
    else:
        temp_path = ''
        avatar = Image.open(target_user.avatar.path)

    ava_w, ava_h = avatar.size
    form = forms.PhotoEditForm()

    if request.method == 'POST':
        temp_path = 'media/avatars/{}{}'.format(
            avaname,
            avatype
        )
        form = forms.PhotoEditForm(request.POST)
        if form.is_valid():
            resize = form.cleaned_data.get('resize') / 100
            avatar.resize(
                (int(ava_w*resize), int(ava_h*resize)),
                resample=Image.NEAREST
            ).save(temp_path)
            # Set avatar variable to temp_avatar file.
            avatar = Image.open(temp_path)
            rotate = form.cleaned_data.get('rotation')
            if rotate == 'vertical':
                avatar.transpose(Image.FLIP_TOP_BOTTOM).save(temp_path)
            elif rotate == 'horizontal':
                avatar.transpose(Image.FLIP_LEFT_RIGHT).save(temp_path)
            else:
                avatar.rotate(int(rotate)).save(temp_path)
            if form.cleaned_data.get('blackwhite'):
                avatar = Image.open(temp_path)
                avatar.convert(mode='L').save(temp_path)
            return redirect('accounts:transformphoto', pk=pk)

    form = forms.PhotoEditForm()
    context = {
        'form': form,
        'user': target_user,
        'temp_path': temp_path
    }
    return render(request, 'accounts/photo_edit_form.html', context)
def user_deactivate_confirm_view(request, pk):
    """
    If session user is target user, deactivate account.
    Else, redirect to home page and do nothing.

    pk: User's id.
    """
    target_user = User.objects.get(id=pk)
    if identify(request, target_user):
        return HttpResponseRedirect(reverse('home'))
    target_user.is_active = False
    target_user.save()
    messages.success(request, 'Your account has been deactivated.')
    return HttpResponseRedirect(reverse('accounts:logout'))
def user_deactivate_view(request, pk):
    """
    If session user is target user,
    get confirmation for account deactivation.
    Else, redirect to homepage and do nothing.

    pk: User's id.
    """
    show_messages(request)
    target_user = User.objects.get(id=pk)
    if identify(request, target_user):
        return HttpResponseRedirect(reverse('home'))
    return render(
        request,
        'projects/delete.html',
        {'target_user': target_user}
    )
def avatar_confirm_view(request, pk):
    """
    If session user is target user,
    save temporary avatar as user's avatar.
    Else, send to home view.
    
    pk: Target user's id.
    """
    target_user = User.objects.get(id=pk)
    if identify(request, target_user):
        return HttpResponseRedirect(reverse('home'))
    avatype = target_user.avatar.path[-4:]
    temp_path = 'media/avatars/{}{}'.format(
        target_user.username,
        avatype
    )
    avatar = Image.open(temp_path)
    avatar.save(target_user.avatar.path)
    target_user.save()
    os.remove(temp_path)
    return redirect('accounts:photo', pk=pk)
def avatar_update_view(request, pk):
    """
    Upload or replace a user's avatar.
    If session user is not target user, redirect to home page.

    pk: Target user's id.
    """
    show_messages(request)
    user = User.objects.get(id=pk)
    if identify(request, user):
        return HttpResponseRedirect(reverse('home'))
    if request.method == 'POST':
        form = forms.PhotoForm(request.POST, request.FILES, instance=user)
        if form.is_valid():
            form.save()
            messages.success(request, 'Your user photo has been updated.')
            return redirect('accounts:details', pk=pk)
    else:
        form = forms.PhotoForm()
    context = {'form': form, 'user': user}
    return render(request, 'accounts/photo_form.html', context)
def user_update_view(request, pk):
    """
    If session user is target user, update account details.
    Else, redirect to home page.

    pk: Target user's id.
    """
    show_messages(request)
    user = User.objects.get(id=pk)
    if identify(request, user):
        return HttpResponseRedirect(reverse('home'))
    userdata = {
        'display_name': user.display_name,
        'bio': user.bio
    }
    SkillFormSet = formset_factory(pforms.SkillForm,
                                   formset=pforms.BaseSkillFormSet)
    user_skills = user.skills.all().order_by('name')
    skill_data = [{'name': skill.name}
                  for skill in user_skills]
    if request.method == 'GET':
        form = forms.UserForm(initial=userdata)
        formset = SkillFormSet(initial=skill_data)

    elif request.method == 'POST':
        form = forms.UserForm(request.POST, request.FILES, instance=user)
        formset = SkillFormSet(request.POST, request.FILES)
        old_skills = []
        for skill in user.skills.all():
            old_skills.append(skill.name)

        if form.is_valid() and formset.is_valid():
            user = form.save()
            new_skills = []

            for skill_form in formset:
                skill_name = skill_form.cleaned_data.get('name')

                if skill_name:
                    new_skills.append(skill_name)

            try:
                with transaction.atomic():
                    for skill in new_skills:
                        add_skill, _ = Skill.objects.get_or_create(name=skill)
                        add_skill.save()
                        add_skill.users.add(user)
                        if skill not in old_skills:
                            messages.success(
                                request,
                                '{} added to skills!'.format(skill)
                            )
                    for skill in old_skills:
                        if skill not in new_skills:
                            old_skill = Skill.objects.get(name=skill)
                            old_skill.save()
                            old_skill.users.remove(user)
                            messages.success(
                                request,
                                '{} removed from skills!'.format(skill)
                            )
                    user.save()

                    messages.success(request,
                                     'You have updated your profile.')

            except IntegrityError:
                messages.error(request,
                               'There was an error saving your profile.')
                return redirect('accounts:details', pk=pk)

    return render(
        request,
        'accounts/user_form.html',
        {'form': form, 'formset': formset}
    )