diff --git a/conf/local_settings.py.example b/conf/local_settings.py.example
index 917b6dc..506ac1b 100644
--- a/conf/local_settings.py.example
+++ b/conf/local_settings.py.example
@@ -18,3 +18,5 @@ EXTERNAL_LOGINS = {
'use_smtp': False,
}
}
+FEEDBACK_ENDPOINT = 'https://example.com/bot/' # or None
+FEEDBACK_KEY = '1145141919811'
diff --git a/conf/settings/dev.py b/conf/settings/dev.py
index d5226a0..5aa95a4 100644
--- a/conf/settings/dev.py
+++ b/conf/settings/dev.py
@@ -19,6 +19,10 @@
'request': {
'format': '%(asctime)s %(ip)s %(userid)s %(levelname)s %(message)s',
},
+ 'simple': {
+ 'format': '{levelname} {message}',
+ 'style': '{',
+ },
},
'filters': {
'add_user_info': {
@@ -39,6 +43,11 @@
'handlers': ['request'],
'propagate': False,
},
+ 'custom': {
+ 'handlers': ['console'],
+ 'level': 'DEBUG',
+ 'propagate': False,
+ }
},
'handlers': {
'databaselog': {
@@ -52,6 +61,11 @@
'class': 'logging.StreamHandler',
'formatter': 'request',
},
+ 'console': {
+ 'level': 'DEBUG',
+ 'class': 'logging.StreamHandler',
+ 'formatter': 'simple',
+ }
},
}
diff --git a/conf/settings/hackergame.py b/conf/settings/hackergame.py
index 72f8da1..fca7cbf 100644
--- a/conf/settings/hackergame.py
+++ b/conf/settings/hackergame.py
@@ -38,6 +38,10 @@
'request': {
'format': '%(asctime)s %(ip)s %(userid)s %(levelname)s %(message)s',
},
+ 'verbose': {
+ 'format': '{levelname} {asctime} [{name}] {message}',
+ 'style': '{',
+ },
},
'filters': {
'add_user_info': {
@@ -58,6 +62,11 @@
'class': 'logging.StreamHandler',
'formatter': 'request',
},
+ 'console': {
+ 'level': 'INFO',
+ 'class': 'logging.StreamHandler',
+ 'formatter': 'verbose',
+ },
},
'loggers': {
'django': {
@@ -74,6 +83,11 @@
'handlers': ['request'],
'propagate': False,
},
+ 'custom': {
+ 'handlers': ['console'],
+ 'level': 'INFO',
+ 'propagate': False,
+ },
},
}
diff --git a/conf/settings/hgtest.py b/conf/settings/hgtest.py
index 00a125d..8d3b471 100644
--- a/conf/settings/hgtest.py
+++ b/conf/settings/hgtest.py
@@ -37,7 +37,11 @@
},
'request': {
'format': '%(asctime)s %(ip)s %(userid)s %(levelname)s %(message)s',
- }
+ },
+ 'verbose': {
+ 'format': '{levelname} {asctime} [{name}] {message}',
+ 'style': '{',
+ },
},
'filters': {
'add_user_info': {
@@ -58,6 +62,11 @@
'class': 'logging.StreamHandler',
'formatter': 'request',
},
+ 'console': {
+ 'level': 'INFO',
+ 'class': 'logging.StreamHandler',
+ 'formatter': 'verbose',
+ },
},
'loggers': {
'django': {
@@ -74,6 +83,11 @@
'handlers': ['request'],
'propagate': False,
},
+ 'custom': {
+ 'handlers': ['console'],
+ 'level': 'INFO',
+ 'propagate': False,
+ },
},
}
diff --git a/frontend/admin.py b/frontend/admin.py
index 62ca49f..8cb1e60 100644
--- a/frontend/admin.py
+++ b/frontend/admin.py
@@ -9,9 +9,9 @@
from server.terms.models import Terms
from server.trigger.models import Trigger
from server.user.models import User
-from .models import Page, Account, Code, AccountLog, SpecialProfileUsedRecord, Qa, Credits
+from .models import Page, Account, Code, AccountLog, SpecialProfileUsedRecord, Qa, Credits, UnidirectionalFeedback, Feedback
-admin.site.register([Page, Account, Code, Qa, Credits, SpecialProfileUsedRecord])
+admin.site.register([Page, Account, Code, Qa, Credits, SpecialProfileUsedRecord, UnidirectionalFeedback, Feedback])
class PermissionListFilter(admin.SimpleListFilter):
diff --git a/frontend/migrations/0010_unidirectionalfeedback.py b/frontend/migrations/0010_unidirectionalfeedback.py
new file mode 100644
index 0000000..f474b3d
--- /dev/null
+++ b/frontend/migrations/0010_unidirectionalfeedback.py
@@ -0,0 +1,50 @@
+# Generated by Django 4.2.16 on 2024-10-24 15:52
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ("frontend", "0009_alter_accountlog_account"),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="UnidirectionalFeedback",
+ fields=[
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "challenge_id",
+ models.IntegerField(help_text="该反馈对应 Challenge 的 ID"),
+ ),
+ (
+ "contents",
+ models.TextField(help_text="反馈内容,最长 1024", max_length=1024),
+ ),
+ (
+ "submit_datetime",
+ models.DateTimeField(auto_now_add=True, help_text="反馈时间"),
+ ),
+ (
+ "user",
+ models.ForeignKey(
+ help_text="反馈用户",
+ on_delete=django.db.models.deletion.CASCADE,
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ ],
+ ),
+ ]
diff --git a/frontend/migrations/0011_feedback.py b/frontend/migrations/0011_feedback.py
new file mode 100644
index 0000000..4181acf
--- /dev/null
+++ b/frontend/migrations/0011_feedback.py
@@ -0,0 +1,33 @@
+# Generated by Django 4.2.16 on 2024-10-25 06:43
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("frontend", "0010_unidirectionalfeedback"),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="Feedback",
+ fields=[
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "content",
+ models.TextField(
+ blank=True, help_text="会被放入 div
的 HTML"
+ ),
+ ),
+ ],
+ ),
+ ]
diff --git a/frontend/models.py b/frontend/models.py
index 0ba56a1..17b6047 100644
--- a/frontend/models.py
+++ b/frontend/models.py
@@ -117,3 +117,24 @@ class Credits(models.Model):
@classmethod
def get(cls):
return cls.objects.get_or_create()[0]
+
+
+class Feedback(models.Model):
+ content = models.TextField(blank=True, help_text='会被放入 div
的 HTML')
+
+ @classmethod
+ def get(cls):
+ return cls.objects.get_or_create()[0]
+
+
+class UnidirectionalFeedback(models.Model):
+ """
+ User could submit feedback for a specific challenge.
+ """
+ challenge_id = models.IntegerField(help_text="该反馈对应 Challenge 的 ID")
+ user = models.ForeignKey(get_user_model(), models.CASCADE, help_text="反馈用户")
+ contents = models.TextField(max_length=1024, help_text="反馈内容,最长 1024")
+ submit_datetime = models.DateTimeField(auto_now_add=True, help_text="反馈时间")
+
+ def __str__(self) -> str:
+ return f"{self.user} 对题目 {self.challenge_id} 的反馈"
diff --git a/frontend/templates/challenge_feedback.html b/frontend/templates/challenge_feedback.html
new file mode 100644
index 0000000..0c567b4
--- /dev/null
+++ b/frontend/templates/challenge_feedback.html
@@ -0,0 +1,58 @@
+{% extends 'base.html' %}
+{% load static %}
+
+{% block js %}
+ {{ block.super }}
+
+
+
+{% endblock %}
+
+{% block content %}
+
+
你对该题目上一次提交反馈在 {{ human_latest_submit() }},需要等待提交后一小时方可再次提交。
+