Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unidirectional feedback #197

Merged
merged 9 commits into from
Oct 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 2 additions & 0 deletions conf/local_settings.py.example
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ EXTERNAL_LOGINS = {
'use_smtp': False,
}
}
FEEDBACK_ENDPOINT = 'https://example.com/bot/' # or None
FEEDBACK_KEY = '1145141919811'
14 changes: 14 additions & 0 deletions conf/settings/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -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': {
Expand All @@ -39,6 +43,11 @@
'handlers': ['request'],
'propagate': False,
},
'custom': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False,
}
},
'handlers': {
'databaselog': {
Expand All @@ -52,6 +61,11 @@
'class': 'logging.StreamHandler',
'formatter': 'request',
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'simple',
}
},
}

Expand Down
14 changes: 14 additions & 0 deletions conf/settings/hackergame.py
Original file line number Diff line number Diff line change
Expand Up @@ -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': {
Expand All @@ -58,6 +62,11 @@
'class': 'logging.StreamHandler',
'formatter': 'request',
},
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'django': {
Expand All @@ -74,6 +83,11 @@
'handlers': ['request'],
'propagate': False,
},
'custom': {
'handlers': ['console'],
'level': 'INFO',
'propagate': False,
},
},
}

Expand Down
16 changes: 15 additions & 1 deletion conf/settings/hgtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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': {
Expand All @@ -58,6 +62,11 @@
'class': 'logging.StreamHandler',
'formatter': 'request',
},
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'django': {
Expand All @@ -74,6 +83,11 @@
'handlers': ['request'],
'propagate': False,
},
'custom': {
'handlers': ['console'],
'level': 'INFO',
'propagate': False,
},
},
}

Expand Down
4 changes: 2 additions & 2 deletions frontend/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
50 changes: 50 additions & 0 deletions frontend/migrations/0010_unidirectionalfeedback.py
Original file line number Diff line number Diff line change
@@ -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,
),
),
],
),
]
33 changes: 33 additions & 0 deletions frontend/migrations/0011_feedback.py
Original file line number Diff line number Diff line change
@@ -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="会被放入 <code>div</code> 的 HTML"
),
),
],
),
]
21 changes: 21 additions & 0 deletions frontend/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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='会被放入 <code>div</code> 的 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} 的反馈"
58 changes: 58 additions & 0 deletions frontend/templates/challenge_feedback.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{% extends 'base.html' %}
{% load static %}

{% block js %}
{{ block.super }}
<script src="{% static 'vue.min.js' %}"></script>
<script src="{% static 'axios.min.js' %}"></script>
<script>
axios.defaults.xsrfCookieName = 'csrftoken';
axios.defaults.xsrfHeaderName = 'X-CSRFToken';
</script>
{% endblock %}

{% block content %}

<div id="app">
<h1>提交对题目 {{challenge_name}} 的反馈</h1>
<div>{{ feedback.content|safe }}</div>
{% verbatim %}
<div v-if="!too_frequent">
{% endverbatim %}
<form method="post" class="pure-form pure-form-stacked">
<fieldset>
{% csrf_token %}
<textarea id="contents" class="pure-input-1" name="contents" rows="20" maxlength="1024" required>{{ contents }}</textarea>
<div class="pure-u-1" style="text-align: right;">
<button type="submit" class="pure-button pure-button-primary">提交!</button>
</div>
</fieldset>
</form>
{% verbatim %}
</div>
<div v-else>
<p>你对该题目上一次提交反馈在 {{ human_latest_submit() }},需要等待提交后一小时方可再次提交。</p>
</div>
</div>
{% endverbatim %}
{{ too_frequent|json_script:'too-frequent' }}
{{ latest_submit|json_script:'latest-submit' }}
<script>
app = new Vue({
el: '#app',
data: {
too_frequent: JSON.parse(document.getElementById('too-frequent').textContent),
latest_submit: JSON.parse(document.getElementById('latest-submit').textContent),
},
methods: {
human_latest_submit() {
if (!this.latest_submit) {
return ""
}
const date = new Date(this.latest_submit)
return date.toLocaleString()
}
}
});
</script>
{% endblock %}
4 changes: 4 additions & 0 deletions frontend/templates/hub.html
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ <h1>{{ opened.name }}</h1>
<input type="text" name="flag" class="pure-input-rounded" maxlength="200" autocomplete="off" :placeholder="opened.prompt">
<button type="submit" class="pure-button pure-input-rounded">提交</button>
</form>
<a :href="get_feedback_url(opened)">需要提交反馈?</a>
</div>
<div class="main-body" v-else v-html="page_content"></div>
</div>
Expand Down Expand Up @@ -259,6 +260,9 @@ <h1>{{ opened.name }}</h1>
get_subchallenge_count(challenge, flag_index) {
let count = (this.clear_count.flags.find(i => i.challenge === challenge.pk && i.flag === flag_index) || {count: 0}).count;
return count;
},
get_feedback_url(challenge) {
return `/challenge/${opened.pk}/feedback/`
}
},
updated: function () {
Expand Down
1 change: 1 addition & 0 deletions frontend/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
path('error/', views.ErrorView.as_view()),
path('data/core.json', views.CoreDataView.as_view(), name='coredata'),
path('challenge/<int:challenge_id>/', views.ChallengeURLView.as_view(), name='challenge_url'),
path('challenge/<int:challenge_id>/feedback/', views.ChallengeFeedbackURLView.as_view(), name='challenge_feedback_url'),
path('score/', views.ScoreView.as_view(), name='score'),

path('profile/ustc/', views.UstcProfileView.as_view(), name='ustcprofile'),
Expand Down
Loading