Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ help:
# Local development
# =================

db:
docker compose up -d

server:
$(DEV_CMD) runserver 0.0.0.0:4672

Expand Down
10 changes: 10 additions & 0 deletions intbot/core/bot/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,16 @@ async def poll_database():
print("Channel does not exist!")


@bot.command()
async def until(ctx):
"""
Returns how much time left until the conference
"""
delta = settings.CONFERENCE_START - timezone.now()

await ctx.send(f"{delta.days} days left until the conference")


def run_bot():
bot_token = settings.DISCORD_BOT_TOKEN
bot.run(bot_token)
9 changes: 9 additions & 0 deletions intbot/core/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.conf import settings
from django.template.response import TemplateResponse
from django.utils import timezone


def days_until(request):
delta = settings.CONFERENCE_START - timezone.now()

return TemplateResponse(request, "days_until.html", {"days_until": delta.days})
10 changes: 8 additions & 2 deletions intbot/intbot/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@

import os
import warnings
from typing import Any
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
Expand Down Expand Up @@ -52,7 +53,9 @@
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"DIRS": [
BASE_DIR / "templates",
],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
Expand Down Expand Up @@ -117,6 +120,9 @@
TASKS: dict[str, Any]


CONFERENCE_START = datetime(2025, 7, 14, tzinfo=timezone.utc)


# There are bunch of settings that we can skip on dev/testing environments if
# not used - that should be always present on prod/staging deployments.
# Instead of repeating them per-env below, they go here.
Expand Down
5 changes: 4 additions & 1 deletion intbot/intbot/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@
internal_webhook_endpoint,
zammad_webhook_endpoint,
)
from core.views import days_until
from django.contrib import admin
from django.urls import path

urlpatterns = [
path("admin/", admin.site.urls),
path("", index),
# Internal Webhooks
# Webhooks
path("webhook/internal/", internal_webhook_endpoint),
path("webhook/github/", github_webhook_endpoint),
path("webhook/zammad/", zammad_webhook_endpoint),
# Public Pages
path("days-until/", days_until),
]
9 changes: 9 additions & 0 deletions intbot/templates/days_until.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html>
<body>
<style type="text/css">
body { background-color: #f5e5d6; color: #151f38; font-family: sans-serif;}
h1 { font-size: 3em; text-align: center; margin-top: 3em; }
</style>
<h1>{{ days_until }} days until the conference</h1>
</body>
</html>
15 changes: 13 additions & 2 deletions intbot/tests/test_bot/test_main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from unittest.mock import AsyncMock, patch
import discord

import discord
import pytest
from asgiref.sync import sync_to_async
from core.bot.main import ping, poll_database, qlen, source, version, wiki, close
from core.bot.main import close, ping, poll_database, qlen, source, until, version, wiki
from core.models import DiscordMessage
from django.utils import timezone
from freezegun import freeze_time


@pytest.mark.asyncio
Expand Down Expand Up @@ -189,3 +190,13 @@ async def test_polling_messages_sends_message_if_not_sent_and_sets_sent_at():
assert dm.sent_at is not None
end = timezone.now()
assert start < dm.sent_at < end


@pytest.mark.asyncio
@freeze_time("2025-04-05")
async def test_until():
ctx = AsyncMock()

await until(ctx)

ctx.send.assert_called_once_with("100 days left until the conference")
8 changes: 8 additions & 0 deletions intbot/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from pytest_django.asserts import assertTemplateUsed


def test_days_until_view(client):
response = client.get("/days-until/")

assert response.status_code == 200
assertTemplateUsed(response, "days_until.html")
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ dependencies = [
"pytest-socket>=0.7.0",
"respx>=0.22.0",
"pydantic>=2.10.6",
"freezegun>=1.5.1",
]

[tool.pytest.ini_options]
Expand Down
35 changes: 35 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.