From 0b6d97e2f652c278e519b8c9aa4cd5b31d433bb2 Mon Sep 17 00:00:00 2001 From: Andrew Williams Date: Thu, 8 Sep 2011 14:42:12 +0100 Subject: [PATCH] Massive reworking of HR to a class view based system. --- app/hr/app_defines.py | 4 +- app/hr/templates/hr/applications/accept.html | 2 +- app/hr/templates/hr/applications/add.html | 2 +- .../hr/applications/add_message.html | 2 +- .../templates/hr/applications/add_note.html | 2 +- .../hr/applications/admin/view_list.html | 10 +- app/hr/templates/hr/applications/reject.html | 2 +- app/hr/templates/hr/applications/view.html | 28 +- .../templates/hr/applications/view_list.html | 2 +- app/hr/templates/hr/blacklist/blacklist.html | 8 +- app/hr/templates/hr/index.html | 11 +- app/hr/templates/hr/recommendations/add.html | 2 +- .../hr/recommendations/view_list.html | 4 +- app/hr/urls.py | 27 +- app/hr/utils.py | 49 +- app/hr/views.py | 603 +++++++++--------- app/sso/templates/sso/lookup/user.html | 6 +- app/templates/base.html | 2 +- 18 files changed, 411 insertions(+), 355 deletions(-) diff --git a/app/hr/app_defines.py b/app/hr/app_defines.py index c26ffe5..1785afb 100644 --- a/app/hr/app_defines.py +++ b/app/hr/app_defines.py @@ -26,8 +26,8 @@ APPLICATION_STATUS_CHOICES = ( APPLICATION_STATUS_ROUTES = { APPLICATION_STATUS_NOTSUBMITTED: [APPLICATION_STATUS_AWAITINGREVIEW], APPLICATION_STATUS_AWAITINGREVIEW: [APPLICATION_STATUS_NOTSUBMITTED, APPLICATION_STATUS_QUERY, APPLICATION_STATUS_FLAGGED], - APPLICATION_STATUS_REJECTED: [], - APPLICATION_STATUS_ACCEPTED: [APPLICATION_STATUS_COMPLETED], + APPLICATION_STATUS_REJECTED: [APPLICATION_STATUS_NOTSUBMITTED], + APPLICATION_STATUS_ACCEPTED: [APPLICATION_STATUS_NOTSUBMITTED, APPLICATION_STATUS_COMPLETED], APPLICATION_STATUS_QUERY: [APPLICATION_STATUS_NOTSUBMITTED, APPLICATION_STATUS_FLAGGED], APPLICATION_STATUS_COMPLETED: [], APPLICATION_STATUS_FLAGGED: [APPLICATION_STATUS_NOTSUBMITTED, APPLICATION_STATUS_QUERY], diff --git a/app/hr/templates/hr/applications/accept.html b/app/hr/templates/hr/applications/accept.html index b5ffc41..c5a1622 100644 --- a/app/hr/templates/hr/applications/accept.html +++ b/app/hr/templates/hr/applications/accept.html @@ -4,7 +4,7 @@ {% block content %}

Fill in a note you want to send to the user.

-
+ {{ form.as_table }} {% csrf_token %} diff --git a/app/hr/templates/hr/applications/add.html b/app/hr/templates/hr/applications/add.html index 8a9872d..05412b2 100644 --- a/app/hr/templates/hr/applications/add.html +++ b/app/hr/templates/hr/applications/add.html @@ -5,7 +5,7 @@ {% block content %}

Select the character you wish to apply with, then the corporation you wish to apply for.

- +
{{ form.as_table }}
diff --git a/app/hr/templates/hr/applications/add_message.html b/app/hr/templates/hr/applications/add_message.html index cf12ad8..fd26c74 100644 --- a/app/hr/templates/hr/applications/add_message.html +++ b/app/hr/templates/hr/applications/add_message.html @@ -3,7 +3,7 @@ {% block title %}Send Message to Applicant{% endblock %} {% block content %} - + {{ form.as_table }}
diff --git a/app/hr/templates/hr/applications/add_note.html b/app/hr/templates/hr/applications/add_note.html index c19a730..436cca3 100644 --- a/app/hr/templates/hr/applications/add_note.html +++ b/app/hr/templates/hr/applications/add_note.html @@ -3,7 +3,7 @@ {% block title %}Add Note to Application{% endblock %} {% block content %} - + {{ form.as_table }}
diff --git a/app/hr/templates/hr/applications/admin/view_list.html b/app/hr/templates/hr/applications/admin/view_list.html index 347a716..c0eab91 100644 --- a/app/hr/templates/hr/applications/admin/view_list.html +++ b/app/hr/templates/hr/applications/admin/view_list.html @@ -5,21 +5,21 @@ {% block content %}

Search All Applications

- +
{% if apps %} - - - + + + {% for app in apps %} - + diff --git a/app/hr/templates/hr/applications/reject.html b/app/hr/templates/hr/applications/reject.html index 88b3911..a76f184 100644 --- a/app/hr/templates/hr/applications/reject.html +++ b/app/hr/templates/hr/applications/reject.html @@ -4,7 +4,7 @@ {% block content %}

Fill in the rejection reason below, please note, this will be sent out to the user.

- +
Application IDCharacterCorporation
Application IDCharacterCorporation Application Status Last Action Date Last Action User
{{ app.id }}
{{ app.id }} {{ app.character }} {{ app.corporation }} {{ app.get_status_display }}
{{ form.as_table }}
diff --git a/app/hr/templates/hr/applications/view.html b/app/hr/templates/hr/applications/view.html index 7920ad4..c787f51 100644 --- a/app/hr/templates/hr/applications/view.html +++ b/app/hr/templates/hr/applications/view.html @@ -27,29 +27,29 @@

{% if app.status < 1 %} -Submit Application +Submit Application {% else %} -Withdraw Application +Withdraw Application {% endif %} -Add Message +Add Message {% if hrstaff %} -Add Staff Note +Add Staff Note {% if app.status < 2 or app.status = 4 or app.status = 6 %} {% if perms.hr.can_accept %} -Reject Application +Reject Application {% ifequal app.blacklisted 0 %} -Accept Application +Accept Application {% endifequal %} {% endif %} {% ifnotequal app.status 4 %} -Mark as In Query +Mark as In Query {% endifnotequal %} {% ifnotequal app.status 6 %} -Flag for Review +Flag for Review {% endifnotequal %} {% endif %} {% ifequal app.status 3 %} -Mark as Complete +Mark as Complete {% endifequal %} {% endif %}

@@ -166,7 +166,7 @@ function createRequestObject() { var http = createRequestObject(); function redditposts(action) { - http.open('get', '{% url hr.views.view_application app.id %}?redditxhr'); + http.open('get', '{% url reddit-commentsjson %}?userid={{ app.user.id }}'); http.onreadystatechange = handleResponse; http.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); http.send(null); @@ -180,11 +180,11 @@ function handleResponse() { document.getElementById('loadlink').style.display = 'none'; var out = ''; - for (var obj in response) { - if (response[obj]['kind'] == 2) { - var out = out + "

" + response[obj]['title'] + " - (/r/" + response[obj]['subreddit']+ ")

"; + for (var obj in response['posts']) { + if (response['posts'][obj]['kind'] == 2) { + var out = out + "

" + response['posts'][obj]['title'] + " - (/r/" + response['posts'][obj]['subreddit']+ ")

"; } else { - var out = out + "

" + response[obj]['body'] + "
/r/" + response[obj]['subreddit'] + " Permalink

"; + var out = out + "

" + response['posts'][obj]['body'] + "
/r/" + response['posts'][obj]['subreddit'] + " Permalink

"; } } document.getElementById('redditposts').innerHTML = out; diff --git a/app/hr/templates/hr/applications/view_list.html b/app/hr/templates/hr/applications/view_list.html index d3e8c44..bc38169 100644 --- a/app/hr/templates/hr/applications/view_list.html +++ b/app/hr/templates/hr/applications/view_list.html @@ -8,7 +8,7 @@ {% for app in apps %} - + diff --git a/app/hr/templates/hr/blacklist/blacklist.html b/app/hr/templates/hr/blacklist/blacklist.html index be2b42d..4a34ca8 100644 --- a/app/hr/templates/hr/blacklist/blacklist.html +++ b/app/hr/templates/hr/blacklist/blacklist.html @@ -1,5 +1,5 @@ {% extends "base.html" %} - +{% load installed %} {% block title %}Blacklist User{% endblock %} {% block content %} @@ -10,12 +10,14 @@
  • EVE API Keys
  • Characters
  • Email Addresses
  • +{% if "reddit"|installed %}
  • Reddit Accounts
  • +{% endif %} - +
    Application IDCharacterCorporationApplication Status
    {{ app.id }}
    {{ app.id }} {{ app.character }} {{ app.corporation }} {{ app.get_status_display }}
    - + {{ form.as_table }}
    {{ u.username }}
    {{ blacklistuser.username }}
    {% csrf_token %} diff --git a/app/hr/templates/hr/index.html b/app/hr/templates/hr/index.html index e3b5b32..e537a61 100644 --- a/app/hr/templates/hr/index.html +++ b/app/hr/templates/hr/index.html @@ -6,20 +6,21 @@

    HR

    Applications

    -

    View your current open applications
    -Create a application

    +

    View your current open applications
    +Create a application

    + {% if can_recommend %}

    Recommendations

    -View your current open recommendations
    -Add a recommendation
    +View your current open recommendations
    +Add a recommendation

    {% endif %} {% if hrstaff %}

    HR Admin

    -View applications
    +View applications

    {% endif %} diff --git a/app/hr/templates/hr/recommendations/add.html b/app/hr/templates/hr/recommendations/add.html index 013e07a..a82fcf2 100644 --- a/app/hr/templates/hr/recommendations/add.html +++ b/app/hr/templates/hr/recommendations/add.html @@ -7,7 +7,7 @@ The person you are recommending needs to have created their application before you can add a recommendation.

    - + {{ form.as_table }}
    diff --git a/app/hr/templates/hr/recommendations/view_list.html b/app/hr/templates/hr/recommendations/view_list.html index 3b9e54e..ca225c8 100644 --- a/app/hr/templates/hr/recommendations/view_list.html +++ b/app/hr/templates/hr/recommendations/view_list.html @@ -5,13 +5,13 @@ {% block content %}

    This list shows your current open recommendations that are yet to be submitted, as soon as the recommended user submits their application your recommendation will be removed from this list.

    -{% if recs %} +{% if recommendations %} -{% for rec in recs %} +{% for rec in recommendations %} diff --git a/app/hr/urls.py b/app/hr/urls.py index eff0176..2d3ffda 100644 --- a/app/hr/urls.py +++ b/app/hr/urls.py @@ -1,22 +1,23 @@ from django.conf.urls.defaults import * +from django.contrib.auth.decorators import login_required from hr import views urlpatterns = patterns('', - ('^$', views.index), - (r'^recommendation/$', views.view_recommendations), - (r'^application/$', views.view_applications), - (r'^application/(?P\d+)/$', views.view_application), - (r'^application/(?P\d+)/update/(?P\d+)/$', views.update_application), - (r'^application/(?P\d+)/note/$', views.add_note), - (r'^application/(?P\d+)/message/$', views.add_message), - (r'^application/(?P\d+)/reject/$', views.reject_application), - (r'^application/(?P\d+)/accept/$', views.accept_application), + url('^$', login_required(views.HrIndexView.as_view()), name='hr-index'), - (r'^application/add/$', views.add_application), - (r'^recommendation/add/$', views.add_recommendation), + url(r'^application/$', login_required(views.HrViewUserApplications.as_view()), name='hr-userapplications'), + url(r'^application/(?P\d+)/$', login_required(views.HrViewApplication.as_view()), name='hr-viewapplication'), + url(r'^application/(?P\d+)/update/(?P\d+)/$', login_required(views.HrUpdateApplication.as_view()), name='hr-updateapplication'), + url(r'^application/(?P\d+)/note/$', login_required(views.HrAddNote.as_view()), name='hr-addnote'), + url(r'^application/(?P\d+)/message/$', login_required(views.HrAddMessage.as_view()), name='hr-addmessage'), + url(r'^application/(?P\d+)/reject/$', login_required(views.HrRejectApplication.as_view()), name='hr-rejectapplication'), + url(r'^application/(?P\d+)/accept/$', login_required(views.HrAcceptApplication.as_view()), name='hr-acceptapplication'), + url(r'^application/add/$', login_required(views.HrAddApplication.as_view()), name='hr-addapplication'), + url(r'^application/admin/$', login_required(views.HrAdminApplications.as_view()), name='hr-admin'), - (r'^application/admin$', views.admin_applications), + url(r'^recommendation/$', login_required(views.HrViewRecommendations.as_view()), name='hr-viewrecommendations'), + url(r'^recommendation/add/$', login_required(views.HrAddRecommendation.as_view()), name='hr-addrecommendation'), - (r'^blacklist/user/(?P\d+)/$', views.blacklist_user), + url(r'^blacklist/user/(?P\d+)/$', login_required(views.HrBlacklistUser.as_view()), name='hr-blacklistuser'), ) diff --git a/app/hr/utils.py b/app/hr/utils.py index ea8505c..726c7d5 100644 --- a/app/hr/utils.py +++ b/app/hr/utils.py @@ -1,10 +1,12 @@ import re - from datetime import datetime + +from django.db import models +from django.template.loader import render_to_string + +from eve_api.models import EVEPlayerCharacter from hr.app_defines import * from hr.models import Blacklist, Application -from django.db import models -from eve_api.models import EVEPlayerCharacter def installed(value): from django.conf import settings @@ -42,7 +44,7 @@ def blacklist_values(user, level=BLACKLIST_LEVEL_NOTE): blacklist.extend(bl_items.filter(type=BLACKLIST_TYPE_AUTH, value=user.username.lower())) # Check EVE Related blacklists - evechars = EVEPlayerCharacter.objects.filter(eveaccount__user=user).select_related('corporation', 'corporation__alliance') + evechars = EVEPlayerCharacter.objects.filter(eveaccount__user=user).distinct().select_related('corporation', 'corporation__alliance') # Check Character blacklists characters = [re.escape(x) for x in evechars.values_list('name', flat=True) if x] @@ -80,3 +82,42 @@ def recommendation_chain(application, first=True): if first: return {name: output} return output + +def check_permissions(user, application=None): + """ Check if the user has permissions to view or admin the application """ + + corplist = EVEPlayerCharacter.objects.select_related('roles').filter(eveaccount__user=user) + if not application: + if user.has_perm('hr.can_view_all') or user.has_perm('hr.can_view_corp') or corplist.filter(roles__name='roleDirector').count(): + return HR_ADMIN + else: + if application.user == user: + return HR_VIEWONLY + if user.has_perm('hr.can_view_all'): + return HR_ADMIN + else: + # Give admin access to directors of the corp + if application.corporation.id in corplist.filter(roles__name='roleDirector').values_list('corporation__id', flat=True): + return HR_ADMIN + + # Give access to none director HR people access + if application.corporation.id in corplist.values_list('corporation__id', flat=True) and user.has_perm('hr.can_view_corp'): + return HR_ADMIN + + return HR_NONE + +def send_message(application, message_type, note=None): + from django.core.mail import send_mail + subject = render_to_string('hr/emails/%s_subject.txt' % message_type, { 'app': application }) + subject = ''.join(subject.splitlines()) + message = render_to_string('hr/emails/%s.txt' % message_type, { 'app': application, 'note': note }) + try: + send_mail(subject, message, getattr(settings, 'DEFAULT_FROM_EMAIL', 'auth@nowhere.com'), [application.user.email]) + except: + pass + + if installed('reddit') and len(application.user.redditaccount_set.all()) > 0: + from reddit.tasks import send_reddit_message + + for account in application.user.redditaccount_set.all(): + send_reddit_message.delay(to=account.username, subject=subject, message=message) diff --git a/app/hr/views.py b/app/hr/views.py index d9e8821..ac730e8 100644 --- a/app/hr/views.py +++ b/app/hr/views.py @@ -1,359 +1,370 @@ from datetime import datetime, timedelta -from django.utils import simplejson + from django.http import HttpResponseRedirect, HttpResponse, Http404 -from django.shortcuts import render_to_response, get_object_or_404, redirect +from django.shortcuts import get_object_or_404 from django.core.urlresolvers import reverse from django.contrib import messages -from django.contrib.auth.models import User, Group +from django.contrib.auth.models import User from django.contrib.auth.decorators import login_required -from django.template import RequestContext -from django.template.loader import render_to_string +from django.views.generic import TemplateView, DetailView, FormView, CreateView, ListView +from django.views.generic.detail import BaseDetailView from django.conf import settings from gargoyle import gargoyle -from utils import installed, blacklist_values +from utils import installed, blacklist_values, check_permissions, send_message from eve_api.models import EVEAccount, EVEPlayerCorporation, EVEPlayerCharacter +from sso.tasks import update_user_access from hr.forms import RecommendationForm, ApplicationForm, NoteForm, BlacklistUserForm, AdminNoteForm from hr.models import Recommendation, Application, Audit, Blacklist, BlacklistSource -from app_defines import * - -### Shared Functions - -def send_message(application, message_type, note=None): - from django.core.mail import send_mail - subject = render_to_string('hr/emails/%s_subject.txt' % message_type, { 'app': application }) - subject = ''.join(subject.splitlines()) - message = render_to_string('hr/emails/%s.txt' % message_type, { 'app': application, 'note': note }) - try: - send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [application.user.email]) - except: - pass - - if installed('reddit') and len(application.user.redditaccount_set.all()) > 0: - from reddit.tasks import send_reddit_message - - for account in application.user.redditaccount_set.all(): - send_reddit_message.delay(to=account.username, subject=subject, message=message) - - -def check_permissions(user, application=None): - """ Check if the user has permissions to view or admin the application """ - - corplist = EVEPlayerCharacter.objects.select_related('roles').filter(eveaccount__user=user) - if not application: - if user.has_perm('hr.can_view_all') or user.has_perm('hr.can_view_corp') or corplist.filter(roles__name='roleDirector').count(): - return HR_ADMIN - else: - if application.user == user: - return HR_VIEWONLY - if user.has_perm('hr.can_view_all'): - return HR_ADMIN - else: - # Give admin access to directors of the corp - if application.corporation.id in corplist.filter(roles__name='roleDirector').values_list('corporation__id', flat=True): - return HR_ADMIN - - # Give access to none director HR people access - if application.corporation.id in corplist.values_list('corporation__id', flat=True) and user.has_perm('hr.can_view_corp'): - return HR_ADMIN - - return HR_NONE +from hr.app_defines import * ### General Views -@login_required -def index(request): - hrstaff = check_permissions(request.user) - can_recommend = False - if len(blacklist_values(request.user, BLACKLIST_LEVEL_ADVISORY)) == 0: - can_recommend = True - return render_to_response('hr/index.html', locals(), context_instance=RequestContext(request)) +class HrIndexView(TemplateView): + """ + Gives the main HR index page, with various options displayed depending on their + access level. + """ + + template_name = 'hr/index.html' + + def get_context_data(self, **kwargs): + context = super(HrIndexView, self).get_context_data(**kwargs) + context['hrstaff'] = check_permissions(self.request.user) + context['can_recommend'] = len(blacklist_values(self.request.user, BLACKLIST_LEVEL_ADVISORY)) == 0 + return context ### Application Management -@login_required -def view_applications(request): - """ Shows a list of the user's applications """ +class HrViewUserApplications(TemplateView): + """ + Shows a list of the user's applications in the system + """ - apps = Application.objects.filter(user=request.user).order_by('id') - return render_to_response('hr/applications/view_list.html', locals(), context_instance=RequestContext(request)) + template_name = 'hr/applications/view_list.html' -@login_required -def view_application(request, applicationid): - """ View a individual application """ + def get_context_data(self, **kwargs): + context = super(HrViewUserApplications, self).get_context_data(**kwargs) + context['applications'] = Application.objects.filter(user=self.request.user).order_by('id') + return context - app = get_object_or_404(Application, id=applicationid) - perm = check_permissions(request.user, app) - if perm == HR_VIEWONLY: - audit = app.audit_set.filter(event__in=[AUDIT_EVENT_STATUSCHANGE, AUDIT_EVENT_REJECTION, AUDIT_EVENT_ACCEPTED, AUDIT_EVENT_MESSAGE]) - elif perm == HR_ADMIN: - hrstaff = True - audit = app.audit_set.all() - else: - return HttpResponseRedirect(reverse('hr.views.index')) +class HrViewApplication(DetailView): + """ + View a individual application and related details + """ - # Respond to Reddit Comment Load - # TODO: Move to reddit app? - if installed('reddit') and gargoyle.is_active('reddit', request) and request.GET.has_key('redditxhr') and request.is_ajax(): - posts = [] - for acc in app.user.redditaccount_set.all(): - try: - accposts = acc.recent_posts() - except: - accposts = [] - posts.extend(accposts) - return HttpResponse(simplejson.dumps(accposts), mimetype='application/javascript') + template_name = 'hr/applications/view.html' + context_object_name = "app" + model = Application + slug_field = 'id' - return render_to_response('hr/applications/view.html', locals(), context_instance=RequestContext(request)) + def get_context_data(self, **kwargs): + context = super(HrViewApplication, self).get_context_data(**kwargs) + perm = check_permissions(self.request.user, self.object) + if perm == HR_VIEWONLY: + context['audit'] = self.object.audit_set.filter(event__in=[AUDIT_EVENT_STATUSCHANGE, AUDIT_EVENT_REJECTION, AUDIT_EVENT_ACCEPTED, AUDIT_EVENT_MESSAGE]) + elif perm == HR_ADMIN: + context['hrstaff'] = True + context['audit'] = self.object.audit_set.all() + return context -@login_required -def add_application(request): - """ Create a new application to a corporation """ - if request.method == 'POST': - form = ApplicationForm(request.POST, user=request.user) - if form.is_valid(): - app = Application(user=request.user, character=form.cleaned_data['character'], corporation=form.cleaned_data['corporation']) - app.save() - messages.add_message(request, messages.INFO, "Your application to %s has been created." % app.corporation) - return HttpResponseRedirect(reverse('hr.views.view_application', args=[app.id])) - else: - form = ApplicationForm(user=request.user) +class HrAddApplication(FormView): - if len(EVEPlayerCorporation.objects.filter(application_config__is_accepting=True)): - return render_to_response('hr/applications/add.html', locals(), context_instance=RequestContext(request)) - else: - return render_to_response('hr/applications/noadd.html', locals(), context_instance=RequestContext(request)) + form_class = ApplicationForm + + def get_form_kwargs(self, **kwargs): + kwargs = super(HrAddApplication, self).get_form_kwargs(**kwargs) + kwargs['user'] = self.request.user + return kwargs + + def form_valid(self, form): + app = Application(user=self.request.user, character=form.cleaned_data['character'], corporation=form.cleaned_data['corporation']) + app.save() + messages.add_message(self.request, messages.INFO, "Your application to %s has been created." % app.corporation) + return HttpResponseRedirect(reverse('hr-viewapplication', args=[app.id])) + + def get_template_names(self): + if len(EVEPlayerCorporation.objects.filter(application_config__is_accepting=True)): + return 'hr/applications/add.html' + else: + return 'hr/applications/noadd.html' ### Recommendation Management -@login_required -def view_recommendations(request): - """ View a list of recommendations the user has made """ +class HrViewRecommendations(TemplateView): + """ + Shows a list of the user's recommendations in the system + """ - recs = Recommendation.objects.filter(user=request.user) - return render_to_response('hr/recommendations/view_list.html', locals(), context_instance=RequestContext(request)) + template_name = 'hr/recommendations/view_list.html' -@login_required -def add_recommendation(request): - """ Add a recommendation to a user's application """ - - # If the person has a blacklist, stop recommendations - if len(blacklist_values(request.user, BLACKLIST_LEVEL_ADVISORY)): - raise Http404 - - if request.method == 'POST': - form = RecommendationForm(request.POST, user=request.user) - if form.is_valid(): - rec = Recommendation(user=request.user) - rec.user_character = form.cleaned_data['character'] - rec.application = form.cleaned_data['application'] - rec.save() - - messages.add_message(request, messages.INFO, "Recommendation added to %s's application" % rec.application ) - return HttpResponseRedirect(reverse('hr.views.view_recommendations')) - else: - form = RecommendationForm(user=request.user) # An unbound form - - return render_to_response('hr/recommendations/add.html', locals(), context_instance=RequestContext(request)) - -@login_required -def admin_applications(request): - # Get the list of viewable applications by the admin - corplist = EVEPlayerCharacter.objects.filter(eveaccount__user=request.user).values_list('corporation', flat=True) - view_status = [APPLICATION_STATUS_AWAITINGREVIEW, APPLICATION_STATUS_ACCEPTED, APPLICATION_STATUS_QUERY, APPLICATION_STATUS_FLAGGED] - - if request.user.has_perm('hr.can_view_all'): - apps = Application.objects.all() - elif request.user.has_perm('hr.can_view_corp'): - apps = Application.objects.filter(corporation__id__in=list(corplist)) - else: - return HttpResponseRedirect(reverse('hr.views.index')) - - if 'q' in request.GET: - query = request.GET['q'] - apps = apps.filter(character__name__icontains=query) - else: - apps = apps.filter(status__in=view_status) - - if 'o' in request.GET: - order = request.GET['o'] - if order in ['id', 'corporation__name', 'character__name']: - apps = apps.order_by(order) - - if 'l' in request.GET: - limit = request.GET['l'] - apps = apps[:limit] - - return render_to_response('hr/applications/admin/view_list.html', locals(), context_instance=RequestContext(request)) - -@login_required -def update_application(request, applicationid, status): - """ Update a application's status """ - - app = get_object_or_404(Application, id=applicationid) - - if int(status) in APPLICATION_STATUS_ROUTES[app.status]: - perm = check_permissions(request.user, app) - if perm == HR_ADMIN or (perm == HR_VIEWONLY and int(status) <= 1): - if not app.status == status: - app.status = status - app.save(user=request.user) - else: - messages.add_message(request, messages.ERROR, "Invalid status change request") - return HttpResponseRedirect(reverse('hr.views.view_application', args=[applicationid])) - -@login_required -def add_note(request, applicationid): - """ Add a note to a application """ - - if check_permissions(request.user) == HR_ADMIN: - if request.method == 'POST': - app = Application.objects.get(id=applicationid) - if check_permissions(request.user, app) == HR_ADMIN: - obj = Audit(application=app, user=request.user, event=AUDIT_EVENT_NOTE) - form = NoteForm(request.POST, instance=obj) - if form.is_valid(): - obj = form.save() - return HttpResponseRedirect(reverse('hr.views.view_application', args=[applicationid])) - - form = NoteForm() - return render_to_response('hr/applications/add_note.html', locals(), context_instance=RequestContext(request)) - - return render_to_response('hr/index.html', locals(), context_instance=RequestContext(request)) + def get_context_data(self, **kwargs): + context = super(HrViewRecommendations, self).get_context_data(**kwargs) + context['recommendations'] = Recommendation.objects.filter(user=self.request.user) + return context -@login_required -def add_message(request, applicationid): - """ Send a message to the end user and note it on the application """ +class HrAddRecommendation(FormView): - app = Application.objects.get(id=applicationid) - perm = check_permissions(request.user, app) - if perm: - if request.method == 'POST': - obj = Audit(application=app, user=request.user, event=AUDIT_EVENT_MESSAGE) - if perm == HR_ADMIN: - form = AdminNoteForm(request.POST, instance=obj, application=app) - else: - form = NoteForm(request.POST, instance=obj) - if form.is_valid(): - obj = form.save() - if not app.user == request.user: - send_message(obj.application, 'message', note=obj.text) - return HttpResponseRedirect(reverse('hr.views.view_application', args=[applicationid])) + template_name = 'hr/recommendations/add.html' + form_class = RecommendationForm - if perm == HR_ADMIN: - form = AdminNoteForm(application=app) + def dispatch(self, request, *args, **kwargs): + if len(blacklist_values(request.user, BLACKLIST_LEVEL_ADVISORY)): + raise Http404 + return super(HrAddRecommendation, self).dispatch(request, *args, **kwargs) + + def form_valid(self, form): + rec = Recommendation(user=self.request.user) + rec.user_character = form.cleaned_data['character'] + rec.application = form.cleaned_data['application'] + rec.save() + + messages.add_message(self.request, messages.INFO, "Recommendation added to %s's application" % rec.application ) + return HttpResponseRedirect(reverse('hr-viewrecommendations')) + + def get_form_kwargs(self): + kwargs = super(HrAddRecommendation, self).get_form_kwargs() + kwargs['user'] = self.request.user + return kwargs + + +class HrAdminApplications(ListView): + + model = Application + template_name = 'hr/applications/admin/view_list.html' + context_object_name = 'apps' + + def get_queryset(self): + if self.request.user.has_perm('hr.can_view_all'): + apps = Application.objects.all() + elif self.request.user.has_perm('hr.can_view_corp'): + apps = Application.objects.filter(corporation__id__in=EVEPlayerCharacter.objects.filter(eveaccount__user=self.request.user)) + + query = self.request.GET.get('q', None) + order = self.request.GET.get('o', 'id') + + # Filter by the query string + if query: + apps = apps.filter(character__name__icontains=query) else: - form = NoteForm() - return render_to_response('hr/applications/add_message.html', locals(), context_instance=RequestContext(request)) + apps = apps.filter(status__in=[APPLICATION_STATUS_AWAITINGREVIEW, APPLICATION_STATUS_ACCEPTED, APPLICATION_STATUS_QUERY, APPLICATION_STATUS_FLAGGED]) - return render_to_response('hr/index.html', locals(), context_instance=RequestContext(request)) + # If a invalid order as been passed, correct it + if not order in ['id', 'corporation__name', 'character__name']: + order = 'id' -@login_required -def reject_application(request, applicationid): - """ Reject the application and notify the user """ + # If we've got a short search string, only get the first 50 + if query and len(query) < 3: + apps = apps[:50] - if check_permissions(request.user) == HR_ADMIN and request.user.has_perm('hr.can_accept'): - app = Application.objects.get(id=applicationid) - if request.method == 'POST': - if check_permissions(request.user, app) == HR_ADMIN: - obj = Audit(application=app, user=request.user, event=AUDIT_EVENT_REJECTION) - form = AdminNoteForm(request.POST, instance=obj, application=app) - if form.is_valid(): - obj = form.save() - obj.application.status = APPLICATION_STATUS_REJECTED - obj.application.save(user=request.user) - send_message(obj.application, 'rejected', note=obj.text) - return HttpResponseRedirect(reverse('hr.views.view_application', args=[applicationid])) + return apps - form = AdminNoteForm(application=app) - return render_to_response('hr/applications/reject.html', locals(), context_instance=RequestContext(request)) - return render_to_response('hr/index.html', locals(), context_instance=RequestContext(request)) +class HrUpdateApplication(BaseDetailView): + """ + Updates the status of a application if the workflow and permissions allow so. + """ + model = Application + slug_field = 'id' -@login_required -def accept_application(request, applicationid): - """ Accept the application and notify the user """ + def render_to_response(self, context): + status = self.kwargs.get('status', None) + if status and int(status) in APPLICATION_STATUS_ROUTES[self.object.status]: + perm = check_permissions(self.request.user, self.object) + if perm == HR_ADMIN or (perm == HR_VIEWONLY and int(status) <= 1): + if not self.object.status == status: + self.object.status = status + self.object.save(user=self.request.user) + self.object = self.model.objects.get(pk=self.object.pk) + messages.add_message(self.request, messages.INFO, "Application %s has been changed to %s" % (self.object.id, self.object.get_status_display())) + else: + messages.add_message(self.request, messages.ERROR, "Invalid status change request") + return HttpResponseRedirect(reverse('hr-viewapplication', args=[self.object.id])) - if check_permissions(request.user) == HR_ADMIN and request.user.has_perm('hr.can_accept'): - app = Application.objects.get(id=applicationid) +class HrAddNote(CreateView): + """ + View to add a note to a application + """ + + template_name = 'hr/applications/add_note.html' + form_class = NoteForm + model = Audit + + def dispatch(self, request, *args, **kwargs): + if not check_permissions(request.user) == HR_ADMIN: + return HttpResponseRedirect(reverse('hr.views.HrIndexView')) + self.application = Application.objects.get(pk=kwargs.get('applicationid')) + return super(HrAddNote, self).dispatch(request, *args, **kwargs) + + def form_valid(self, form): + if check_permissions(self.request.user, self.application) == HR_ADMIN: + self.object = form.save(commit=False) + self.object.event = AUDIT_EVENT_NOTE + self.object.application = self.application + self.object.user = self.request.user + self.object.save() + return HttpResponseRedirect(self.get_success_url()) + + def get_success_url(self): + return reverse('hr-viewapplication', args=[self.application.id]) + + def get_context_data(self, **kwargs): + context = super(HrAddNote, self).get_context_data(**kwargs) + context['application'] = self.application + return context + + +class HrAddMessage(HrAddNote): + + template_name = 'hr/applications/add_message.html' + + def dispatch(self, request, *args, **kwargs): + self.application = Application.objects.get(pk=kwargs.get('applicationid')) + self.perm = check_permissions(request.user, self.application) + if not self.perm: + return HttpResponseRedirect(reverse('hr.views.HrIndexView')) + return super(HrAddMessage, self).dispatch(request, *args, **kwargs) + + def get_form_class(self): + if self.perm == HR_ADMIN: + return AdminNoteForm + else: + return NoteForm + + def get_form_kwargs(self): + kwargs = super(HrAddMessage, self).get_form_kwargs() + if self.perm == HR_ADMIN: + kwargs['application'] = self.application + return kwargs + + def form_valid(self, form): + self.object = form.save(commit=False) + self.object.application = self.application + self.object.event = AUDIT_EVENT_MESSAGE + self.object.user = self.request.user + self.object.save() + if not self.application.user == self.request.user: + try: + send_message(self.application, 'message', note=self.object.text) + except: + pass + return HttpResponseRedirect(self.get_success_url()) + +class HrRejectApplication(CreateView): + + template_name = 'hr/applications/reject.html' + message_template_name = 'rejected' + form_class = AdminNoteForm + model = Audit + application_change_status = APPLICATION_STATUS_REJECTED + audit_event_type = AUDIT_EVENT_REJECTION + + def dispatch(self, request, *args, **kwargs): + self.application = get_object_or_404(Application, pk=kwargs.get('applicationid')) + if not (check_permissions(request.user) == HR_ADMIN and request.user.has_perm('hr.can_accept')): + return HttpResponseRedirect(reverse('hr-index')) + return super(HrRejectApplication, self).dispatch(request, *args, **kwargs) + + def get_form_kwargs(self): + kwargs = super(HrRejectApplication, self).get_form_kwargs() + kwargs['application'] = self.application + return kwargs + + def get_context_data(self, **kwargs): + context = super(HrRejectApplication, self).get_context_data(**kwargs) + context['application'] = self.application + return context + + def form_valid(self, form): + self.object = form.save(commit=False) + self.object.application = self.application + self.object.user = self.request.user + self.object.event = self.audit_event_type + self.object.save() + + self.object.application.status = self.application_change_status + self.object.application.save(user=self.request.user) + + try: + send_message(self.object.application, self.message_template_name, note=self.object.text) + except: + pass + return HttpResponseRedirect(self.get_success_url()) + + def get_success_url(self): + return reverse('hr-viewapplication', args=[self.application.id]) + + +class HrAcceptApplication(HrRejectApplication): + + template_name = 'hr/applications/accept.html' + message_template_name = 'accepted' + application_change_status = APPLICATION_STATUS_ACCEPTED + audit_event_type = AUDIT_EVENT_ACCEPTED + + def dispatch(self, request, *args, **kwargs): + app = get_object_or_404(Application, pk=kwargs.get('applicationid')) if app.blacklisted: messages.add_message(request, messages.INFO, "This application has one or more blacklist entries and cannot be accepted.") - return HttpResponseRedirect(reverse('hr.views.view_application', args=[applicationid])) - - if request.method == 'POST': - if check_permissions(request.user, app) == HR_ADMIN: - obj = Audit(application=app, user=request.user, event=AUDIT_EVENT_ACCEPTED) - form = AdminNoteForm(request.POST, instance=obj, application=app) - if form.is_valid(): - obj = form.save() - obj.application.status = APPLICATION_STATUS_ACCEPTED - obj.application.save(user=request.user) - send_message(obj.application, 'accepted', note=obj.text) - return HttpResponseRedirect(reverse('hr.views.view_application', args=[applicationid])) - - form = AdminNoteForm(application=app) - return render_to_response('hr/applications/accept.html', locals(), context_instance=RequestContext(request)) - - return render_to_response('hr/index.html', locals(), context_instance=RequestContext(request)) + return HttpResponseRedirect(reverse('hr-viewapplication', args=[app.id])) + return super(HrAcceptApplication, self).dispatch(request, *args, **kwargs) -def blacklist_user(request, userid): +class HrBlacklistUser(FormView): - if request.user.has_perm('hr.add_blacklist'): + template_name = 'hr/blacklist/blacklist.html' + form_class = BlacklistUserForm - u = get_object_or_404(User, id=userid) + def dispatch(self, request, *args, **kwargs): + self.blacklist_user = get_object_or_404(User, id=kwargs.get('userid')) + return super(HrBlacklistUser, self).dispatch(request, *args, **kwargs) - if request.method == 'POST': - form = BlacklistUserForm(request.POST) - if form.is_valid(): - source = BlacklistSource.objects.get(id=1) + def get_context_data(self, **kwargs): + context = super(HrBlacklistUser, self).get_context_data(**kwargs) + context['blacklistuser'] = self.blacklist_user + return context - if not form.cleaned_data.get('expiry_date', None): - expiry = datetime.utcnow() + timedelta(days=50*365) - else: - expiry = form.cleaned_data['expiry_date'] + def blacklist_item(type, value): + Blacklist(type=self.type, value=self.value, level=self.level, source=self.source, expiry_date=self.expiry, created_by=self.request.user, reason=self.reason).save() - level = form.cleaned_data.get('level', 0) + def form_valid(self, form): + self.source = BlacklistSource.objects.get(id=1) + self.expiry = form.cleaned_data.get('expiry_date', None) + if not self.expiry: + self.expiry = datetime.utcnow() + timedelta(days=50*365) # 50 year default + self.level = form.cleaned_data.get('level', 0) + self.reason = form.cleaned_data.get('reason', 'No reason provided') - def blacklist_item(type, value): - o = Blacklist(type=type, value=value, level=level, source=source, expiry_date=expiry, created_by=request.user, reason=form.cleaned_data['reason']) - o.save() + # Blacklist email address + self.blacklist_item(BLACKLIST_TYPE_EMAIL, self.blacklist_user.email) - for ea in u.eveaccount_set.all(): - blacklist_item(BLACKLIST_TYPE_APIUSERID, ea.api_user_id) + # Blacklist API keys + for account in self.blacklist_user.eveaccount_set.all(): + self.blacklist_item(BLACKLIST_TYPE_APIUSERID, account.api_user_id) - if installed('reddit'): - for ra in u.redditaccount_set.all(): - blacklist_item(BLACKLIST_TYPE_REDDIT, ra.username) + # Blacklist Characters + for character in EVEPlayerCharacter.objects.filter(eveaccount__user=self.blacklist_user).distinct(): + self.blacklist_item(BLACKLIST_TYPE_CHARACTER, character.name) - for char in EVEPlayerCharacter.objects.filter(eveaccount__user=u): - blacklist_item(BLACKLIST_TYPE_CHARACTER, char.name) + # Blacklist Reddit accounts + if installed('reddit'): + for account in u.redditaccount_set.all(): + self.blacklist_item(BLACKLIST_TYPE_REDDIT, account.username) - blacklist_item(BLACKLIST_TYPE_EMAIL, u.email) + messages.add_message(request, messages.INFO, "User %s has been blacklisted" % u.username ) - messages.add_message(request, messages.INFO, "User %s has been blacklisted" % u.username ) + # Disable the account if requested + if form.cleaned_data.get('disable', None): + self.blacklist_user.active = False + self.blacklist_user.save() - if form.cleaned_data.get('disable', None): - # Disable the account - u.active = False - u.save() + update_user_access.delay(user=self.blacklist_user.id) - for acc in u.serviceaccount_set.all(): - acc.delete() - - messages.add_message(request, messages.INFO, "User %s disabled" % u.username ) - - return redirect('sso.views.user_view', username=u.username) - else: - messages.add_message(request, messages.ERROR, "Error while processing the form") - - form = BlacklistUserForm() - return render_to_response('hr/blacklist/blacklist.html', locals(), context_instance=RequestContext(request)) - - return render_to_response('hr/index.html', locals(), context_instance=RequestContext(request)) + messages.add_message(request, messages.INFO, "User %s disabled" % u.username ) + return redirect('sso.views.user_view', username=self.blacklist_user.username) diff --git a/app/sso/templates/sso/lookup/user.html b/app/sso/templates/sso/lookup/user.html index ce646f5..a8e7924 100644 --- a/app/sso/templates/sso/lookup/user.html +++ b/app/sso/templates/sso/lookup/user.html @@ -23,7 +23,7 @@ Update Access {% if "hr"|installed %} {% if perms.hr.add_blacklist %} -Blacklist User +Blacklist User {% endif %} {% endif %} @@ -49,7 +49,7 @@
    RecommenderRecommended ApplicationApplication Status
    {{ rec.user_character }} {{ rec.application }} {{ rec.application.get_status_display }}
    {% for app in user.application_set.all %} - + @@ -63,7 +63,7 @@
    IDCharacterApplied ToStatus
    {{ app.id }}
    {{ app.id }} {{ app.character }} {{ app.corporation }} {{ app.get_status_display }}
    {% for rec in user.recommendation_set.all %} - + {% endfor %} diff --git a/app/templates/base.html b/app/templates/base.html index 0d8ba4e..efb3442 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -23,7 +23,7 @@
  • Application Access
  • {% endif %} {% if "hr"|installed %} -
  • HR
  • +
  • HR
  • {% endif %}
  • Characters
  • {% if perms.sso.can_search_users %}
    Recommended ApplicationRecommendation CharacterRecommendation Date
    {{ rec.application.character.name }}
    {{ rec.application.character.name }} {{ rec.user_character }} {{ rec.recommendation_date }}