Skip to content

Commit

Permalink
Merge branch 'update-deps'
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterJCLaw committed Apr 4, 2024
2 parents 9682aa2 + 7c9db62 commit d1334cd
Show file tree
Hide file tree
Showing 18 changed files with 92 additions and 73 deletions.
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[*]
indent_size = 4
indent_style = space

insert_final_newline = true
trim_trailing_whitespace = true

[*.html]
indent_size = 2

[*.yml]
indent_size = 2

[Makefile]
indent_style = tab
2 changes: 1 addition & 1 deletion helpdesk/accounts/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class SignupForm(UserCreationForm):
widget=forms.PasswordInput(),
required=True,
)

class Meta:
model = User
fields = ("username",)
Expand Down
2 changes: 1 addition & 1 deletion helpdesk/accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def get_form(self, form_class: type[BaseModelForm] | None = None) -> BaseModelFo
form.fields['first_name'].required = True
form.fields['first_name'].label = "Given name"
return form

def form_valid(self, form: BaseModelForm) -> HttpResponse:
messages.info(self.request, f"Welcome to {settings.SYSTEM_TITLE}!")
self.object.onboarded_at = timezone.now()
Expand Down
4 changes: 2 additions & 2 deletions helpdesk/helpdesk/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@

def get_object_or_none(model: type[ModelT], **kwargs: Any) -> ModelT | None:
try:
return model.objects.get(**kwargs)
except model.DoesNotExist:
return model.objects.get(**kwargs) # type: ignore[attr-defined]
except model.DoesNotExist: # type: ignore[attr-defined]
return None
4 changes: 2 additions & 2 deletions helpdesk/helpdesk/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class SearchResult(TypedDict):


class SearchView(LoginRequiredMixin, SingleTableMixin, TemplateView):

template_name = "search.html"
table_class = SearchTable

Expand All @@ -73,7 +73,7 @@ def _get_filters(self, q: str) -> dict[type[Ticket] | type[Team], Q]:
Ticket: Q(title__icontains=q) | Q(events__comment__icontains=q) | Q(id=ticket_id),
Team: Q(tla__icontains=q) | Q(name__icontains=q),
}

def get_result_count(self, q: str) -> int:
filters = self._get_filters(q)
return sum(
Expand Down
3 changes: 2 additions & 1 deletion helpdesk/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ ignore = [
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
"B009", # Do not call `getattr` with a constant attribute value.
"S101", # S101 Use of `assert` detected
"N999", # N999 Invalid module name
]

line-length = 120
line-length = 120
2 changes: 1 addition & 1 deletion helpdesk/teams/management/commands/import_from_srcomp.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def _import_pit_locations(self, srcomp_url: str) -> None:
slug=slug,
defaults={"name": location_data["display_name"]},
)

def _import_teams(self, srcomp_url: str) -> None:
resp = requests.get(f"{srcomp_url}/teams", timeout=5)
resp.raise_for_status()
Expand Down
6 changes: 3 additions & 3 deletions helpdesk/teams/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ class Team(models.Model):
is_rookie = models.BooleanField("Is Rookie")
pit_location = models.ForeignKey(TeamPitLocation, on_delete=models.PROTECT)

class Meta:
ordering = ["tla"]

def __str__(self) -> str:
return f"{self.tla} - {self.name}"

def get_absolute_url(self) -> str:
return reverse_lazy('teams:team_detail', args=[self.tla])

class Meta:
ordering = ["tla"]


class TeamComment(models.Model):
Expand Down
4 changes: 2 additions & 2 deletions helpdesk/teams/srcomp.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def _get(self, endpoint: str) -> dict[str, Any] | None:
return None
except ConnectionError:
return None

try:
return resp.json()
except JSONDecodeError:
Expand All @@ -39,7 +39,7 @@ def _get(self, endpoint: str) -> dict[str, Any] | None:
def get_score_info_for_team(self, tla: str) -> ScoreInfo | None:
if not self._base_url:
return None

if data := self._get(f"teams/{tla}"):
return ScoreInfo(
league_pos=data.get("league_pos"), # type: ignore[arg-type]
Expand Down
6 changes: 3 additions & 3 deletions helpdesk/teams/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def get_context_data(self, **kwargs: dict[str, Any]) -> dict[str, Any]:
comment_form=CommentSubmitForm(),
**kwargs,
)

class TeamSubmitCommentFormView(LoginRequiredMixin, FormMixin, SingleObjectMixin, ProcessFormView):

http_method_names = ['post', 'put']
Expand Down Expand Up @@ -86,10 +86,10 @@ class TeamDetailTicketsView(LoginRequiredMixin, SingleTableMixin, DetailView):

def get_ticket_queryset(self) -> QuerySet[Ticket]:
return self.get_object().tickets.with_event_fields()

def get_ticket_filter(self) -> TicketFilter:
queryset = self.get_ticket_queryset()

return TicketFilter(
data=self.request.GET or None,
request=self.request,
Expand Down
28 changes: 14 additions & 14 deletions helpdesk/tickets/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ def __str__(self) -> str:
if self.description:
return f"{self.name} - {self.description}"
return self.name

def attention_count(self) -> int:
tickets = self.tickets.with_event_fields().exclude(
models.Q(status=TicketStatus.RESOLVED) | models.Q(assignee_id__isnull=False),
)
return tickets.count()

def in_progress_count(self) -> int:
tickets = self.tickets.with_event_fields().filter(
status=TicketStatus.OPEN,
Expand All @@ -53,7 +53,7 @@ def with_status(self) -> TicketQuerySet:
ticket_id=models.OuterRef("pk"),
).order_by("-created_at")
return self.annotate(status=models.Subquery(events.values("new_status")[:1]))

def with_assignee(self) -> TicketQuerySet:
events = TicketEvent.objects.annotate(
assignee=models.F("assignee_change__user"),
Expand All @@ -62,13 +62,13 @@ def with_assignee(self) -> TicketQuerySet:
assignee_change__isnull=False,
).order_by("-created_at")
return self.annotate(assignee_id=models.Subquery(events.values("assignee")[:1]))

def with_event_fields(self) -> TicketQuerySet:
return self.with_assignee().with_status()


class TicketManager(models.Manager):

def get_queryset(self) -> TicketQuerySet: # type: ignore[override]
return TicketQuerySet(self.model, using=self._db)

Expand Down Expand Up @@ -104,7 +104,7 @@ def __str__(self) -> str:

def get_absolute_url(self) -> str:
return reverse_lazy('tickets:ticket_detail', kwargs={'pk': self.id})

@property
def assignee(self) -> User | None:
"""
Expand All @@ -113,22 +113,22 @@ def assignee(self) -> User | None:
Must be called only when the Ticket has with_event_fields()
"""
return get_object_or_none(User, pk=self.assignee_id) # type: ignore[attr-defined]

@property
def status_name(self) -> str:
"""
Get the name of the status.
Must be called only when the Ticket has with_event_fields()
"""
lookups = {val: name for val, name in TicketStatus.choices}
lookups = dict(TicketStatus.choices)
return lookups.get(self.status, "Unknown") # type: ignore[attr-defined]

@property
def status_css_tag(self) -> str:
"""
Get the CSS class of the status.
Must be called only when the Ticket has with_event_fields()
"""
lookup = {
Expand All @@ -140,21 +140,21 @@ def status_css_tag(self) -> str:
@property
def is_escalatable(self) -> bool:
return self.queue.escalation_queue is not None

@property
def last_updated(self) -> datetime:
return max(self.updated_at, self.created_at, *self.events.values_list("created_at", flat=True))


class TicketStatus(models.TextChoices):
OPEN = "OP", "Open"
OPEN = "OP", "Open"
RESOLVED = "RS", "Resolved"


class TicketEventAssigneeChange(models.Model):
"""
For a given ticket event, this model exists iff the assignee changed.
We need a separate table for this so that we can differentiate
between changing of an assignee and removal.
Expand Down
2 changes: 1 addition & 1 deletion helpdesk/tickets/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ class Meta:
order_by = 'created_at'

def render_status(self, value: str) -> str:
lookups = {val: name for val, name in TicketStatus.choices}
lookups = dict(TicketStatus.choices)
return lookups.get(value, "Unknown")
8 changes: 4 additions & 4 deletions helpdesk/tickets/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ def get_ticket_queryset(self) -> QuerySet[Ticket]:
if "status" not in self.request.GET:
queryset = queryset.filter(status=TicketStatus.OPEN)
return queryset

def get_ticket_filter(self) -> TicketFilter:
queryset = self.get_ticket_queryset()

return TicketFilter(
data=self.request.GET or None,
request=self.request,
Expand Down Expand Up @@ -76,7 +76,7 @@ def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
context = super().get_context_data(**kwargs)
context["ticket_queues"] = TicketQueue.objects.all()
return context


class TicketListView(LoginRequiredMixin, SingleTableMixin, FilterView):
filterset_class = TicketFilter
Expand Down Expand Up @@ -106,7 +106,7 @@ class TicketCreateView(LoginRequiredMixin, CreateView):
def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
"""The same template is used for updating tickets."""
return super().get_context_data(create=True, **kwargs)

def get_initial(self) -> dict[str, Any]:
return {
"team": get_object_or_none(Team, tla=self.request.GET.get("team")),
Expand Down
2 changes: 1 addition & 1 deletion requirements-dev.in
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ types-dj-database-url
types-setuptools

faker
freezegun
freezegun
Loading

0 comments on commit d1334cd

Please sign in to comment.