Free and open source ticket system written in python

Add TeamAdmin class to admin.py and create migration for access_non_category_tickets field in Team model

+62 -11
+4 -1
ticketing/admin.py
··· 15 15 16 16 admin.site.register(Comment) 17 17 admin.site.register(Template) 18 - admin.site.register(Team) 18 + 19 + @admin.register(Team) 20 + class TeamAdmin(admin.ModelAdmin): 21 + filter_horizontal = ('members',) 19 22 admin.site.register(FileAttachment)
+18
ticketing/migrations/0013_team_access_non_category_tickets.py
··· 1 + # Generated by Django 5.0.3 on 2024-03-24 14:42 2 + 3 + from django.db import migrations, models 4 + 5 + 6 + class Migration(migrations.Migration): 7 + 8 + dependencies = [ 9 + ("ticketing", "0012_seed_mailtemplates"), 10 + ] 11 + 12 + operations = [ 13 + migrations.AddField( 14 + model_name="team", 15 + name="access_non_category_tickets", 16 + field=models.BooleanField(default=False), 17 + ), 18 + ]
+38
ticketing/models.py
··· 18 18 name = models.CharField(max_length=200) 19 19 description = models.TextField(blank=True) 20 20 members = models.ManyToManyField(PawUser) 21 + access_non_category_tickets = models.BooleanField(default=False) 21 22 22 23 def __str__(self): 23 24 return self.name ··· 66 67 indexes = [ 67 68 models.Index(fields=["priority", "title"]), 68 69 ] 70 + 71 + @classmethod 72 + def _get_tickets(cls, user) -> models.QuerySet: 73 + """ 74 + For regular users with no team: return all open tickets that are created by the user 75 + """ 76 + user_teams = user.team_set.all() 77 + if not user_teams: 78 + return cls.objects.filter(user=user) 79 + 80 + q = cls.objects.filter( 81 + models.Q(user=user) | # tickets created by user 82 + (models.Q(assigned_team__in=user_teams) | models.Q(assigned_to=user)) | # tickets assigned to user or user's team 83 + (models.Q(assigned_team=None) & models.Q(category=None)) # tickets that are not assigned and have no category (general), needs to be excluded with filter 84 + ) 85 + 86 + if not any([team.access_non_category_tickets for team in user_teams]): 87 + return q.exclude(models.Q(assigned_team=None) & models.Q(category=None) & ~models.Q(user=user)) 88 + return q 89 + 90 + @classmethod 91 + def get_open_tickets(cls, user) -> models.QuerySet: 92 + """ 93 + For regular users with no team: return all open tickets that are created by the user 94 + """ 95 + return cls._get_tickets(user).exclude(status=cls.Status.CLOSED) 96 + 97 + @classmethod 98 + def get_closed_tickets(cls, user) -> models.QuerySet: 99 + """ 100 + For regular users with no team: return all closed tickets that are created by the user 101 + """ 102 + return cls._get_tickets(user).filter(status=cls.Status.CLOSED) 103 + 104 + def can_open(self, user): 105 + return self in Ticket._get_tickets(user) 106 + 69 107 70 108 def close_ticket(self): 71 109 self.status = self.Status.CLOSED
+2 -10
ticketing/views.py
··· 8 8 9 9 @login_required 10 10 def show_tickets(request): 11 - if request.user.is_staff: 12 - # show only tickets that are not closed and are not assigned or assigned to the current user's team 13 - tickets = Ticket.objects.filter( 14 - ~Q(status=Ticket.Status.CLOSED) & (~Q(assigned_team=None) 15 - | ~Q(assigned_team__in=request.user.team_set.all())) 16 - ).order_by("priority", "-created_at") 17 - else: 18 - tickets = Ticket.objects.filter( 19 - user=request.user).order_by("-created_at") 11 + tickets = Ticket.get_open_tickets(request.user).order_by("priority", "-updated_at") 20 12 return render(request, "ticketing/tickets.html", {"tickets": tickets}) 21 13 22 14 ··· 37 29 ticket = get_object_or_404(Ticket, pk=ticket_id) 38 30 # comment_templates = Template.objects.filter(category=ticket.category) 39 31 40 - if request.user != ticket.user and not request.user.is_staff: 32 + if not ticket.can_open(request.user): 41 33 return redirect("all_tickets") 42 34 43 35 form, template_form, team_assignment_form, category_assignment_form = CommentForm(