Skip to content

Commit 763b94c

Browse files
committed
Make site logo configurable in misc_config
1 parent b7cd4d1 commit 763b94c

File tree

9 files changed

+122
-3
lines changed

9 files changed

+122
-3
lines changed

dmoj/settings.py

+3
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,9 @@
630630
SUBMISSION_FILE_UPLOAD_URL_PREFIX = '/submission_file'
631631
SUBMISSION_FILE_UPLOAD_MEDIA_DIR = 'submission_file'
632632

633+
STATIC_UPLOAD_URL_PREFIX = '/static-upload'
634+
STATIC_UPLOAD_MEDIA_DIR = 'static-upload'
635+
633636
# Database
634637
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
635638

dmoj/urls.py

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from judge.views import TitledTemplateView, api, blog, comment, contests, language, license, mailgun, organization, \
1919
preview, problem, problem_manage, ranked_submission, register, stats, status, submission, tag, tasks, ticket, \
2020
two_factor, user, widgets
21+
from judge.views.misc_config import MiscConfigEdit
2122
from judge.views.problem_data import ProblemDataView, ProblemSubmissionDiff, \
2223
problem_data_file, problem_init_view
2324
from judge.views.register import ActivationView, RegistrationView
@@ -415,6 +416,8 @@ def paged_list_view(view, name):
415416
path('failure', tasks.demo_failure),
416417
path('progress', tasks.demo_progress),
417418
])),
419+
420+
path('misc_config/', MiscConfigEdit.as_view(), name='misc_config'),
418421
]
419422

420423
favicon_paths = ['apple-touch-icon-180x180.png', 'apple-touch-icon-114x114.png', 'android-chrome-72x72.png',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 3.2.23 on 2024-01-12 10:16
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('judge', '0202_import_polygon_package'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='miscconfig',
15+
name='key',
16+
field=models.CharField(max_length=30, unique=True, verbose_name='key'),
17+
),
18+
]

judge/models/interface.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717

1818
class MiscConfig(models.Model):
19-
key = models.CharField(max_length=30, verbose_name=_('key'), db_index=True)
19+
key = models.CharField(max_length=30, verbose_name=_('key'), unique=True)
2020
value = models.TextField(verbose_name=_('value'), blank=True)
2121

2222
def __str__(self):

judge/views/misc_config.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from django import forms
2+
from django.db import transaction
3+
from django.http import Http404
4+
from django.urls import reverse
5+
from django.utils.translation import gettext_lazy as _
6+
from django.views.generic import FormView
7+
8+
from judge.models import MiscConfig
9+
from judge.utils.views import TitleMixin
10+
from judge.views.widgets import static_uploader
11+
12+
13+
class MiscConfigForm(forms.Form):
14+
logo = forms.FileField(help_text='The site logo e.g. the image in the top left corner.')
15+
16+
17+
class MiscConfigEdit(TitleMixin, FormView):
18+
template_name = 'misc_config/edit.html'
19+
form_class = MiscConfigForm
20+
title = _('Site settings')
21+
22+
def get_success_url(self):
23+
return reverse('home')
24+
25+
def form_valid(self, form):
26+
with transaction.atomic():
27+
logo = form.files.get('logo', default=None)
28+
if logo is not None:
29+
logo_url = static_uploader(logo)
30+
config, _ = MiscConfig.objects.update_or_create(key='site_logo', defaults={'value': logo_url})
31+
config.save()
32+
return super().form_valid(form)
33+
34+
def dispatch(self, request, *args, **kwargs):
35+
if not request.user.is_superuser:
36+
raise Http404
37+
return super().dispatch(request, *args, **kwargs)

judge/views/widgets.py

+11
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,17 @@ def martor_image_uploader(request):
8888
return HttpResponse(data, content_type='application/json')
8989

9090

91+
def static_uploader(static_file):
92+
ext = os.path.splitext(static_file.name)[1]
93+
name = str(uuid.uuid4()) + ext
94+
default_storage.save(os.path.join(settings.STATIC_UPLOAD_MEDIA_DIR, name), static_file)
95+
url_base = getattr(settings, 'STATIC_UPLOAD_URL_PREFIX',
96+
urljoin(settings.MEDIA_URL, settings.STATIC_UPLOAD_MEDIA_DIR))
97+
if not url_base.endswith('/'):
98+
url_base += '/'
99+
return urljoin(url_base, name)
100+
101+
91102
def csrf_failure(request: HttpRequest, reason=''):
92103
# Redirect to the same page in case of CSRF failure
93104
# So that we can turn on cloudflare DDOS protection without

templates/base.html

+7
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,13 @@
269269
</ul>
270270

271271
<span id="user-links">
272+
{% if request.user.is_superuser %}
273+
<a href="{{ url('misc_config') }}" style="margin-right: 5px;">
274+
<span title="{{ _('Site settings') }}">
275+
<i class="fa fa-gear" style="color: rgb(200,200,200) ; font-size: 1.15em"></i>
276+
</span>
277+
</a>
278+
{% endif %}
272279
<a href=
273280
{% if request.resolver_match.view_name == "problem_detail" and problem %}
274281
"{{ url('new_problem_ticket', problem.code) }}"

templates/misc_config/edit.html

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{% extends "base.html" %}
2+
3+
{% block js_media %}
4+
{{ form.media.js }}
5+
{% endblock %}
6+
7+
{% block media %}
8+
{{ form.media.css }}
9+
<link rel="stylesheet" type="text/css" href="{{ static('ui_form.css') }}">
10+
<style>
11+
.hidden {
12+
display: none;
13+
}
14+
</style>
15+
{% endblock %}
16+
17+
{% block body %}
18+
<div>
19+
{% if request.user.is_staff %}
20+
<div class="alert alert-warning alert-dismissable">
21+
<a class="close">x</a>
22+
<a href="{{ url('admin:judge_miscconfig_changelist') }}">{{ _('Configure in admin panel for more options') }}</a>
23+
</div>
24+
{% endif %}
25+
<form action="" method="post" class="form-area" enctype="multipart/form-data" style="display: flex; justify-content: center; flex-direction: column;">
26+
{% if form.errors %}
27+
<p class="errornote"> {{ _('Please correct the error below.') }}</p>
28+
{% endif %}
29+
{% csrf_token %}
30+
<table class="django-as-table">{{ form.as_table() }}</table>
31+
<table>
32+
<tr><td style="float: left;">
33+
<td style="float: right;"><input type="submit" value="{{ _('Update') }}" class="button"></td></tr>
34+
</table>
35+
</form>
36+
</div>
37+
{% endblock %}
38+

templates/site-logo-fragment.html

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
{% elif logo_override_image is defined and logo_override_image %}
44
<img src="{{ logo_override_image|camo }}" alt="{{ SITE_NAME }}" height="40" style="border: none; padding-top: 4px">
55
{% else %}
6-
<img src="{{ static('icons/logo.svg') }}" alt="{{ SITE_NAME }}" width="130" height="40"
7-
onerror="this.src=&quot;{{ static('icons/logo.png') }}&quot;; this.onerror=null" style="border: none; padding-top: 4px">
6+
{% with logo_url=misc_config.site_logo|default(static('icons/logo.svg'), true) %}
7+
<img src="{{ logo_url }}" alt="{{ SITE_NAME }}" width="130" height="40"
8+
onerror="this.src=&quot;{{ logo_url }}&quot;; this.onerror=null" style="border: none; padding-top: 4px">
9+
{% endwith %}
810
{% endif %}

0 commit comments

Comments
 (0)