aboutsummaryrefslogtreecommitdiffstats
path: root/pydis_site
diff options
context:
space:
mode:
authorGravatar Leon Sandøy <[email protected]>2019-10-12 00:07:45 +0200
committerGravatar GitHub <[email protected]>2019-10-12 00:07:45 +0200
commitf357084f15d27b2dea141eccdb86cde61c495ce6 (patch)
treed4a7cef40dcefcb4f3873e159127ee1b310af7d1 /pydis_site
parentUpdate favicons (rounded corners, other improvements) (diff)
parentMerge pull request #280 from python-discord/fix-home-responsive (diff)
Merge branch 'master' into favicons
Diffstat (limited to 'pydis_site')
-rw-r--r--pydis_site/apps/api/admin.py55
-rw-r--r--pydis_site/apps/api/migrations/0044_migrate_nominations_from_infraction_to_nomination_model.py64
-rw-r--r--pydis_site/apps/api/migrations/0045_add_plural_name_for_log_entry.py17
-rw-r--r--pydis_site/apps/api/models/bot/nomination.py5
-rw-r--r--pydis_site/apps/api/models/log_entry.py5
-rw-r--r--pydis_site/apps/api/tests/test_models.py39
-rw-r--r--pydis_site/static/css/home/index.css19
-rw-r--r--pydis_site/templates/home/index.html49
8 files changed, 203 insertions, 50 deletions
diff --git a/pydis_site/apps/api/admin.py b/pydis_site/apps/api/admin.py
index c3784317..059f52eb 100644
--- a/pydis_site/apps/api/admin.py
+++ b/pydis_site/apps/api/admin.py
@@ -1,18 +1,63 @@
+from typing import Optional
+
from django.contrib import admin
+from django.http import HttpRequest
from .models import (
- BotSetting, DeletedMessage,
- DocumentationLink, Infraction,
- MessageDeletionContext, Nomination,
- OffTopicChannelName, Role,
- Tag, User
+ BotSetting,
+ DeletedMessage,
+ DocumentationLink,
+ Infraction,
+ LogEntry,
+ MessageDeletionContext,
+ Nomination,
+ OffTopicChannelName,
+ Role,
+ Tag,
+ User
)
+class LogEntryAdmin(admin.ModelAdmin):
+ """Allows viewing logs in the Django Admin without allowing edits."""
+
+ actions = None
+ list_display = ('timestamp', 'application', 'level', 'message')
+ fieldsets = (
+ ('Overview', {'fields': ('timestamp', 'application', 'logger_name')}),
+ ('Metadata', {'fields': ('level', 'module', 'line')}),
+ ('Contents', {'fields': ('message',)})
+ )
+ list_filter = ('application', 'level', 'timestamp')
+ search_fields = ('message',)
+ readonly_fields = (
+ 'application',
+ 'logger_name',
+ 'timestamp',
+ 'level',
+ 'module',
+ 'line',
+ 'message'
+ )
+
+ def has_add_permission(self, request: HttpRequest) -> bool:
+ """Deny manual LogEntry creation."""
+ return False
+
+ def has_delete_permission(
+ self,
+ request: HttpRequest,
+ obj: Optional[LogEntry] = None
+ ) -> bool:
+ """Deny LogEntry deletion."""
+ return False
+
+
admin.site.register(BotSetting)
admin.site.register(DeletedMessage)
admin.site.register(DocumentationLink)
admin.site.register(Infraction)
+admin.site.register(LogEntry, LogEntryAdmin)
admin.site.register(MessageDeletionContext)
admin.site.register(Nomination)
admin.site.register(OffTopicChannelName)
diff --git a/pydis_site/apps/api/migrations/0044_migrate_nominations_from_infraction_to_nomination_model.py b/pydis_site/apps/api/migrations/0044_migrate_nominations_from_infraction_to_nomination_model.py
new file mode 100644
index 00000000..a56450c0
--- /dev/null
+++ b/pydis_site/apps/api/migrations/0044_migrate_nominations_from_infraction_to_nomination_model.py
@@ -0,0 +1,64 @@
+# Generated by Django 2.2.5 on 2019-09-30 12:15
+import logging
+
+from django.db import migrations
+from django.db.models import Q
+
+log = logging.getLogger('nomination_migration')
+
+
+def migrate_nominations_to_new_model(apps, schema_editor):
+ """
+ Migrations nominations from the infraction model to the nomination model.
+
+ This migration works by replaying the nomination history in chronological order, adding and
+ ending nominations as we've recorded them.
+ """
+ Infraction = apps.get_model('api', 'Infraction')
+ Nomination = apps.get_model('api', 'Nomination')
+
+ all_nominations = (
+ Q(reason__startswith="Helper nomination:") | Q(reason__startswith="Unwatched (talent-pool):")
+ )
+
+ for infraction in Infraction.objects.filter(all_nominations).order_by('inserted_at'):
+ if infraction.reason.startswith("Helper nomination:"):
+ if Nomination.objects.filter(user=infraction.user, active=True).exists():
+ log.error(
+ f"User `{infraction.user.id}` already has an active nomination, aborting."
+ )
+ continue
+ nomination = Nomination(
+ user=infraction.user,
+ inserted_at=infraction.inserted_at,
+ reason=infraction.reason[19:], # Strip "Helper nomination: " prefix
+ actor=infraction.actor,
+ active=True,
+ )
+ nomination.save()
+ infraction.delete()
+ elif infraction.reason.startswith("Unwatched (talent-pool):"):
+ if not Nomination.objects.filter(user=infraction.user, active=True).exists():
+ log.error(
+ f"User `{infraction.user.id}` has no active nomination, can't end it!"
+ )
+ continue
+ nomination = Nomination.objects.get(user=infraction.user, active=True)
+ nomination.end_reason = infraction.reason[25:] # Strip "Unwatched (talent-pool):"
+ nomination.ended_at = infraction.inserted_at
+ nomination.active = False
+ nomination.save()
+ infraction.delete()
+ else:
+ log.error(f"I don't understand this infraction: {infraction}")
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0043_infraction_hidden_warnings_to_notes'),
+ ]
+
+ operations = [
+ migrations.RunPython(migrate_nominations_to_new_model),
+ ]
diff --git a/pydis_site/apps/api/migrations/0045_add_plural_name_for_log_entry.py b/pydis_site/apps/api/migrations/0045_add_plural_name_for_log_entry.py
new file mode 100644
index 00000000..6b9933d8
--- /dev/null
+++ b/pydis_site/apps/api/migrations/0045_add_plural_name_for_log_entry.py
@@ -0,0 +1,17 @@
+# Generated by Django 2.2.3 on 2019-10-11 17:48
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0044_migrate_nominations_from_infraction_to_nomination_model'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='logentry',
+ options={'verbose_name_plural': 'Log entries'},
+ ),
+ ]
diff --git a/pydis_site/apps/api/models/bot/nomination.py b/pydis_site/apps/api/models/bot/nomination.py
index 8a8f4d36..cd9951aa 100644
--- a/pydis_site/apps/api/models/bot/nomination.py
+++ b/pydis_site/apps/api/models/bot/nomination.py
@@ -39,3 +39,8 @@ class Nomination(ModelReprMixin, models.Model):
help_text="When the nomination was ended.",
null=True
)
+
+ def __str__(self):
+ """Representation that makes the target and state of the nomination immediately evident."""
+ status = "active" if self.active else "ended"
+ return f"Nomination of {self.user} ({status})"
diff --git a/pydis_site/apps/api/models/log_entry.py b/pydis_site/apps/api/models/log_entry.py
index acd7953a..488af48e 100644
--- a/pydis_site/apps/api/models/log_entry.py
+++ b/pydis_site/apps/api/models/log_entry.py
@@ -48,3 +48,8 @@ class LogEntry(ModelReprMixin, models.Model):
message = models.TextField(
help_text="The textual content of the log line."
)
+
+ class Meta:
+ """Customizes the default generated plural name to valid English."""
+
+ verbose_name_plural = 'Log entries'
diff --git a/pydis_site/apps/api/tests/test_models.py b/pydis_site/apps/api/tests/test_models.py
index 2120b056..bce76942 100644
--- a/pydis_site/apps/api/tests/test_models.py
+++ b/pydis_site/apps/api/tests/test_models.py
@@ -1,13 +1,21 @@
-from datetime import datetime as dt, timezone
+from datetime import datetime as dt
from django.test import SimpleTestCase
+from django.utils import timezone
from ..models import (
- DeletedMessage, DocumentationLink,
- Infraction, Message,
- MessageDeletionContext, ModelReprMixin,
- OffTopicChannelName, Reminder,
- Role, Tag, User
+ DeletedMessage,
+ DocumentationLink,
+ Infraction,
+ Message,
+ MessageDeletionContext,
+ ModelReprMixin,
+ Nomination,
+ OffTopicChannelName,
+ Reminder,
+ Role,
+ Tag,
+ User
)
@@ -27,6 +35,19 @@ class ReprMixinTests(SimpleTestCase):
class StringDunderMethodTests(SimpleTestCase):
def setUp(self):
+ self.nomination = Nomination(
+ id=123,
+ actor=User(
+ id=9876, name='Mr. Hemlock',
+ discriminator=6666, avatar_hash=None
+ ),
+ user=User(
+ id=9876, name="Hemlock's Cat",
+ discriminator=7777, avatar_hash=None
+ ),
+ reason="He purrrrs like the best!",
+ )
+
self.objects = (
DeletedMessage(
id=45,
@@ -102,3 +123,9 @@ class StringDunderMethodTests(SimpleTestCase):
def test_returns_string(self):
for instance in self.objects:
self.assertIsInstance(str(instance), str)
+
+ def test_nomination_str_representation(self):
+ self.assertEqual(
+ "Nomination of Hemlock's Cat#7777 (active)",
+ str(self.nomination)
+ )
diff --git a/pydis_site/static/css/home/index.css b/pydis_site/static/css/home/index.css
index a90a60d7..4c36031b 100644
--- a/pydis_site/static/css/home/index.css
+++ b/pydis_site/static/css/home/index.css
@@ -71,15 +71,6 @@ span.repo-language-dot.javascript {
}
@media screen and (min-width: 1088px) {
- .column.is-half, .column.is-half-tablet {
- flex: none;
- width: 50%;
- }
-
- .columns:not(.is-desktop) {
- display: flex;
- }
-
.video-container iframe {
height: calc(42vw * 0.5625);
max-height: 371px;
@@ -88,18 +79,10 @@ span.repo-language-dot.javascript {
}
@media screen and (max-width: 1087px) {
- .column.is-half, .column.is-half-tablet {
- flex: none;
- width: 100%;
- }
-
- .columns:not(.is-desktop) {
- display: block;
- }
-
.video-container iframe {
height: calc(92vw * 0.5625);
max-height: none;
max-width: none;
}
}
+
diff --git a/pydis_site/templates/home/index.html b/pydis_site/templates/home/index.html
index 205e92ff..0fa2f67c 100644
--- a/pydis_site/templates/home/index.html
+++ b/pydis_site/templates/home/index.html
@@ -15,32 +15,30 @@
<div class="container is-spaced">
<h1 class="is-size-1">Who are we?</h1>
<br>
- <div class="columns">
- <div class="column is-half">
+ <div class="columns is-desktop">
+ <div class="column is-half-desktop">
<p>
We're a large community focused around the Python programming language.
- We believe anyone can learn programming, and are very dedicated to helping
- novice developers take their first steps into the world of code. We also
+ We believe anyone can learn to code, and are very dedicated to helping
+ novice developers take their first steps into the world of programming. We also
attract a lot of expert developers who are seeking friendships, collaborators,
- or looking to hone their craft by teaching and getting involved in the community.
-
- <br/><br/>
-
- We organise regular community events like code jams, open source hackathons,
- seasonal events and community challenges. Through our sponsorships and with
- help from donations, we are even able to award prizes to the winners of our events.
-
- <br/><br/>
-
+ and who wish to hone their craft by teaching and getting involved in the community.
+ </p>
+ <p>
+ We organise regular community events such as code jams, open-source hackathons,
+ seasonal events, and community challenges. Through our sponsorships and donations,
+ many of our events even have prizes to win!
+ </p>
+ <p>
You can find help with most Python-related problems in one of our help channels.
- Our staff of nearly 50 dedicated expert Helpers are available around the clock
+ Our staff of over 50 dedicated expert Helpers are available around the clock
in every timezone. Whether you're looking to learn the language or working on a
complex project, we've got someone who can help you if you get stuck.
</p>
</div>
{# Intro video #}
- <div class="column is-half video-container">
+ <div class="column is-half-desktop video-container">
<iframe src="https://www.youtube.com/embed/DIBXg8Qh7bA" frameborder="0"
allow="accelerometer; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
@@ -50,11 +48,11 @@
{# Projects #}
<h1 class="is-size-1">Projects</h1>
<br>
- <div class="columns is-multiline">
+ <div class="columns is-multiline is-tablet">
{# Display projects from HomeView.repos #}
{% for repo in repo_data %}
- <div class="column is-one-third">
+ <div class="column is-one-third-desktop is-half-tablet">
<div class="card has-equal-height github-card">
<div class="card-content">
<div class="repo-headline">
@@ -84,11 +82,20 @@
<h1 class="title is-6 has-text-grey">
Sponsors
</h1>
- <a href="https://linode.com"><img src="{% static "images/sponsors/linode.png" %}" alt="Linode"/></a>
- <a href="https://jetbrains.com"><img src="{% static "images/sponsors/jetbrains.png" %}" alt="JetBrains"/></a>
- <a href="https://adafruit.com"><img src="{% static "images/sponsors/adafruit.png" %}" alt="Adafruit"/></a>
+ <div class="columns is-mobile is-multiline">
+ <a href="https://linode.com" class="column is-narrow">
+ <img src="{% static "images/sponsors/linode.png" %}" alt="Linode"/>
+ </a>
+ <a href="https://jetbrains.com" class="column is-narrow">
+ <img src="{% static "images/sponsors/jetbrains.png" %}" alt="JetBrains"/>
+ </a>
+ <a href="https://adafruit.com" class="column is-narrow">
+ <img src="{% static "images/sponsors/adafruit.png" %}" alt="Adafruit"/>
+ </a>
+ </div>
</div>
</div>
</section>
{% endblock %}
+