Skip to content

Commit

Permalink
Large admin.py rewrite, mostly admin UI tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
Dillon Lareau committed Feb 8, 2020
1 parent dfef776 commit 809a0ab
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 74 deletions.
212 changes: 143 additions & 69 deletions huntserver/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,27 @@
from huntserver.widgets import HtmlEditor
from django.contrib.auth.models import User, Group
from django.utils.safestring import mark_safe
from django.template.defaultfilters import truncatechars

# Register your models here.
from . import models


class UnlockableInline(admin.TabularInline):
model = models.Unlockable
extra = 1
def short_team_name(teamable_object):
return truncatechars(teamable_object.team.team_name, 50)


class ResponseInline(admin.TabularInline):
model = models.Response
extra = 1
short_team_name.short_description = "Team name"


class UnlockInline(admin.TabularInline):
model = models.Puzzle.unlocks.through
extra = 2
fk_name = 'to_puzzle'
verbose_name = "Puzzle that counts towards unlocking this puzzle"
verbose_name_plural = "Puzzles that count towards this puzzle"
class HintAdmin(admin.ModelAdmin):
list_display = [short_team_name, 'puzzle', 'request_time', 'has_been_answered']

def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "from_puzzle":
try:
parent_obj_id = request.resolver_match.args[0]
puzzle = models.Puzzle.objects.get(id=parent_obj_id)
query = models.Puzzle.objects.filter(hunt=puzzle.hunt)
kwargs["queryset"] = query.order_by('puzzle_id')
except IndexError:
pass
return super(UnlockInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
def has_been_answered(self, hint):
return hint.response != ""

has_been_answered.boolean = True
has_been_answered.short_description = "Answered?"


class HintUnlockPlanForm(forms.ModelForm):
Expand All @@ -56,39 +45,61 @@ class HintUnlockPLanInline(admin.TabularInline):
radio_fields = {"unlock_type": admin.VERTICAL}


class PuzzleAdmin(admin.ModelAdmin):
def get_object(self, request, object_id, to_field):
# Hook obj for use in formfield_for_manytomany
self.obj = super(PuzzleAdmin, self).get_object(request, object_id, to_field)
return self.obj
class HuntAdminForm(forms.ModelForm):
model = models.Hunt

def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "unlocks" and getattr(self, 'obj', None):
query = models.Puzzle.objects.filter(hunt=self.obj.hunt)
kwargs["queryset"] = query.order_by('puzzle_id')
return super(PuzzleAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)
class Meta:
fields = '__all__'
widgets = {
'template': HtmlEditor(attrs={'style': 'width: 90%; height: 400px;'}),
}

list_filter = ('hunt',)
fields = ('hunt', 'puzzle_name', 'puzzle_number', 'puzzle_id', 'is_meta',
'doesnt_count', 'is_html_puzzle', 'resource_link', 'link', 'solution_link',
'answer', 'extra_data', 'num_pages', 'num_required_to_unlock')
inlines = (UnlockInline, ResponseInline)

class HuntAdmin(admin.ModelAdmin):
form = HuntAdminForm
inlines = (HintUnlockPLanInline,)
list_display = ['hunt_name', 'team_size', 'start_date', 'is_current_hunt']


class PrepuzzleAdminForm(forms.ModelForm):
model = models.Prepuzzle
class MessageAdmin(admin.ModelAdmin):
list_display = [short_team_name, 'short_message']

def short_message(self, message):
return truncatechars(message.text, 60)

short_message.short_description = "Message"


class PersonAdmin(admin.ModelAdmin):
list_display = ['user_full_name', 'user_username', 'is_shib_acct']
search_fields = ['user__email', 'user__username', 'user__first_name', 'user__last_name']

def user_full_name(self, person):
return person.user.first_name + " " + person.user.last_name

def user_username(self, person):
return person.user.username

user_full_name.short_description = "Name"
user_username.short_description = "Username"


class PrepuzzleAdminForm(forms.ModelForm):
class Meta:
fields = '__all__'
model = models.Prepuzzle
fields = ['puzzle_name', 'released', 'hunt', 'answer', 'resource_link', 'template',
'response_string']
widgets = {
'template': HtmlEditor(attrs={'style': 'width: 90%; height: 400px;'}),
}


class PrepuzzleAdmin(admin.ModelAdmin):
form = PrepuzzleAdminForm
list_display = ['puzzle_name', 'hunt', 'released']
readonly_fields = ('puzzle_url',)

# Needed to add request to modelAdmin
def get_queryset(self, request):
qs = super(PrepuzzleAdmin, self).get_queryset(request)
self.request = request
Expand All @@ -108,6 +119,78 @@ def puzzle_url(self, obj):
puzzle_url.short_description = 'Puzzle URL: (Not editable)'


class UnlockInline(admin.TabularInline):
model = models.Puzzle.unlocks.through
extra = 2
fk_name = 'to_puzzle'
verbose_name = "Puzzle that counts towards unlocking this puzzle"
verbose_name_plural = "Puzzles that count towards this puzzle"

def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "from_puzzle":
try:
parent_obj_id = request.resolver_match.kwargs['object_id']
puzzle = models.Puzzle.objects.get(id=parent_obj_id)
query = models.Puzzle.objects.filter(hunt=puzzle.hunt)
kwargs["queryset"] = query.order_by('puzzle_id')
except IndexError:
pass
return super(UnlockInline, self).formfield_for_foreignkey(db_field, request, **kwargs)


class ResponseInline(admin.TabularInline):
model = models.Response
extra = 1


class PuzzleAdmin(admin.ModelAdmin):
def get_object(self, request, object_id, to_field):
# Hook obj for use in formfield_for_manytomany
self.obj = super(PuzzleAdmin, self).get_object(request, object_id, to_field)
return self.obj

def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "unlocks" and getattr(self, 'obj', None):
query = models.Puzzle.objects.filter(hunt=self.obj.hunt)
kwargs["queryset"] = query.order_by('puzzle_id')
return super(PuzzleAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)

list_filter = ('hunt',)
fields = ('hunt', 'puzzle_name', 'puzzle_number', 'puzzle_id', 'is_meta',
'doesnt_count', 'is_html_puzzle', 'resource_link', 'link', 'solution_link',
'answer', 'extra_data', 'num_pages', 'num_required_to_unlock')
list_display = ['combined_id', 'puzzle_name', 'hunt', 'is_meta']
list_display_links = ['combined_id', 'puzzle_name']
ordering = ['-hunt', 'puzzle_number']
inlines = (UnlockInline, ResponseInline)

def combined_id(self, puzzle):
return str(puzzle.puzzle_number) + "-" + puzzle.puzzle_id

combined_id.short_description = "ID"


class ResponseAdmin(admin.ModelAdmin):
list_display = ['__str__', 'puzzle_just_name']
ordering = ['-puzzle']

def puzzle_just_name(self, response):
return response.puzzle.puzzle_name

puzzle_just_name.short_description = "Puzzle"


class SolveAdmin(admin.ModelAdmin):
list_display = ['__str__', 'solve_time']

def solve_time(self, solve):
return solve.submission.submission_time


class SubmissionAdmin(admin.ModelAdmin):
list_display = ['submission_text', short_team_name, 'submission_time']


class TeamAdminForm(forms.ModelForm):
persons = forms.ModelMultipleChoiceField(
queryset=models.Person.objects.all(),
Expand Down Expand Up @@ -144,27 +227,17 @@ def save(self, commit=True):

class TeamAdmin(admin.ModelAdmin):
form = TeamAdminForm
list_filter = ('hunt',)


class PersonAdmin(admin.ModelAdmin):
list_display = ('__str__', 'is_shib_acct',)
search_fields = ['user__email', 'user__username', 'user__first_name', 'user__last_name']

list_display = ['short_team_name', 'location', 'hunt', 'playtester']
list_filter = ['hunt']

class HuntAdminForm(forms.ModelForm):
model = models.Hunt
def short_team_name(self, team):
return truncatechars(team.team_name, 30) + " (" + str(team.size) + ")"

class Meta:
fields = '__all__'
widgets = {
'template': HtmlEditor(attrs={'style': 'width: 90%; height: 400px;'}),
}
short_team_name.short_description = "Team name"


class HuntAdmin(admin.ModelAdmin):
form = HuntAdminForm
inlines = (HintUnlockPLanInline,)
class UnlockAdmin(admin.ModelAdmin):
list_display = ['__str__', 'time']


class UserProxyObject(User):
Expand All @@ -176,22 +249,23 @@ class Meta:


class UserProxyAdmin(admin.ModelAdmin):
list_display = ['username', 'first_name', 'last_name']
search_fields = ['email', 'username', 'first_name', 'last_name']


admin.site.unregister(User)
admin.site.unregister(Group)

admin.site.register(UserProxyObject, UserProxyAdmin)
admin.site.register(models.Hunt, HuntAdmin)
admin.site.register(models.Puzzle, PuzzleAdmin)
admin.site.register(models.Prepuzzle, PrepuzzleAdmin)
admin.site.register(models.Person, PersonAdmin)
admin.site.register(models.Team, TeamAdmin)
admin.site.register(models.Submission)
admin.site.register(models.Solve)
admin.site.register(models.Unlock)
admin.site.register(models.Message)
admin.site.register(models.Response)
admin.site.register(models.Hint, HintAdmin)
admin.site.register(models.Hunt, HuntAdmin)
admin.site.register(models.Message, MessageAdmin)
admin.site.register(models.Person, PersonAdmin)
admin.site.register(models.Prepuzzle, PrepuzzleAdmin)
admin.site.register(models.Puzzle, PuzzleAdmin)
admin.site.register(models.Response, ResponseAdmin)
admin.site.register(models.Solve, SolveAdmin)
admin.site.register(models.Submission, SubmissionAdmin)
admin.site.register(models.Team, TeamAdmin)
admin.site.register(models.Unlockable)
admin.site.register(models.Hint)
admin.site.register(models.Unlock, UnlockAdmin)
admin.site.register(UserProxyObject, UserProxyAdmin)
15 changes: 10 additions & 5 deletions huntserver/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ class Puzzle(models.Model):
help_text="Number of pages in the PDF for this puzzle. Set automatically upon download")
is_meta = models.BooleanField(
default=False,
verbose_name="Is a metapuzzle",
help_text="Is this puzzle a meta-puzzle?")
is_html_puzzle = models.BooleanField(
default=False,
Expand Down Expand Up @@ -282,6 +283,10 @@ def short_name(self):
""" Team name shortened to 30 characters for more consistent display """
return self.team_name[:30]

@property
def size(self):
return self.person_set.count()

@property
def has_waiting_messages(self):
return max(self.last_received_message - self.last_seen_message, 0)
Expand All @@ -298,7 +303,7 @@ def hints_open_for_puzzle(self, puzzle):
return False

def __str__(self):
return str(self.person_set.count()) + " (" + self.location + ") " + self.team_name
return str(self.size) + " (" + self.location + ") " + self.short_name


@python_2_unicode_compatible
Expand Down Expand Up @@ -423,7 +428,7 @@ def serialize_for_ajax(self):
return message

def __str__(self):
return self.team.team_name + " => " + self.puzzle.puzzle_name
return self.team.short_name + " => " + self.puzzle.puzzle_name


@python_2_unicode_compatible
Expand Down Expand Up @@ -452,7 +457,7 @@ def serialize_for_ajax(self):
return message

def __str__(self):
return self.team.team_name + ": " + self.puzzle.puzzle_name
return self.team.short_name + ": " + self.puzzle.puzzle_name


@python_2_unicode_compatible
Expand All @@ -472,7 +477,7 @@ class Message(models.Model):
help_text="Message send time")

def __str__(self):
return self.team.team_name + ": " + self.text
return self.team.short_name + ": " + self.text


@python_2_unicode_compatible
Expand Down Expand Up @@ -550,7 +555,7 @@ class Hint(models.Model):
help_text="Last time of modification")

def __str__(self):
return (self.team.team_name + ": " + self.puzzle.puzzle_name +
return (self.team.short_name + ": " + self.puzzle.puzzle_name +
" (" + str(self.request_time) + ")")


Expand Down

0 comments on commit 809a0ab

Please sign in to comment.