Skip to content

Commit

Permalink
more more changes on sources and bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
simodalla committed Jul 15, 2014
1 parent 3f404ce commit 49a9461
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 56 deletions.
59 changes: 47 additions & 12 deletions helpdesk/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from django.contrib.admin.templatetags.admin_urls import admin_urlname
from django.contrib.contenttypes.generic import GenericTabularInline
from django.core.urlresolvers import reverse
from django.http.response import HttpResponseRedirectBase
from django.shortcuts import redirect
from django.utils.translation import ugettext_lazy as _, ugettext

Expand All @@ -17,7 +18,7 @@
from .forms import TicketAdminAutocompleteForm, ReportAdminAutocompleteForm
from .models import (
Category, Tipology, Attachment, Ticket, HelpdeskUser, Message,
Report, StatusChangesLog)
Report, StatusChangesLog, Source)
from .views import OpenTicketView, ObjectToolsView


Expand Down Expand Up @@ -83,7 +84,7 @@ class TicketAdmin(admin.ModelAdmin):

operator_read_only_fields = ['content', 'tipologies', 'priority', 'status']
operator_list_display = ['requester', 'created']
operator_list_filter = ['requester', 'assignee']
operator_list_filter = ['requester', 'assignee', 'source']
operator_actions = ['requester', 'assignee']

# class Media:
Expand All @@ -107,12 +108,14 @@ def get_object_tools(request, view_name, obj=None):
object_tools[view_name].append(
{'url': reverse('{}_open'.format(admin_prefix_url),
kwargs={'pk': obj.pk}),
'text': ugettext('Open and assign to me')})
'text': ugettext('Open and assign to me'),
'id': 'open_and_assign_ticket'})
elif obj.is_open():
url = reverse(admin_urlname(Report._meta, 'add'))
object_tools[view_name].append(
{'url': '{}?ticket={}'.format(url, obj.pk),
'text': ugettext('Add report')})
'text': ugettext('Add report'),
'id': 'add_report_to_ticket'})
try:
return object_tools[view_name]
except KeyError:
Expand Down Expand Up @@ -249,6 +252,11 @@ def save_formset(self, request, form, formset, change):
formset.save_m2m()

def save_model(self, request, obj, form, change):
if obj.source_id is None:
try:
obj.source = Source.get_default_obj()
except Source.DoesNotExist:
pass
if obj.requester_id is None:
obj.requester = request.user
super(TicketAdmin, self).save_model(request, obj, form, change)
Expand Down Expand Up @@ -313,11 +321,11 @@ class ReportAdmin(admin.ModelAdmin):
form = ReportAdminAutocompleteForm
list_display = ['id', 'ticket', 'content', 'visible_from_requester',
'action_on_ticket', 'sender', 'recipient']
radio_fields = {'action_on_ticket': admin.VERTICAL}
search_fields = ['ticket__pk', 'ticket__content', 'content']

@staticmethod
def _check_access(request):
url_to_redirect = reverse(admin_urlname(Ticket._meta, 'changelist'))
ticket_id = request.GET.get('ticket', None)
error = None
if not ticket_id:
Expand All @@ -326,18 +334,45 @@ def _check_access(request):
error = "ERROR TICKET ID NO TICKET MATCH"
if error:
messages.error(request, error)
return redirect(url_to_redirect)
return redirect(admin_urlname(Ticket._meta, 'changelist'))

def add_view(self, request, form_url='', extra_context=None):
print("---------->", request.session.get('site_id'))
return (
ReportAdmin._check_access(request) or
super(ReportAdmin, self).add_view( request, form_url=form_url,
extra_context=extra_context)
)
result = ReportAdmin._check_access(request)
if not result:
result = super(ReportAdmin, self).add_view(
request, form_url=form_url, extra_context=extra_context)
if issubclass(result.__class__, HttpResponseRedirectBase):
result = redirect(admin_urlname(Ticket._meta, 'change'),
request.GET.get('ticket'))
return result

def save_model(self, request, obj, form, change):
if obj.sender_id is None:
obj.sender = request.user
if obj.recipient_id is None:
obj.recipient = obj.ticket.requester
super(ReportAdmin, self).save_model(request, obj, form, change)


class SourceAdmin(admin.ModelAdmin):
actions = None
filter_horizontal = ('sites',)
list_display = ['code', 'title']

def has_delete_permission(self, request, obj=None):
from helpdesk.core import DEFAULT_SOURCES
if obj and obj.code in [code for code, title in DEFAULT_SOURCES]:
error_msg = _(
" %(title)s is a system %(model)s and is not"
" eliminated.") % {'title': obj.title,
'model': obj._meta.verbose_name.lower()}
self.message_user(request, error_msg)
return False
return super(SourceAdmin, self).has_delete_permission(request, obj=obj)


admin.site.register(Category, CategoryAdmin)
admin.site.register(Tipology, TipologyAdmin)
admin.site.register(Report, ReportAdmin)
admin.site.register(Ticket, TicketAdmin)
admin.site.register(Source, SourceAdmin)
1 change: 0 additions & 1 deletion helpdesk/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
'helpdesk.delete_category',
'helpdesk.add_tipology', 'helpdesk.change_tipology',
'helpdesk.delete_tipology',

])
HELPDESK_TICKET_MAX_TIPOLOGIES = 3

Expand Down
19 changes: 15 additions & 4 deletions helpdesk/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from autocomplete_light import ModelForm as AutocompleteModelForm

from .models import Ticket, Report
from .models import Ticket, Report, Source


class TicketAdminForm(forms.ModelForm):
Expand All @@ -20,9 +20,20 @@ def __init__(self, *args, **kwargs):
super(TicketAdminForm, self).__init__(*args, **kwargs)
# tipologies is filtered by current site if 'tipologies' in
# self.fields. If field is read_only isn't in self.fields
if 'tipologies' in self.fields:
site = Site.objects.get(pk=current_site_id())
self.fields['tipologies'].queryset = site.tipologies.all()
# for field, related_name in ('t')
site = Site.objects.get(pk=current_site_id())
for field, related_name in [('tipologies', 'helpdesk_tipologies'),
('source', 'helpdesk_sources')]:
if field in self.fields:
relate_manager = getattr(site, related_name, None)
print(relate_manager)
if relate_manager:
self.fields[field].queryset = relate_manager.all()
if 'source' in self.fields:
try:
self.fields['source'].initial = Source.get_default_obj()
except Source.DoesNotExist:
pass

def clean_tipologies(self):
"""
Expand Down
11 changes: 8 additions & 3 deletions helpdesk/management/commands/demohelpdesk.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from six.moves import cStringIO
from helpdesk.management.commands import inithelpdesk
from helpdesk.models import (HelpdeskUser, Category, Ticket, Message, Report,
PRIORITIES, Tipology)
PRIORITIES, Tipology, Source)
from helpdesk.defaults import (
HELPDESK_REQUESTERS, HELPDESK_OPERATORS, HELPDESK_ADMINS)

Expand Down Expand Up @@ -39,6 +39,9 @@ def handle(self, *apps, **options):
inithelpdesk.Command().execute(stdout=cStringIO(), stderr=cStringIO())

default_site = Site.objects.get(pk=1)

[source.sites.add(default_site) for source in Source.objects.all()]

for c in range(0, 5):
category, c_created = Category.objects.get_or_create(
title='category {}'.format(c))
Expand Down Expand Up @@ -77,12 +80,14 @@ def handle(self, *apps, **options):
cursor.execute("SELECT setval('public.helpdesk_{}_id_seq',"
" 1, true);".format(table))

for n, p in enumerate(PRIORITIES):
for n, priority in enumerate(PRIORITIES):
ticket = Ticket()
ticket.priority = p[0]
ticket.priority = priority[0]
ticket.requester = user
ticket.content = t.render(Context({}))
ticket.site = default_site
ticket.source = Source.objects.get(
code='portal' if n % 2 == 1 else 'email')
ticket.save()
ticket.tipologies.add(*tipologies[0:2])
ticket.initialize()
Expand Down
16 changes: 16 additions & 0 deletions helpdesk/management/commands/inithelpdesk.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
from __future__ import unicode_literals, absolute_import

from django.contrib.auth.models import Group, Permission
from django.contrib.sites.models import Site
from django.core.management.base import BaseCommand

from helpdesk.core import DEFAULT_SOURCES
from helpdesk.defaults import (
HELPDESK_REQUESTERS, HELPDESK_OPERATORS, HELPDESK_ADMINS)
from helpdesk.models import Source

from mezzanine.utils.sites import current_site_id


class Command(BaseCommand):
Expand Down Expand Up @@ -37,3 +42,14 @@ def handle(self, *apps, **options):
codename__in=permission_codenames))
self.stdout.write('Add permissions to {}: {}.\n\n'.format(
group.name, permission_codenames))

site = Site.objects.get(pk=current_site_id())
Source.objects.all().delete()
for code, title in DEFAULT_SOURCES:
source, created = Source.objects.get_or_create(
code=code, defaults={'title': title})
if created:
source.sites.add(site)



31 changes: 24 additions & 7 deletions helpdesk/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class Tipology(TimeStamped):
related_name='tipologies')
sites = models.ManyToManyField('sites.Site', blank=True,
verbose_name=_('Enable on Sites'),
related_name='tipologies')
related_name='helpdesk_tipologies')
priority = models.IntegerField(_('Priority'), choices=PRIORITIES,
default=PRIORITY_LOW)

Expand Down Expand Up @@ -180,17 +180,27 @@ class Meta:

@python_2_unicode_compatible
class Source(TimeStamped):
title = models.CharField(_('Title'), max_length=500)
active = models.BooleanField(default=True)
code = models.CharField(_('code'), max_length=30, unique=True)
title = models.CharField(_('Title'), max_length=30, unique=True)
sites = models.ManyToManyField('sites.Site', blank=True,
verbose_name=_('Enable on Sites'),
related_name='helpdesk_sources')

class Meta:
verbose_name = _('Source')
verbose_name_plural = _('Sources')
ordering = ('-created',)
ordering = ('title',)

def __str__(self):
return self.title

@classmethod
def get_default_obj(cls):
try:
return cls.objects.get(code='portal')
except cls.DoesNotExist as dne:
raise dne


@python_2_unicode_compatible
class Ticket(SiteRelated, TimeStamped, RichText, StatusModel):
Expand All @@ -207,7 +217,6 @@ class Ticket(SiteRelated, TimeStamped, RichText, StatusModel):
related_tickets = models.ManyToManyField(
'self', verbose_name=_('Related tickets'), blank=True)
source = models.ForeignKey('Source', verbose_name=_('Source'),
limit_choices_to={'active': True},
blank=True, null=True)

class Meta:
Expand Down Expand Up @@ -347,10 +356,18 @@ def __str__(self):
return self.content


ACTIONS_ON_TICKET = (
('no_action', _('No action (maintain the current status)')),
('put_on_pending', _('Put on pending')),
('close', _('Close Ticket')),
)


@python_2_unicode_compatible
class Report(Message):
action_on_ticket = models.IntegerField(blank=True, null=True)
visible_from_requester = models.BooleanField(default=True)
action_on_ticket = models.CharField(max_length=50, default='no_action',
choices=ACTIONS_ON_TICKET)
visible_from_requester = models.BooleanField(default=False)

class Meta:
get_latest_by = 'created'
Expand Down
10 changes: 6 additions & 4 deletions helpdesk/static/helpdesk/js/helpdesk.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ $(document).ready(function () {
var url = "/admin/helpdesk/ticket/object_tools/?view=" + current_url;
$.get(url, function (data) {
var object_tools_ul = $('ul.object-tools');
for(var key in data) {
object_tools_ul.append(
'<li><a href="'+ data[key].url +'">' +
data[key].text+ '</a></li>');
for (var key in data) {
var li = '<li><a href="'+ data[key].url + '"';
if (data[key].id) {
li += ' id="' + data[key].id + '"';
}
object_tools_ul.append(li + '>' + data[key].text+ '</a></li>');
}
}, "json");

Expand Down
4 changes: 4 additions & 0 deletions tests/lives/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ def user(self, user):
def quit(self):
self.driver.quit()

@property
def current_url(self):
return self.driver.current_url.replace(self.live_server.url, '')

def get(self, url, *args, **kwargs):
from django.core.urlresolvers import reverse
if url.startswith('/'):
Expand Down
49 changes: 25 additions & 24 deletions tests/lives/test_operator_stories.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec

from helpdesk.models import Ticket, StatusChangesLog
from helpdesk.models import Ticket, StatusChangesLog, Report


pytestmark = pytest.mark.django_db
Expand Down Expand Up @@ -116,28 +116,29 @@ def test_open_ticket_from_change_view(browser_o, initialized_ticket):
'ticket_statuschangelog_{}'.format(initialized_ticket.pk))


@pytest.mark.target
@pytest.mark.livetest
def test_add_report_to_open_ticket_without_action(browser_o, opened_ticket):
# new_ticket_ids = [str(t.id) for t in new_tickets]
browser_o.get('admin:helpdesk_ticket_changelist')
# for checkbox in [e for e in browser_o.driver.find_elements_by_name(
# "_selected_action")]:
# if checkbox.get_attribute('value') in new_ticket_ids:
# checkbox.click()
# browser_o.driver.find_element_by_css_selector(
# '.changelist-actions .chzn-single').click()
# exc = Exception('Error')
# for action in browser_o.driver.find_elements_by_css_selector(
# '.chzn-results li'):
# if action.text.strip().lower() == 'open e assign selected tickets':
# with patch('helpdesk.models.Ticket.opening', side_effect=exc):
# action.click()
# error_message = browser_o.get_messages(level='error')
# assert len(error_message) == 1
# for ticket in Ticket.objects.filter(id__in=new_ticket_ids):
# assert ticket.status == Ticket.STATUS.new
# assert ticket.assignee is None
# assert str(ticket.id) in error_message[0].text
# assert 'Error' in error_message[0].text

content = 'foo ' * 10
action = 'no_action'
browser_o.get('admin:helpdesk_ticket_change', *(opened_ticket.id,))
browser_o.driver.find_element_by_id('add_report_to_ticket').click()
browser_o.driver.find_element_by_id('id_content').send_keys(content)
visible_from_req = browser_o.driver.find_element_by_id(
'id_visible_from_requester')
if visible_from_req.is_selected():
visible_from_req.click()
browser_o.driver.find_element_by_css_selector(
'input[value="{}"]'.format(action)).click()
browser_o.driver.find_element_by_name('_save').click()
report = Report.objects.filter(ticket__id=opened_ticket.id).latest()
assert report.ticket.id == opened_ticket.id
assert report.content == content
assert report.sender.pk == browser_o.user.pk
assert report.recipient.pk == opened_ticket.requester.pk
assert report.action_on_ticket == action
assert report.visible_from_requester is False
WebDriverWait(browser_o.driver, 10).until(
ec.visibility_of_element_located((By.ID, 'ticket_form')),
message='It seems that not redirect to ticket change form. Current'
' url is: {}'.format(browser_o.current_url)
)
2 changes: 1 addition & 1 deletion tests/lives/test_requester_stories.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

pytestmark = pytest.mark.django_db


@pytest.mark.target
@pytest.mark.livetest
def test_add_ticket(browser_r, tipologies, ticket_content):
browser_r.get('admin:helpdesk_ticket_add')
Expand Down

0 comments on commit 49a9461

Please sign in to comment.