From 04553f9ff0c481903e77f5572fac32f0540994fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Thu, 21 May 2020 22:27:53 +0800 Subject: [PATCH 01/30] Initialize setting review / proposal stage page --- src/locale/zh_Hant/LC_MESSAGES/django.po | 6 ++ src/static/css/components/_texts.scss | 4 + src/static/css/components/_toggle.scss | 44 +++++++++++ src/static/css/main.scss | 1 + .../default/_includes/dashboard_tablist.html | 6 ++ .../default/reviews/review_change.html | 76 +++++++++++++++++++ src/users/models.py | 3 + src/users/urls.py | 1 + src/users/views.py | 2 + 9 files changed, 143 insertions(+) create mode 100644 src/static/css/components/_toggle.scss create mode 100644 src/templates/default/reviews/review_change.html diff --git a/src/locale/zh_Hant/LC_MESSAGES/django.po b/src/locale/zh_Hant/LC_MESSAGES/django.po index a1e05ee09..16a75e2e9 100644 --- a/src/locale/zh_Hant/LC_MESSAGES/django.po +++ b/src/locale/zh_Hant/LC_MESSAGES/django.po @@ -1516,6 +1516,12 @@ msgstr "更改密碼" msgid "Reviews" msgstr "審查" +#: templates/default/_includes/dashboard_tablist.html:28 +#: templates/default/reviews/review_change.html:12 +#: templates/default/reviews/review_change.html:18 +msgid "Change Review" +msgstr "更改審查設定" + #: templates/default/_includes/nav/dashboard_nav.html:10 msgid "Log out" msgstr "登出" diff --git a/src/static/css/components/_texts.scss b/src/static/css/components/_texts.scss index 659429f2c..e67e71acd 100644 --- a/src/static/css/components/_texts.scss +++ b/src/static/css/components/_texts.scss @@ -8,3 +8,7 @@ .text-emphasize { @include roboto-medium(); } + +.input-customized-size input{ + width: 16.2em; +} \ No newline at end of file diff --git a/src/static/css/components/_toggle.scss b/src/static/css/components/_toggle.scss new file mode 100644 index 000000000..914de8201 --- /dev/null +++ b/src/static/css/components/_toggle.scss @@ -0,0 +1,44 @@ +.material-switch > input[type="checkbox"] { + display: none; +} + +.material-switch > label { + cursor: pointer; + height: 0px; + position: relative; + width: 40px; +} + +.material-switch > label::before { + background: rgb(0, 0, 0); + box-shadow: inset 0px 0px 10px rgba(0, 0, 0, 0.5); + border-radius: 8px; + content: ''; + height: 16px; + margin-top: -8px; + position:absolute; + opacity: 0.3; + transition: all 0.4s ease-in-out; + width: 40px; +} +.material-switch > label::after { + background: rgb(255, 255, 255); + border-radius: 16px; + box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3); + content: ''; + height: 24px; + left: -4px; + margin-top: -8px; + position: absolute; + top: -4px; + transition: all 0.3s ease-in-out; + width: 24px; +} +.material-switch > input[type="checkbox"]:checked + label::before { + background: inherit; + opacity: 0.5; +} +.material-switch > input[type="checkbox"]:checked + label::after { + background: inherit; + left: 20px; +} \ No newline at end of file diff --git a/src/static/css/main.scss b/src/static/css/main.scss index 962ffb4d4..ee36a5e16 100644 --- a/src/static/css/main.scss +++ b/src/static/css/main.scss @@ -20,6 +20,7 @@ @import "components/tables"; @import "components/texts"; @import "components/lists"; +@import "components/toggle"; // Pages @import "pages/proposals"; diff --git a/src/templates/default/_includes/dashboard_tablist.html b/src/templates/default/_includes/dashboard_tablist.html index 05154e393..a9f0ccb5a 100644 --- a/src/templates/default/_includes/dashboard_tablist.html +++ b/src/templates/default/_includes/dashboard_tablist.html @@ -22,4 +22,10 @@ {% endif %} {% endif %} + + {% if user.is_admin %} +
  • + {% trans 'Change Review' %} +
  • + {% endif %} diff --git a/src/templates/default/reviews/review_change.html b/src/templates/default/reviews/review_change.html new file mode 100644 index 000000000..9c5b67bee --- /dev/null +++ b/src/templates/default/reviews/review_change.html @@ -0,0 +1,76 @@ +{% extends 'dashboard_base.html' %} + +{% load i18n crispy_forms_tags %} + +{% block dashboard_tablist %} +{% include '_includes/dashboard_tablist.html' with active='admin' %} +{% endblock dashboard_tablist %} + +{% block main-content %} + +

    + {% trans 'Change Review' %} +

    + +
    +
    +
    +
    {% trans 'Change Review' %}
    +
      +
    • + pycontw-2020.proposals.creatable +
      + + +
      +
    • +
    • + pycontw-2020.proposals.editable +
      + + +
      +
    • +
    • + pycontw-2020.proposals.withdrawable +
      + + +
      +
    • +
    • + pycontw-2020.reviews.visible.to.submitters +
      + + +
      +
    • +
    • + pycontw-2020.reviews.stage +
      + +
      +
    • +
    • + pycontw-2020.proposals.disable.after +
      + +
      +
    • +
    +
    + +
    + {% csrf_token %} +
    + {{ form|crispy }} + +
    +
    +
    + + +{% endblock main-content %} diff --git a/src/users/models.py b/src/users/models.py index 3097900c4..a6f8ee146 100644 --- a/src/users/models.py +++ b/src/users/models.py @@ -246,6 +246,9 @@ def is_valid_speaker(self): def is_reviewer(self): return self.has_perm('reviews.add_review') + def is_admin(self): + return self.is_superuser + @property def cospeaking_info_set(self): return self.additionalspeaker_set.filter( diff --git a/src/users/urls.py b/src/users/urls.py index f71dd74ec..e6f9033a3 100644 --- a/src/users/urls.py +++ b/src/users/urls.py @@ -30,5 +30,6 @@ url(r'^agreement/$', views.coc_agree, name='coc_agreement'), + url(r'^review-change/$', views.review_change, name='review_change'), ] diff --git a/src/users/views.py b/src/users/views.py index 24415ac66..4b9ac95de 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -193,6 +193,8 @@ def get_context_data(self, **kwargs): context.update(**reviews_state()._asdict()) return context +def review_change(request): + return render(request, 'reviews/review_change.html') login = auth_views.LoginView.as_view(authentication_form=AuthenticationForm) logout = auth_views.LogoutView.as_view() From f195f71f386f40eb4daacac65ec8f730b981d3cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Sat, 18 Jul 2020 16:30:40 +0800 Subject: [PATCH 02/30] Alice fixup with love --- src/proposals/templatetags/proposals.py | 7 +- src/static/css/components/_buttons.scss | 17 ++ src/static/css/components/_texts.scss | 3 +- src/static/css/components/_toggle.scss | 3 + .../css/vendors/bootstrap/_buttons.scss | 3 +- src/static/js/reviews/review_change.js | 74 ++++++++ .../default/_includes/dashboard_tablist.html | 2 +- .../default/reviews/review_change.html | 166 ++++++++++++------ src/users/models.py | 3 - src/users/views.py | 30 ++++ 10 files changed, 243 insertions(+), 65 deletions(-) create mode 100644 src/static/js/reviews/review_change.js diff --git a/src/proposals/templatetags/proposals.py b/src/proposals/templatetags/proposals.py index b8a245e88..dedb8990b 100644 --- a/src/proposals/templatetags/proposals.py +++ b/src/proposals/templatetags/proposals.py @@ -1,5 +1,5 @@ from django.template import Library - +from django.conf import settings from proposals.utils import SEP_DEFAULT, SEP_LAST, format_names register = Library() @@ -10,3 +10,8 @@ def speaker_names_display( proposal, sep_default=SEP_DEFAULT, sep_last=SEP_LAST): names = [info.user.speaker_name for info in proposal.speakers] return format_names(names, sep_default=sep_default, sep_last=sep_last) + + +@register.filter +def configuration_switch(value): + return settings.CONFERENCE_DEFAULT_SLUG + value \ No newline at end of file diff --git a/src/static/css/components/_buttons.scss b/src/static/css/components/_buttons.scss index c7240dbd7..0ee29b276 100644 --- a/src/static/css/components/_buttons.scss +++ b/src/static/css/components/_buttons.scss @@ -10,6 +10,10 @@ @include button-variant($btn-natural-color, $btn-natural-bg, $btn-natural-border); } +.btn-natural-noborder { + @include button-variant($btn-natural-color, $btn-natural-bg, $btn-natural-border); +} + .btn-action{ @include button-variant($btn-action-color, $btn-action-bg, $btn-action-border); } @@ -40,6 +44,19 @@ } } +.btn-natural-noborder { + &:hover { + background-color: $btn-natural-hover-bg; + } + &, + &:focus, + &:active { + outline: none; + border-color: transparent; + } + margin-bottom: 20px; +} + .btn-natural.btn-withdraw { &, &:hover, diff --git a/src/static/css/components/_texts.scss b/src/static/css/components/_texts.scss index e67e71acd..cf494cfb1 100644 --- a/src/static/css/components/_texts.scss +++ b/src/static/css/components/_texts.scss @@ -11,4 +11,5 @@ .input-customized-size input{ width: 16.2em; -} \ No newline at end of file +} + diff --git a/src/static/css/components/_toggle.scss b/src/static/css/components/_toggle.scss index 914de8201..f5d121e78 100644 --- a/src/static/css/components/_toggle.scss +++ b/src/static/css/components/_toggle.scss @@ -21,6 +21,7 @@ transition: all 0.4s ease-in-out; width: 40px; } + .material-switch > label::after { background: rgb(255, 255, 255); border-radius: 16px; @@ -34,10 +35,12 @@ transition: all 0.3s ease-in-out; width: 24px; } + .material-switch > input[type="checkbox"]:checked + label::before { background: inherit; opacity: 0.5; } + .material-switch > input[type="checkbox"]:checked + label::after { background: inherit; left: 20px; diff --git a/src/static/css/vendors/bootstrap/_buttons.scss b/src/static/css/vendors/bootstrap/_buttons.scss index 6452b709f..da8828aba 100755 --- a/src/static/css/vendors/bootstrap/_buttons.scss +++ b/src/static/css/vendors/bootstrap/_buttons.scss @@ -110,6 +110,7 @@ a.btn { &:hover, &:focus, &:active { + outline: none; border-color: transparent; } &:hover, @@ -128,7 +129,6 @@ a.btn { } } - // Button Sizes // -------------------------------------------------- @@ -166,3 +166,4 @@ input[type="button"] { width: 100%; } } + diff --git a/src/static/js/reviews/review_change.js b/src/static/js/reviews/review_change.js new file mode 100644 index 000000000..e77fe4b27 --- /dev/null +++ b/src/static/js/reviews/review_change.js @@ -0,0 +1,74 @@ + +var proposals_creatable = document.getElementById("proposals.creatable"); +var proposals_editable = document.getElementById("proposals.editable"); +var proposals_withdrawable = document.getElementById("proposals.withdrawable"); +var reviews_stage = document.getElementById("reviews.stage"); +var reviews_visible_to_submitters = document.getElementById("reviews.visible.to.submitters"); + +$('.hotkey').click(function () { + if ($(this).val() == "Call for Proposals") { + Call_for_Proposals(); + } + else if ($(this).val() == "First Round Review") { + First_Round_Review() + } + else if ($(this).val() == "Modification Stage") { + Modification_Stage() + } + else if ($(this).val() == "Second Round Review") { + Second_Round_Review() + } + else if ($(this).val() == "Internal Decision") { + Internal_Decision() + } + else { + Announcement_of_Acceptance() + } + + /* + Proposal Review Stage Setting + Reference : https://github.com/pycontw/pycon.tw/blob/master/src/reviews/README.md + */ + function Call_for_Proposals(){ + proposals_creatable.checked = true; + proposals_editable.checked = true; + proposals_withdrawable.checked = true; + reviews_stage.value = "0"; + reviews_visible_to_submitters.checked = false; + } + function First_Round_Review() { + proposals_creatable.checked = false; + proposals_editable.checked = false; + proposals_withdrawable.checked = false; + reviews_stage.value = "0"; + reviews_visible_to_submitters.checked = false; + } + function Modification_Stage() { + proposals_creatable.checked = false; + proposals_editable.checked = true; + proposals_withdrawable.checked = false; + reviews_stage.value = "0"; + reviews_visible_to_submitters.checked = true; + } + function Second_Round_Review() { + proposals_creatable.checked = false; + proposals_editable.checked = false; + proposals_withdrawable.checked = false; + reviews_stage.value = "2"; + reviews_visible_to_submitters.checked = false; + } + function Internal_Decision() { + proposals_creatable.checked = false; + proposals_editable.checked = false; + proposals_withdrawable.checked = false; + reviews_stage.value = "0"; + reviews_visible_to_submitters.checked = false; + } + function Announcement_of_Acceptance() { + proposals_creatable.checked = false; + proposals_editable.checked = true; + proposals_withdrawable.checked = false; + reviews_stage.value = "0"; + reviews_visible_to_submitters.checked = true; + } +}); \ No newline at end of file diff --git a/src/templates/default/_includes/dashboard_tablist.html b/src/templates/default/_includes/dashboard_tablist.html index a9f0ccb5a..a15e9afe7 100644 --- a/src/templates/default/_includes/dashboard_tablist.html +++ b/src/templates/default/_includes/dashboard_tablist.html @@ -23,7 +23,7 @@ {% endif %} - {% if user.is_admin %} + {% if user.is_superuser %}
  • {% trans 'Change Review' %}
  • diff --git a/src/templates/default/reviews/review_change.html b/src/templates/default/reviews/review_change.html index 9c5b67bee..bdbd4fa74 100644 --- a/src/templates/default/reviews/review_change.html +++ b/src/templates/default/reviews/review_change.html @@ -1,6 +1,8 @@ {% extends 'dashboard_base.html' %} -{% load i18n crispy_forms_tags %} +{% load i18n static %} +{% load proposals %} +{% load compress crispy_forms_tags %} {% block dashboard_tablist %} {% include '_includes/dashboard_tablist.html' with active='admin' %} @@ -12,65 +14,113 @@

    {% trans 'Change Review' %}

    -
    -
    -
    -
    {% trans 'Change Review' %}
    -
      -
    • - pycontw-2020.proposals.creatable -
      - - -
      -
    • -
    • - pycontw-2020.proposals.editable -
      - - -
      -
    • -
    • - pycontw-2020.proposals.withdrawable -
      - - -
      -
    • -
    • - pycontw-2020.reviews.visible.to.submitters -
      - - -
      -
    • -
    • - pycontw-2020.reviews.stage -
      - -
      -
    • -
    • - pycontw-2020.proposals.disable.after -
      - -
      -
    • -
    -
    +
    + +
    + + + + + + +
    + +
    +
    + {% csrf_token %} +
    +
    {% trans 'Change Review' %}
    +
      +
    • + {{ ".proposals.creatable"|configuration_switch }} +
      + + + +
      +
    • +
    • + {{ ".proposals.editable"|configuration_switch }} +
      + + + +
      +
    • +
    • + {{ ".proposals.withdrawable"|configuration_switch }} +
      + + + +
      +
    • +
    • + {{ ".reviews.visible.to.submitters"|configuration_switch }} +
      + + + +
      +
    • +
    • + {{ ".reviews.stage"|configuration_switch }} +
      + +
      +
    • +
    • + {{ ".proposals.disable.after"|configuration_switch }} +
      + +
      +
    • +
    • + timezone (non-required) +
      + +
      +
    • +
    • + comment (non-required) +
      + +
      +
    • +
    +
    - - {% csrf_token %} -
    - {{ form|crispy }} - -
    +
    + {{ form|crispy }} + +
    +
    - {% endblock main-content %} + +{% block extra_js %} + +{% compress js %} + +{% endcompress %} +{% endblock extra_js %} \ No newline at end of file diff --git a/src/users/models.py b/src/users/models.py index a6f8ee146..3097900c4 100644 --- a/src/users/models.py +++ b/src/users/models.py @@ -246,9 +246,6 @@ def is_valid_speaker(self): def is_reviewer(self): return self.has_perm('reviews.add_review') - def is_admin(self): - return self.is_superuser - @property def cospeaking_info_set(self): return self.additionalspeaker_set.filter( diff --git a/src/users/views.py b/src/users/views.py index 4b9ac95de..78428b24e 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -25,6 +25,14 @@ UserProfileUpdateForm, ) from .models import CocRecord +from reviews.context import proposals_state, reviews_state +from registry.helper import reg + +from lxml import etree +import lxml.html + +from pytz import timezone +from datetime import datetime, timedelta User = auth.get_user_model() @@ -194,6 +202,28 @@ def get_context_data(self, **kwargs): return context def review_change(request): + if request.method == 'POST': + + CONFERENCE_DEFAULT_SLUG = settings.CONFERENCE_DEFAULT_SLUG + TIME_ZONE = settings.TIME_ZONE + + fmt = '%Y-%m-%d %H:%M:%S%z' + date_time_obj = datetime.strptime( + request.POST['proposals.disable.after'], '%Y-%m-%dT%H:%M:%S') + loc_dt = timezone(TIME_ZONE).localize(date_time_obj) + messages.info(request, 'Your setting has been changed successfully at ' + str(datetime.now())) + + reg[CONFERENCE_DEFAULT_SLUG + + '.proposals.creatable'] = request.POST['proposals.creatable'] + reg[CONFERENCE_DEFAULT_SLUG + + '.proposals.editable'] = request.POST['proposals.editable'] + reg[CONFERENCE_DEFAULT_SLUG + '.proposals.withdrawable'] = request.POST[ + 'proposals.withdrawable'] + reg[CONFERENCE_DEFAULT_SLUG + '.reviews.visible.to.submitters'] = request.POST[ + 'reviews.visible.to.submitters'] + reg[CONFERENCE_DEFAULT_SLUG + '.reviews.stage'] = int(request.POST['reviews.stage']) + reg[CONFERENCE_DEFAULT_SLUG + '.proposals.disable.after'] = loc_dt + return render(request, 'reviews/review_change.html') login = auth_views.LoginView.as_view(authentication_form=AuthenticationForm) From 69a7f07c052632cbe1f12493f592e6f4bbb87677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Sun, 27 Sep 2020 14:54:42 +0800 Subject: [PATCH 03/30] Clear gui --- src/templates/default/reviews/review_change.html | 4 ++-- src/users/views.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/templates/default/reviews/review_change.html b/src/templates/default/reviews/review_change.html index bdbd4fa74..31f8e0cd6 100644 --- a/src/templates/default/reviews/review_change.html +++ b/src/templates/default/reviews/review_change.html @@ -91,13 +91,13 @@

  • - timezone (non-required) + timezone (default is UTC +8)(non-required)
  • - comment (non-required) + timezone comment (non-required)
    diff --git a/src/users/views.py b/src/users/views.py index 78428b24e..e7725430d 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -211,6 +211,7 @@ def review_change(request): date_time_obj = datetime.strptime( request.POST['proposals.disable.after'], '%Y-%m-%dT%H:%M:%S') loc_dt = timezone(TIME_ZONE).localize(date_time_obj) + print(loc_dt) messages.info(request, 'Your setting has been changed successfully at ' + str(datetime.now())) reg[CONFERENCE_DEFAULT_SLUG + From 7300021f27876328bffe7125c87159eceabbd9c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Fri, 2 Oct 2020 11:53:46 +0800 Subject: [PATCH 04/30] Default timezone sring handling --- .../default/reviews/review_change.html | 39 ++++++++++++++++++- src/users/views.py | 20 ++++++---- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/templates/default/reviews/review_change.html b/src/templates/default/reviews/review_change.html index 31f8e0cd6..e837f986e 100644 --- a/src/templates/default/reviews/review_change.html +++ b/src/templates/default/reviews/review_change.html @@ -91,9 +91,41 @@

  • - timezone (default is UTC +8)(non-required) + timezone
    - +
  • @@ -115,6 +147,9 @@

    + {% endblock main-content %} {% block extra_js %} diff --git a/src/users/views.py b/src/users/views.py index e7725430d..024de75fb 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -31,8 +31,8 @@ from lxml import etree import lxml.html -from pytz import timezone -from datetime import datetime, timedelta +import pytz +import datetime User = auth.get_user_model() @@ -202,16 +202,21 @@ def get_context_data(self, **kwargs): return context def review_change(request): + + # Get default TimeZone + tz = pytz.timezone(settings.TIME_ZONE) + now = datetime.datetime.now(tz=tz).isoformat() + default_tz = now[len(now)-6:] + if request.method == 'POST': CONFERENCE_DEFAULT_SLUG = settings.CONFERENCE_DEFAULT_SLUG - TIME_ZONE = settings.TIME_ZONE + print(request.POST['proposals.disable.after']) fmt = '%Y-%m-%d %H:%M:%S%z' - date_time_obj = datetime.strptime( + date_time_obj = datetime.datetime.strptime( request.POST['proposals.disable.after'], '%Y-%m-%dT%H:%M:%S') - loc_dt = timezone(TIME_ZONE).localize(date_time_obj) - print(loc_dt) + loc_dt = datetime.timezone(TIME_ZONE).localize(date_time_obj) messages.info(request, 'Your setting has been changed successfully at ' + str(datetime.now())) reg[CONFERENCE_DEFAULT_SLUG + @@ -225,7 +230,8 @@ def review_change(request): reg[CONFERENCE_DEFAULT_SLUG + '.reviews.stage'] = int(request.POST['reviews.stage']) reg[CONFERENCE_DEFAULT_SLUG + '.proposals.disable.after'] = loc_dt - return render(request, 'reviews/review_change.html') + return render(request, 'reviews/review_change.html',{'default_tz': default_tz}) + login = auth_views.LoginView.as_view(authentication_form=AuthenticationForm) logout = auth_views.LogoutView.as_view() From a0362506ce58d7a0e760f8c9bf44e419fbe334c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Sun, 4 Oct 2020 18:04:09 +0800 Subject: [PATCH 05/30] rename to Review Stages --- src/locale/zh_Hant/LC_MESSAGES/django.po | 8 ++++---- .../js/reviews/{review_change.js => review_stages.js} | 0 src/templates/default/_includes/dashboard_tablist.html | 2 +- .../reviews/{review_change.html => review_stages.html} | 6 +++--- src/users/urls.py | 5 +---- src/users/views.py | 4 ++-- 6 files changed, 11 insertions(+), 14 deletions(-) rename src/static/js/reviews/{review_change.js => review_stages.js} (100%) rename src/templates/default/reviews/{review_change.html => review_stages.html} (97%) diff --git a/src/locale/zh_Hant/LC_MESSAGES/django.po b/src/locale/zh_Hant/LC_MESSAGES/django.po index 16a75e2e9..0604f8edc 100644 --- a/src/locale/zh_Hant/LC_MESSAGES/django.po +++ b/src/locale/zh_Hant/LC_MESSAGES/django.po @@ -1517,10 +1517,10 @@ msgid "Reviews" msgstr "審查" #: templates/default/_includes/dashboard_tablist.html:28 -#: templates/default/reviews/review_change.html:12 -#: templates/default/reviews/review_change.html:18 -msgid "Change Review" -msgstr "更改審查設定" +#: templates/default/reviews/review_stages.html:12 +#: templates/default/reviews/review_stages.html:18 +msgid "Review Stages" +msgstr "審查階段" #: templates/default/_includes/nav/dashboard_nav.html:10 msgid "Log out" diff --git a/src/static/js/reviews/review_change.js b/src/static/js/reviews/review_stages.js similarity index 100% rename from src/static/js/reviews/review_change.js rename to src/static/js/reviews/review_stages.js diff --git a/src/templates/default/_includes/dashboard_tablist.html b/src/templates/default/_includes/dashboard_tablist.html index a15e9afe7..b3c72d496 100644 --- a/src/templates/default/_includes/dashboard_tablist.html +++ b/src/templates/default/_includes/dashboard_tablist.html @@ -25,7 +25,7 @@ {% if user.is_superuser %}
  • - {% trans 'Change Review' %} + {% trans 'Review Stages' %}
  • {% endif %} diff --git a/src/templates/default/reviews/review_change.html b/src/templates/default/reviews/review_stages.html similarity index 97% rename from src/templates/default/reviews/review_change.html rename to src/templates/default/reviews/review_stages.html index e837f986e..01db246ff 100644 --- a/src/templates/default/reviews/review_change.html +++ b/src/templates/default/reviews/review_stages.html @@ -11,7 +11,7 @@ {% block main-content %}

    - {% trans 'Change Review' %} + {% trans 'Review Stages' %}

    @@ -38,7 +38,7 @@

    -
    + {% csrf_token %}
    {% trans 'Change Review' %}
    @@ -156,6 +156,6 @@

    {% compress js %} - + {% endcompress %} {% endblock extra_js %} \ No newline at end of file diff --git a/src/users/urls.py b/src/users/urls.py index e6f9033a3..b973f45a1 100644 --- a/src/users/urls.py +++ b/src/users/urls.py @@ -4,11 +4,9 @@ from . import views urlpatterns = [ - url(r'^login/$', views.login, name='login'), url(r'^logout/$', views.logout, name='logout'), url(r'^profile/$', views.user_profile_update, name='user_profile_update'), - url(r'^password-change/$', views.password_change, name='password_change'), url(r'^password-change/done/$', views.password_change_done, name='password_change_done'), @@ -30,6 +28,5 @@ url(r'^agreement/$', views.coc_agree, name='coc_agreement'), - url(r'^review-change/$', views.review_change, name='review_change'), - + url(r'^review-stages/$', views.review_stages, name='review_stages'), ] diff --git a/src/users/views.py b/src/users/views.py index 024de75fb..876eb8850 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -201,7 +201,7 @@ def get_context_data(self, **kwargs): context.update(**reviews_state()._asdict()) return context -def review_change(request): +def review_stages(request): # Get default TimeZone tz = pytz.timezone(settings.TIME_ZONE) @@ -230,7 +230,7 @@ def review_change(request): reg[CONFERENCE_DEFAULT_SLUG + '.reviews.stage'] = int(request.POST['reviews.stage']) reg[CONFERENCE_DEFAULT_SLUG + '.proposals.disable.after'] = loc_dt - return render(request, 'reviews/review_change.html',{'default_tz': default_tz}) + return render(request, 'reviews/review_stages.html',{'default_tz': default_tz}) login = auth_views.LoginView.as_view(authentication_form=AuthenticationForm) From 81d875e7fe13d4410aacfaf4a8a90855d6e80274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Tue, 13 Oct 2020 00:05:50 +0800 Subject: [PATCH 06/30] Generating timezone dynamically with pytz --- .../default/reviews/review_stages.html | 12 ++++- src/users/views.py | 49 ++++++++++--------- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/templates/default/reviews/review_stages.html b/src/templates/default/reviews/review_stages.html index 01db246ff..36706e678 100644 --- a/src/templates/default/reviews/review_stages.html +++ b/src/templates/default/reviews/review_stages.html @@ -3,6 +3,8 @@ {% load i18n static %} {% load proposals %} {% load compress crispy_forms_tags %} +{% load tz %} +{% get_current_timezone as TIME_ZONE %} {% block dashboard_tablist %} {% include '_includes/dashboard_tablist.html' with active='admin' %} @@ -93,7 +95,7 @@

  • timezone
    - + + {% for tz in timezones %} + + {% endfor %}
  • timezone comment (non-required)
    - +
  • diff --git a/src/users/views.py b/src/users/views.py index 876eb8850..6bce60cfb 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -203,34 +203,37 @@ def get_context_data(self, **kwargs): def review_stages(request): - # Get default TimeZone - tz = pytz.timezone(settings.TIME_ZONE) - now = datetime.datetime.now(tz=tz).isoformat() - default_tz = now[len(now)-6:] - if request.method == 'POST': - CONFERENCE_DEFAULT_SLUG = settings.CONFERENCE_DEFAULT_SLUG - - print(request.POST['proposals.disable.after']) fmt = '%Y-%m-%d %H:%M:%S%z' + tz_selectd = pytz.timezone(request.POST['review_timezone']) date_time_obj = datetime.datetime.strptime( request.POST['proposals.disable.after'], '%Y-%m-%dT%H:%M:%S') - loc_dt = datetime.timezone(TIME_ZONE).localize(date_time_obj) - messages.info(request, 'Your setting has been changed successfully at ' + str(datetime.now())) - - reg[CONFERENCE_DEFAULT_SLUG + - '.proposals.creatable'] = request.POST['proposals.creatable'] - reg[CONFERENCE_DEFAULT_SLUG + - '.proposals.editable'] = request.POST['proposals.editable'] - reg[CONFERENCE_DEFAULT_SLUG + '.proposals.withdrawable'] = request.POST[ - 'proposals.withdrawable'] - reg[CONFERENCE_DEFAULT_SLUG + '.reviews.visible.to.submitters'] = request.POST[ - 'reviews.visible.to.submitters'] - reg[CONFERENCE_DEFAULT_SLUG + '.reviews.stage'] = int(request.POST['reviews.stage']) - reg[CONFERENCE_DEFAULT_SLUG + '.proposals.disable.after'] = loc_dt - - return render(request, 'reviews/review_stages.html',{'default_tz': default_tz}) + loc_dt = tz_selectd.localize(date_time_obj).strftime(fmt) + + CONFERENCE_DEFAULT_SLUG = settings.CONFERENCE_DEFAULT_SLUG + review_stages_list = [ + 'proposals.creatable', 'proposals.editable', + 'proposals.withdrawable', 'reviews.visible.to.submitters', + 'reviews.stage', 'proposals.disable.after' + ] + + for tag in review_stages_list: + key = CONFERENCE_DEFAULT_SLUG + '.' + tag + if(tag == 'proposals.disable.after'): + value = loc_dt + else: + value = request.POST[tag] + reg[key] = value + print(key) + print(value) + + messages.info( + request, + 'This setting has been changed successfully and the review stage will expire at ' + + str(loc_dt) + ' (' + request.POST.get('review_timezone') + ')') + + return render(request, 'reviews/review_stages.html',{'timezones': pytz.common_timezones}) login = auth_views.LoginView.as_view(authentication_form=AuthenticationForm) From 13972088810d45187eaddeac9c470c4082b83c33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Tue, 13 Oct 2020 00:11:07 +0800 Subject: [PATCH 07/30] Delete comment in review_stages.html --- .../default/reviews/review_stages.html | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/src/templates/default/reviews/review_stages.html b/src/templates/default/reviews/review_stages.html index 36706e678..b3fde5a20 100644 --- a/src/templates/default/reviews/review_stages.html +++ b/src/templates/default/reviews/review_stages.html @@ -95,41 +95,7 @@

  • timezone
    -
  • -
  • - timezone comment (non-required) -
    - -
    -
  • @@ -121,14 +105,9 @@

    - {% endblock main-content %} {% block extra_js %} - {% compress js %} {% endcompress %} diff --git a/src/users/views.py b/src/users/views.py index 43b7aa3a9..3e138314c 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -202,6 +202,13 @@ def get_context_data(self, **kwargs): return context def review_stages(request): + + review_stages_list = [ + 'Call for Proposals', 'First Round Review_1', + 'First Round Review_2', 'Modification Stage', + 'Second Round Review', 'Internal Decision', + 'Announcement of Acceptance' + ] if request.method == 'POST': @@ -212,26 +219,32 @@ def review_stages(request): loc_dt = tz_selectd.localize(date_time_obj).strftime(fmt) CONFERENCE_DEFAULT_SLUG = settings.CONFERENCE_DEFAULT_SLUG - review_stages_list = [ + review_stages_var = [ 'proposals.creatable', 'proposals.editable', 'proposals.withdrawable', 'reviews.visible.to.submitters', 'reviews.stage', 'proposals.disable.after' ] - for tag in review_stages_list: + for tag in review_stages_var: key = CONFERENCE_DEFAULT_SLUG + '.' + tag if(tag == 'proposals.disable.after'): value = loc_dt + elif(tag == 'reviews.stage'): + value = int(request.POST[tag]) else: value = request.POST[tag] reg[key] = value - + messages.info( request, 'This setting has been changed successfully and the review stage will expire at ' + str(loc_dt) + ' (' + request.POST.get('review_timezone') + ')') - return render(request, 'reviews/review_stages.html',{'timezones': pytz.common_timezones}) + return render( + request, 'reviews/review_stages.html', { + 'timezones': pytz.common_timezones, + 'review_stages_list': review_stages_list + }) login = auth_views.LoginView.as_view(authentication_form=AuthenticationForm) From d867fc273e56dd94f4adcae6fde7b03495603821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Tue, 27 Oct 2020 00:29:00 +0800 Subject: [PATCH 10/30] return value add reviews_state() --- src/users/views.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/users/views.py b/src/users/views.py index 3e138314c..0d3fcf861 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -202,10 +202,10 @@ def get_context_data(self, **kwargs): return context def review_stages(request): - + review_stages_list = [ 'Call for Proposals', 'First Round Review_1', - 'First Round Review_2', 'Modification Stage', + 'First Round Review', 'Modification Stage', 'Second Round Review', 'Internal Decision', 'Announcement of Acceptance' ] @@ -243,7 +243,8 @@ def review_stages(request): return render( request, 'reviews/review_stages.html', { 'timezones': pytz.common_timezones, - 'review_stages_list': review_stages_list + 'review_stages_list': review_stages_list, + **reviews_state()._asdict() }) From 65016fa6c0e7a1d79aa8c6c71cf31e69550c33ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Tue, 27 Oct 2020 00:35:29 +0800 Subject: [PATCH 11/30] Rename First Round Review_2 to First Round Review --- src/static/js/reviews/review_stages.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/static/js/reviews/review_stages.js b/src/static/js/reviews/review_stages.js index 3727e7da6..9917816b1 100644 --- a/src/static/js/reviews/review_stages.js +++ b/src/static/js/reviews/review_stages.js @@ -12,8 +12,8 @@ $('.hotkey').click(function () { else if ($(this).val() == "First Round Review_1") { First_Round_Review_1() } - else if ($(this).val() == "First Round Review_2") { - First_Round_Review_2() + else if ($(this).val() == "First Round Review") { + First_Round_Review() } else if ($(this).val() == "Modification Stage") { Modification_Stage() @@ -46,7 +46,7 @@ $('.hotkey').click(function () { reviews_stage.value = "0"; reviews_visible_to_submitters.checked = false; } - function First_Round_Review_2() { + function First_Round_Review() { proposals_creatable.checked = false; proposals_editable.checked = false; proposals_withdrawable.checked = false; From 95d6dc95596a8b3666d2ee39971727537249ad2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Thu, 10 Dec 2020 22:39:00 +0800 Subject: [PATCH 12/30] Change the typography to vertical --- .../default/reviews/review_stages.html | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/templates/default/reviews/review_stages.html b/src/templates/default/reviews/review_stages.html index ca6e5240a..c6852fbc4 100644 --- a/src/templates/default/reviews/review_stages.html +++ b/src/templates/default/reviews/review_stages.html @@ -17,14 +17,12 @@

    - -
    +
    + {% for rs in review_stages_list %} - + {% endfor %} -
    - -
    + {% csrf_token %}
    @@ -78,8 +76,8 @@

  • {{ ".proposals.disable.after"|configuration_switch }}
    - +
  • @@ -111,4 +109,5 @@

    {% compress js %} {% endcompress %} -{% endblock extra_js %} \ No newline at end of file +{% endblock extra_js %} + From b56946c5c83c05659e9720b753bec958add71313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Thu, 10 Dec 2020 22:40:26 +0800 Subject: [PATCH 13/30] Rename First Round Review_1 to Locked (proposal editing and reviewing disabled) --- src/static/js/reviews/review_stages.js | 8 ++++---- src/users/views.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/static/js/reviews/review_stages.js b/src/static/js/reviews/review_stages.js index 9917816b1..909ae40cd 100644 --- a/src/static/js/reviews/review_stages.js +++ b/src/static/js/reviews/review_stages.js @@ -9,8 +9,8 @@ $('.hotkey').click(function () { if ($(this).val() == "Call for Proposals") { Call_for_Proposals(); } - else if ($(this).val() == "First Round Review_1") { - First_Round_Review_1() + else if ($(this).val() == "Locked (proposal editing and reviewing disabled)") { + Locked() } else if ($(this).val() == "First Round Review") { First_Round_Review() @@ -36,10 +36,10 @@ $('.hotkey').click(function () { proposals_creatable.checked = true; proposals_editable.checked = true; proposals_withdrawable.checked = true; - reviews_stage.value = 0; + reviews_stage.value = "0"; reviews_visible_to_submitters.checked = false; } - function First_Round_Review_1() { + function Locked() { proposals_creatable.checked = false; proposals_editable.checked = false; proposals_withdrawable.checked = false; diff --git a/src/users/views.py b/src/users/views.py index 0d3fcf861..c2f3fe385 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -204,10 +204,10 @@ def get_context_data(self, **kwargs): def review_stages(request): review_stages_list = [ - 'Call for Proposals', 'First Round Review_1', - 'First Round Review', 'Modification Stage', - 'Second Round Review', 'Internal Decision', - 'Announcement of Acceptance' + 'Call for Proposals', + 'Locked (proposal editing and reviewing disabled)', + 'First Round Review', 'Modification Stage', 'Second Round Review', + 'Internal Decision', 'Announcement of Acceptance' ] if request.method == 'POST': From 663e4334573140cb5647b4a5f76239a234048a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Wed, 16 Dec 2020 00:20:11 +0800 Subject: [PATCH 14/30] Enhance user friendliness : accepting pycontw-2020.proposals.disable.after values without ss (seconds) --- src/templates/default/reviews/review_stages.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/templates/default/reviews/review_stages.html b/src/templates/default/reviews/review_stages.html index c6852fbc4..8967b9bda 100644 --- a/src/templates/default/reviews/review_stages.html +++ b/src/templates/default/reviews/review_stages.html @@ -76,7 +76,7 @@

  • {{ ".proposals.disable.after"|configuration_switch }}
    -
  • From c2a6d53f2a20850fcdbffc0c47a5cf308d514046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Wed, 16 Dec 2020 00:27:23 +0800 Subject: [PATCH 15/30] Enhance user friendliness : Try more django date format (DATETIME_INPUT_FORMATS) for pycontw-2020.proposals.disable.after & catch ValidationError --- src/users/views.py | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/users/views.py b/src/users/views.py index c2f3fe385..092733bdb 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -1,5 +1,7 @@ import lxml.html from django.conf import settings +from django.conf.global_settings import DATETIME_INPUT_FORMATS +from django.core.exceptions import ValidationError from django.contrib import auth, messages from django.contrib.auth import views as auth_views from django.contrib.auth.decorators import login_required @@ -202,31 +204,27 @@ def get_context_data(self, **kwargs): return context def review_stages(request): - review_stages_list = [ 'Call for Proposals', 'Locked (proposal editing and reviewing disabled)', 'First Round Review', 'Modification Stage', 'Second Round Review', 'Internal Decision', 'Announcement of Acceptance' ] + review_stages_var = [ + 'proposals.creatable', 'proposals.editable', + 'proposals.withdrawable', 'reviews.visible.to.submitters', + 'reviews.stage', 'proposals.disable.after' + ] if request.method == 'POST': - fmt = '%Y-%m-%d %H:%M:%S%z' + date_time_obj = date_preprocess( + DATETIME_INPUT_FORMATS, request.POST['proposals.disable.after']) tz_selectd = pytz.timezone(request.POST['review_timezone']) - date_time_obj = datetime.datetime.strptime( - request.POST['proposals.disable.after'], '%Y-%m-%dT%H:%M:%S') - loc_dt = tz_selectd.localize(date_time_obj).strftime(fmt) - - CONFERENCE_DEFAULT_SLUG = settings.CONFERENCE_DEFAULT_SLUG - review_stages_var = [ - 'proposals.creatable', 'proposals.editable', - 'proposals.withdrawable', 'reviews.visible.to.submitters', - 'reviews.stage', 'proposals.disable.after' - ] + loc_dt = tz_selectd.localize(date_time_obj).strftime('%Y-%m-%d %H:%M:%S%z') for tag in review_stages_var: - key = CONFERENCE_DEFAULT_SLUG + '.' + tag + key = settings.CONFERENCE_DEFAULT_SLUG + '.' + tag if(tag == 'proposals.disable.after'): value = loc_dt elif(tag == 'reviews.stage'): @@ -247,6 +245,17 @@ def review_stages(request): **reviews_state()._asdict() }) +def date_preprocess(DATETIME_INPUT_FORMATS, value): + # Add defined datetime formatx + DATETIME_INPUT_FORMATS += ['%Y-%m-%dT%H:%M:%S', '%Y-%m-%dT%H:%M'] + value = value.strip() + # Try to strptime against each input format. + for format in DATETIME_INPUT_FORMATS: + try: + return datetime.datetime.strptime(value, format) + except (ValueError, TypeError): + continue + raise ValidationError("Please input valid date format : " + "%Y-%m-%dT%H:%M") login = auth_views.LoginView.as_view(authentication_form=AuthenticationForm) logout = auth_views.LogoutView.as_view() From cc7fc66b167a94d1a03edfebb9ac3e0570ae7f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Wed, 23 Dec 2020 01:42:52 +0800 Subject: [PATCH 16/30] Enhance user friendliness : display current review stage setting --- src/locale/zh_Hant/LC_MESSAGES/django.po | 12 +++++ .../default/reviews/review_stages.html | 46 ++++++++++++++++++- src/users/views.py | 16 +++++-- 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/locale/zh_Hant/LC_MESSAGES/django.po b/src/locale/zh_Hant/LC_MESSAGES/django.po index 0604f8edc..d65786fdb 100644 --- a/src/locale/zh_Hant/LC_MESSAGES/django.po +++ b/src/locale/zh_Hant/LC_MESSAGES/django.po @@ -1522,6 +1522,18 @@ msgstr "審查" msgid "Review Stages" msgstr "審查階段" +#: templates/default/_includes/dashboard_tablist.html:28 +#: templates/default/reviews/review_stages.html:12 +#: templates/default/reviews/review_stages.html:18 +msgid "Current Review Stage Setting" +msgstr "目前審查階段設定" + +#: templates/default/_includes/dashboard_tablist.html:28 +#: templates/default/reviews/review_stages.html:12 +#: templates/default/reviews/review_stages.html:18 +msgid "Set Review Stage" +msgstr "設定審查階段" + #: templates/default/_includes/nav/dashboard_nav.html:10 msgid "Log out" msgstr "登出" diff --git a/src/templates/default/reviews/review_stages.html b/src/templates/default/reviews/review_stages.html index 8967b9bda..7bcb8526c 100644 --- a/src/templates/default/reviews/review_stages.html +++ b/src/templates/default/reviews/review_stages.html @@ -13,12 +13,56 @@ {% block main-content %}

    - {% trans 'Review Stages' %} + {% trans 'Review Stages' %}

    + +
    +
    {% trans 'Current Review Stage Setting' %}
    +
      +
    • + {{ ".proposals.creatable"|configuration_switch }} +
      +

      {{ current_review_stages_setting.proposals_creatable }}

      +
      +
    • +
    • + {{ ".proposals.editable"|configuration_switch }} +
      +

      {{ current_review_stages_setting.proposals_editable }}

      +
      +
    • +
    • + {{ ".proposals.withdrawable"|configuration_switch }} +
      +

      {{ current_review_stages_setting.proposals_withdrawable }}

      +
      +
    • +
    • + {{ ".proposals.reviews.visible.to.submitters"|configuration_switch }} +
      +

      {{ current_review_stages_setting.reviews_visible_to_submitters }}

      +
      +
    • +
    • + {{ ".proposals.reviews.stage"|configuration_switch }} +
      +

      {{ current_review_stages_setting.reviews_stage }}

      +
      +
    • +
    • + {{ ".proposals.proposals.disable.after"|configuration_switch }} +
      +

      {{ current_review_stages_setting.proposals_disable_after }}

      +
      +
    +
    +
    +

    {% trans 'Set Review Stage' %}

    +
    {% for rs in review_stages_list %} {% endfor %} diff --git a/src/users/views.py b/src/users/views.py index 092733bdb..5fb506a4a 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -204,6 +204,7 @@ def get_context_data(self, **kwargs): return context def review_stages(request): + current_review_stages_setting = {} review_stages_list = [ 'Call for Proposals', 'Locked (proposal editing and reviewing disabled)', @@ -217,7 +218,6 @@ def review_stages(request): ] if request.method == 'POST': - date_time_obj = date_preprocess( DATETIME_INPUT_FORMATS, request.POST['proposals.disable.after']) tz_selectd = pytz.timezone(request.POST['review_timezone']) @@ -233,15 +233,21 @@ def review_stages(request): value = request.POST[tag] reg[key] = value - messages.info( - request, - 'This setting has been changed successfully and the review stage will expire at ' - + str(loc_dt) + ' (' + request.POST.get('review_timezone') + ')') + messages.info(request, 'This setting has been changed successfully.') + else: + for tag in review_stages_var: + key = settings.CONFERENCE_DEFAULT_SLUG + '.' + tag + value = reg.get(key, '') + # Django template language does not support dictionary keys containing "." + if "." in tag: + tag = tag.replace(".", "_") + current_review_stages_setting[tag] = value return render( request, 'reviews/review_stages.html', { 'timezones': pytz.common_timezones, 'review_stages_list': review_stages_list, + 'current_review_stages_setting': current_review_stages_setting, **reviews_state()._asdict() }) From 8547598a4b6c9a0d5c953fc5aeae0d039d225cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Sun, 27 Dec 2020 22:40:06 +0800 Subject: [PATCH 17/30] Enhance user friendliness : automatically load the current settings to the form that will be submitted --- src/templates/default/reviews/review_stages.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/templates/default/reviews/review_stages.html b/src/templates/default/reviews/review_stages.html index 7bcb8526c..142f188b3 100644 --- a/src/templates/default/reviews/review_stages.html +++ b/src/templates/default/reviews/review_stages.html @@ -152,6 +152,13 @@

    {% trans 'Set Review Stage' %}

    {% block extra_js %} {% compress js %} + {% endcompress %} {% endblock extra_js %} From aaa5034aed59bc73a302850c2a18b2c7419ca709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Sun, 27 Dec 2020 22:45:16 +0800 Subject: [PATCH 18/30] Move url.py & view.py to more precise folder --- src/reviews/urls.py | 2 ++ src/reviews/views.py | 72 ++++++++++++++++++++++++++++++++++++++++++++ src/users/urls.py | 2 +- src/users/views.py | 66 ---------------------------------------- 4 files changed, 75 insertions(+), 67 deletions(-) diff --git a/src/reviews/urls.py b/src/reviews/urls.py index f81b1df27..2c18103ee 100644 --- a/src/reviews/urls.py +++ b/src/reviews/urls.py @@ -1,9 +1,11 @@ from django.conf.urls import url +from . import views from .views import ReviewEditView, TalkProposalListView urlpatterns = [ url(r'^$', TalkProposalListView.as_view(), name='review_proposal_list'), url(r'^talk/(?P\d+)/$', ReviewEditView.as_view(), name='review_edit'), + url(r'^review-stages/$', views.review_stages, name='review_stages'), ] diff --git a/src/reviews/views.py b/src/reviews/views.py index 6e0ea7534..b0982c6ba 100644 --- a/src/reviews/views.py +++ b/src/reviews/views.py @@ -2,10 +2,14 @@ import json import random +from django.conf import settings +from django.conf.global_settings import DATETIME_INPUT_FORMATS +from django.core.exceptions import ValidationError from django.contrib.auth.mixins import PermissionRequiredMixin from django.db.models import Count from django.http import Http404 from django.urls import reverse +from django.shortcuts import redirect, render from django.views.generic import ListView, UpdateView from core.utils import SequenceQuerySet @@ -15,6 +19,10 @@ from .forms import ReviewForm from .models import REVIEW_REQUIRED_PERMISSIONS, Review, TalkProposalSnapshot +from registry.helper import reg + +import pytz +import datetime class ReviewableMixin: def dispatch(self, request, *args, **kwargs): @@ -327,3 +335,67 @@ def get_success_url(self): if query_string: return url + '?' + query_string return url + +def review_stages(request): + current_review_stages_setting = {} + review_stages_list = [ + 'Call for Proposals', + 'Locked (proposal editing and reviewing disabled)', + 'First Round Review', 'Modification Stage', 'Second Round Review', + 'Internal Decision', 'Announcement of Acceptance' + ] + review_stages_var = [ + 'proposals.creatable', 'proposals.editable', 'proposals.withdrawable', + 'reviews.visible.to.submitters', 'reviews.stage', + 'proposals.disable.after' + ] + + if request.method == 'POST': + date_time_obj = date_preprocess( + DATETIME_INPUT_FORMATS, request.POST['proposals.disable.after']) + tz_selectd = pytz.timezone(request.POST['review_timezone']) + loc_dt = tz_selectd.localize(date_time_obj).strftime( + '%Y-%m-%d %H:%M:%S%z') + + for tag in review_stages_var: + key = settings.CONFERENCE_DEFAULT_SLUG + '.' + tag + if (tag == 'proposals.disable.after'): + value = loc_dt + elif (tag == 'reviews.stage'): + value = int(request.POST[tag]) + else: + value = request.POST[tag] + reg[key] = value + + messages.info(request, 'This setting has been changed successfully.') + else: + for tag in review_stages_var: + key = settings.CONFERENCE_DEFAULT_SLUG + '.' + tag + value = reg.get(key, '') + # Django template language does not support dictionary keys containing "." + if "." in tag: + tag = tag.replace(".", "_") + current_review_stages_setting[tag] = value + print(tag) + print(value) + + return render( + request, 'reviews/review_stages.html', { + 'timezones': pytz.common_timezones, + 'review_stages_list': review_stages_list, + 'current_review_stages_setting': current_review_stages_setting, + **reviews_state()._asdict() + }) + + +def date_preprocess(DATETIME_INPUT_FORMATS, value): + # Add defined datetime formatx + DATETIME_INPUT_FORMATS += ['%Y-%m-%dT%H:%M:%S', '%Y-%m-%dT%H:%M'] + value = value.strip() + # Try to strptime against each input format. + for format in DATETIME_INPUT_FORMATS: + try: + return datetime.datetime.strptime(value, format) + except (ValueError, TypeError): + continue + raise ValidationError("Please input valid date format : " + "%Y-%m-%dT%H:%M") diff --git a/src/users/urls.py b/src/users/urls.py index b973f45a1..2a49cfa82 100644 --- a/src/users/urls.py +++ b/src/users/urls.py @@ -1,4 +1,5 @@ from django.conf.urls import url +from django.contrib.auth import views as auth from django.urls import path from . import views @@ -28,5 +29,4 @@ url(r'^agreement/$', views.coc_agree, name='coc_agreement'), - url(r'^review-stages/$', views.review_stages, name='review_stages'), ] diff --git a/src/users/views.py b/src/users/views.py index 5fb506a4a..a3c88df8e 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -1,7 +1,5 @@ import lxml.html from django.conf import settings -from django.conf.global_settings import DATETIME_INPUT_FORMATS -from django.core.exceptions import ValidationError from django.contrib import auth, messages from django.contrib.auth import views as auth_views from django.contrib.auth.decorators import login_required @@ -28,14 +26,10 @@ ) from .models import CocRecord from reviews.context import proposals_state, reviews_state -from registry.helper import reg from lxml import etree import lxml.html -import pytz -import datetime - User = auth.get_user_model() @@ -203,66 +197,6 @@ def get_context_data(self, **kwargs): context.update(**reviews_state()._asdict()) return context -def review_stages(request): - current_review_stages_setting = {} - review_stages_list = [ - 'Call for Proposals', - 'Locked (proposal editing and reviewing disabled)', - 'First Round Review', 'Modification Stage', 'Second Round Review', - 'Internal Decision', 'Announcement of Acceptance' - ] - review_stages_var = [ - 'proposals.creatable', 'proposals.editable', - 'proposals.withdrawable', 'reviews.visible.to.submitters', - 'reviews.stage', 'proposals.disable.after' - ] - - if request.method == 'POST': - date_time_obj = date_preprocess( - DATETIME_INPUT_FORMATS, request.POST['proposals.disable.after']) - tz_selectd = pytz.timezone(request.POST['review_timezone']) - loc_dt = tz_selectd.localize(date_time_obj).strftime('%Y-%m-%d %H:%M:%S%z') - - for tag in review_stages_var: - key = settings.CONFERENCE_DEFAULT_SLUG + '.' + tag - if(tag == 'proposals.disable.after'): - value = loc_dt - elif(tag == 'reviews.stage'): - value = int(request.POST[tag]) - else: - value = request.POST[tag] - reg[key] = value - - messages.info(request, 'This setting has been changed successfully.') - else: - for tag in review_stages_var: - key = settings.CONFERENCE_DEFAULT_SLUG + '.' + tag - value = reg.get(key, '') - # Django template language does not support dictionary keys containing "." - if "." in tag: - tag = tag.replace(".", "_") - current_review_stages_setting[tag] = value - - return render( - request, 'reviews/review_stages.html', { - 'timezones': pytz.common_timezones, - 'review_stages_list': review_stages_list, - 'current_review_stages_setting': current_review_stages_setting, - **reviews_state()._asdict() - }) - -def date_preprocess(DATETIME_INPUT_FORMATS, value): - # Add defined datetime formatx - DATETIME_INPUT_FORMATS += ['%Y-%m-%dT%H:%M:%S', '%Y-%m-%dT%H:%M'] - value = value.strip() - # Try to strptime against each input format. - for format in DATETIME_INPUT_FORMATS: - try: - return datetime.datetime.strptime(value, format) - except (ValueError, TypeError): - continue - raise ValidationError("Please input valid date format : " + "%Y-%m-%dT%H:%M") - login = auth_views.LoginView.as_view(authentication_form=AuthenticationForm) logout = auth_views.LogoutView.as_view() password_change = PasswordChangeView.as_view() From 0ad904558d0a13ece5b452414abe91e57545101e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Tue, 29 Dec 2020 01:30:26 +0800 Subject: [PATCH 19/30] Fix problem that current settings will not be loaded after submitting form --- src/reviews/views.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/reviews/views.py b/src/reviews/views.py index b0982c6ba..cd77e8efc 100644 --- a/src/reviews/views.py +++ b/src/reviews/views.py @@ -6,6 +6,7 @@ from django.conf.global_settings import DATETIME_INPUT_FORMATS from django.core.exceptions import ValidationError from django.contrib.auth.mixins import PermissionRequiredMixin +from django.contrib import messages from django.db.models import Count from django.http import Http404 from django.urls import reverse @@ -368,16 +369,15 @@ def review_stages(request): reg[key] = value messages.info(request, 'This setting has been changed successfully.') - else: - for tag in review_stages_var: - key = settings.CONFERENCE_DEFAULT_SLUG + '.' + tag - value = reg.get(key, '') - # Django template language does not support dictionary keys containing "." - if "." in tag: - tag = tag.replace(".", "_") - current_review_stages_setting[tag] = value - print(tag) - print(value) + + # Render current setting to frontend + for tag in review_stages_var: + key = settings.CONFERENCE_DEFAULT_SLUG + '.' + tag + value = reg.get(key, '') + # Django template language does not support dictionary keys containing "." + if "." in tag: + tag = tag.replace(".", "_") + current_review_stages_setting[tag] = value return render( request, 'reviews/review_stages.html', { From f2dd18e3ddbf8df7fbb0c1affc06fb6505c6f1d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=B5=E6=AB=BB=E7=80=9E?= Date: Sat, 16 Jan 2021 08:47:18 +0800 Subject: [PATCH 20/30] proposals.disabled.after not be required --- src/reviews/views.py | 30 +++++++++++++---- src/static/js/reviews/review_stages.js | 3 +- .../default/reviews/review_stages.html | 33 ++----------------- 3 files changed, 27 insertions(+), 39 deletions(-) diff --git a/src/reviews/views.py b/src/reviews/views.py index cd77e8efc..48e9e2977 100644 --- a/src/reviews/views.py +++ b/src/reviews/views.py @@ -352,16 +352,31 @@ def review_stages(request): ] if request.method == 'POST': - date_time_obj = date_preprocess( - DATETIME_INPUT_FORMATS, request.POST['proposals.disable.after']) - tz_selectd = pytz.timezone(request.POST['review_timezone']) - loc_dt = tz_selectd.localize(date_time_obj).strftime( - '%Y-%m-%d %H:%M:%S%z') for tag in review_stages_var: key = settings.CONFERENCE_DEFAULT_SLUG + '.' + tag if (tag == 'proposals.disable.after'): - value = loc_dt + if(request.POST['proposals.disable.after'] == ""): + continue + else: + date_time_obj = date_preprocess( + DATETIME_INPUT_FORMATS, + request.POST['proposals.disable.after']) + if(date_time_obj is None): + messages.error(request,'Please input valid date format : " + "%Y-%m-%dT%H:%M') + return render( + request, 'reviews/review_stages.html', { + 'timezones': pytz.common_timezones, + 'review_stages_list': review_stages_list, + 'current_review_stages_setting': current_review_stages_setting, + **reviews_state()._asdict() + }) + continue + else: + tz_selectd = pytz.timezone(request.POST['review_timezone']) + loc_dt = tz_selectd.localize(date_time_obj).strftime( + '%Y-%m-%d %H:%M:%S%z') + value = loc_dt elif (tag == 'reviews.stage'): value = int(request.POST[tag]) else: @@ -398,4 +413,5 @@ def date_preprocess(DATETIME_INPUT_FORMATS, value): return datetime.datetime.strptime(value, format) except (ValueError, TypeError): continue - raise ValidationError("Please input valid date format : " + "%Y-%m-%dT%H:%M") + return None + # raise ValidationError("Please input valid date format : " + "%Y-%m-%dT%H:%M") diff --git a/src/static/js/reviews/review_stages.js b/src/static/js/reviews/review_stages.js index 909ae40cd..48baa9a8b 100644 --- a/src/static/js/reviews/review_stages.js +++ b/src/static/js/reviews/review_stages.js @@ -81,4 +81,5 @@ $('.hotkey').click(function () { reviews_stage.value = "0"; reviews_visible_to_submitters.checked = true; } -}); \ No newline at end of file + +}); diff --git a/src/templates/default/reviews/review_stages.html b/src/templates/default/reviews/review_stages.html index 142f188b3..3427d22b8 100644 --- a/src/templates/default/reviews/review_stages.html +++ b/src/templates/default/reviews/review_stages.html @@ -22,41 +22,12 @@

    {% trans 'Current Review Stage Setting' %}
      -
    • - {{ ".proposals.creatable"|configuration_switch }} -
      -

      {{ current_review_stages_setting.proposals_creatable }}

      -
      -
    • -
    • - {{ ".proposals.editable"|configuration_switch }} -
      -

      {{ current_review_stages_setting.proposals_editable }}

      -
      -
    • -
    • - {{ ".proposals.withdrawable"|configuration_switch }} -
      -

      {{ current_review_stages_setting.proposals_withdrawable }}

      -
      -
    • -
    • - {{ ".proposals.reviews.visible.to.submitters"|configuration_switch }} -
      -

      {{ current_review_stages_setting.reviews_visible_to_submitters }}

      -
      -
    • -
    • - {{ ".proposals.reviews.stage"|configuration_switch }} -
      -

      {{ current_review_stages_setting.reviews_stage }}

      -
      -
    • {{ ".proposals.proposals.disable.after"|configuration_switch }}

      {{ current_review_stages_setting.proposals_disable_after }}

      +
    @@ -121,7 +92,7 @@

    {% trans 'Set Review Stage' %}

    {{ ".proposals.disable.after"|configuration_switch }}
    + >

  • From eef9a4685ed25554b34f63bfebd97e35a7356784 Mon Sep 17 00:00:00 2001 From: tomatoprinx Date: Sun, 2 Jun 2024 23:13:51 +0800 Subject: [PATCH 21/30] Remove unnecessary parentheses and harcoded key --- src/reviews/views.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/reviews/views.py b/src/reviews/views.py index 48e9e2977..2f5232465 100644 --- a/src/reviews/views.py +++ b/src/reviews/views.py @@ -355,14 +355,12 @@ def review_stages(request): for tag in review_stages_var: key = settings.CONFERENCE_DEFAULT_SLUG + '.' + tag - if (tag == 'proposals.disable.after'): - if(request.POST['proposals.disable.after'] == ""): + if tag == 'proposals.disable.after': + if request.POST[tag] == "": continue else: - date_time_obj = date_preprocess( - DATETIME_INPUT_FORMATS, - request.POST['proposals.disable.after']) - if(date_time_obj is None): + date_time_obj = date_preprocess(DATETIME_INPUT_FORMATS, request.POST[tag]) + if date_time_obj is None: messages.error(request,'Please input valid date format : " + "%Y-%m-%dT%H:%M') return render( request, 'reviews/review_stages.html', { @@ -377,7 +375,7 @@ def review_stages(request): loc_dt = tz_selectd.localize(date_time_obj).strftime( '%Y-%m-%d %H:%M:%S%z') value = loc_dt - elif (tag == 'reviews.stage'): + elif tag == 'reviews.stage': value = int(request.POST[tag]) else: value = request.POST[tag] From 4fac69890871e4be396e769defcd6d116371883f Mon Sep 17 00:00:00 2001 From: tomatoprinx Date: Sat, 20 Jul 2024 16:59:29 +0800 Subject: [PATCH 22/30] Fix duplicated return() and safeguard current_review_stages_setting from data loss on invalid `proposals.disable.after` value --- src/reviews/views.py | 60 +++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/src/reviews/views.py b/src/reviews/views.py index 2f5232465..082d312ae 100644 --- a/src/reviews/views.py +++ b/src/reviews/views.py @@ -1,29 +1,26 @@ import collections +import datetime import json import random +import pytz +from core.utils import SequenceQuerySet from django.conf import settings from django.conf.global_settings import DATETIME_INPUT_FORMATS -from django.core.exceptions import ValidationError -from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib import messages +from django.contrib.auth.mixins import PermissionRequiredMixin from django.db.models import Count from django.http import Http404 +from django.shortcuts import render from django.urls import reverse -from django.shortcuts import redirect, render from django.views.generic import ListView, UpdateView - -from core.utils import SequenceQuerySet from proposals.models import TalkProposal +from registry.helper import reg from .context import reviews_state from .forms import ReviewForm from .models import REVIEW_REQUIRED_PERMISSIONS, Review, TalkProposalSnapshot -from registry.helper import reg - -import pytz -import datetime class ReviewableMixin: def dispatch(self, request, *args, **kwargs): @@ -35,7 +32,6 @@ def dispatch(self, request, *args, **kwargs): class TalkProposalListView(ReviewableMixin, PermissionRequiredMixin, ListView): - model = TalkProposal permission_required = REVIEW_REQUIRED_PERMISSIONS template_name = 'reviews/talk_proposal_list.html' @@ -179,9 +175,9 @@ def get_stage_1_reviews(self): review__stage=1, review__reviewer=self.request.user ) & TalkProposal.objects.filter( - review__stage=2, - review__reviewer=self.request.user - ) + review__stage=2, + review__reviewer=self.request.user + ) ) stage_1_reviews = ( Review.objects @@ -209,7 +205,6 @@ def get_stage_2_reviews(self): class ReviewEditView(ReviewableMixin, PermissionRequiredMixin, UpdateView): - form_class = ReviewForm permission_required = REVIEW_REQUIRED_PERMISSIONS template_name = 'reviews/review_form.html' @@ -337,6 +332,7 @@ def get_success_url(self): return url + '?' + query_string return url + def review_stages(request): current_review_stages_setting = {} review_stages_list = [ @@ -351,8 +347,13 @@ def review_stages(request): 'proposals.disable.after' ] - if request.method == 'POST': + # Initialize current setting with existing value + for tag in review_stages_var: + key = settings.CONFERENCE_DEFAULT_SLUG + '.' + tag + value = reg.get(key, '') + update_current_review_stages_setting(tag, value, current_review_stages_setting) + if request.method == 'POST': for tag in review_stages_var: key = settings.CONFERENCE_DEFAULT_SLUG + '.' + tag if tag == 'proposals.disable.after': @@ -361,15 +362,8 @@ def review_stages(request): else: date_time_obj = date_preprocess(DATETIME_INPUT_FORMATS, request.POST[tag]) if date_time_obj is None: - messages.error(request,'Please input valid date format : " + "%Y-%m-%dT%H:%M') - return render( - request, 'reviews/review_stages.html', { - 'timezones': pytz.common_timezones, - 'review_stages_list': review_stages_list, - 'current_review_stages_setting': current_review_stages_setting, - **reviews_state()._asdict() - }) - continue + messages.error(request, 'Please input valid date format : " + "%Y-%m-%dT%H:%M') + value = None else: tz_selectd = pytz.timezone(request.POST['review_timezone']) loc_dt = tz_selectd.localize(date_time_obj).strftime( @@ -380,18 +374,10 @@ def review_stages(request): else: value = request.POST[tag] reg[key] = value + update_current_review_stages_setting(tag, value, current_review_stages_setting) messages.info(request, 'This setting has been changed successfully.') - # Render current setting to frontend - for tag in review_stages_var: - key = settings.CONFERENCE_DEFAULT_SLUG + '.' + tag - value = reg.get(key, '') - # Django template language does not support dictionary keys containing "." - if "." in tag: - tag = tag.replace(".", "_") - current_review_stages_setting[tag] = value - return render( request, 'reviews/review_stages.html', { 'timezones': pytz.common_timezones, @@ -401,6 +387,13 @@ def review_stages(request): }) +def update_current_review_stages_setting(tag, value, current_review_stages_setting): + # Django template language does not support dictionary keys containing "." + if "." in tag: + tag = tag.replace(".", "_") + current_review_stages_setting[tag] = value + + def date_preprocess(DATETIME_INPUT_FORMATS, value): # Add defined datetime formatx DATETIME_INPUT_FORMATS += ['%Y-%m-%dT%H:%M:%S', '%Y-%m-%dT%H:%M'] @@ -412,4 +405,3 @@ def date_preprocess(DATETIME_INPUT_FORMATS, value): except (ValueError, TypeError): continue return None - # raise ValidationError("Please input valid date format : " + "%Y-%m-%dT%H:%M") From 4e0bcdd48066d9c4a40969048d5c3f1c582b1c41 Mon Sep 17 00:00:00 2001 From: tomatoprinx Date: Sun, 21 Jul 2024 01:33:51 +0800 Subject: [PATCH 23/30] Fix `proposals.disable.after` value rendering in input element --- src/static/js/reviews/review_stages.js | 152 +++++++++--------- .../default/reviews/review_stages.html | 36 +++-- 2 files changed, 97 insertions(+), 91 deletions(-) diff --git a/src/static/js/reviews/review_stages.js b/src/static/js/reviews/review_stages.js index 48baa9a8b..8fa376d34 100644 --- a/src/static/js/reviews/review_stages.js +++ b/src/static/js/reviews/review_stages.js @@ -1,85 +1,85 @@ - var proposals_creatable = document.getElementById("proposals.creatable"); var proposals_editable = document.getElementById("proposals.editable"); var proposals_withdrawable = document.getElementById("proposals.withdrawable"); +var proposals_disable_after = document.getElementById("proposals.disable.after"); var reviews_stage = document.getElementById("reviews.stage"); var reviews_visible_to_submitters = document.getElementById("reviews.visible.to.submitters"); $('.hotkey').click(function () { - if ($(this).val() == "Call for Proposals") { - Call_for_Proposals(); - } - else if ($(this).val() == "Locked (proposal editing and reviewing disabled)") { - Locked() - } - else if ($(this).val() == "First Round Review") { - First_Round_Review() - } - else if ($(this).val() == "Modification Stage") { - Modification_Stage() - } - else if ($(this).val() == "Second Round Review") { - Second_Round_Review() - } - else if ($(this).val() == "Internal Decision") { - Internal_Decision() - } - else { - Announcement_of_Acceptance() - } + if ($(this).val() == "Call for Proposals") { + Call_for_Proposals(); + } else if ($(this).val() == "Locked (proposal editing and reviewing disabled)") { + Locked() + } else if ($(this).val() == "First Round Review") { + First_Round_Review() + } else if ($(this).val() == "Modification Stage") { + Modification_Stage() + } else if ($(this).val() == "Second Round Review") { + Second_Round_Review() + } else if ($(this).val() == "Internal Decision") { + Internal_Decision() + } else { + Announcement_of_Acceptance() + } + + /* + Proposal Review Stage Setting + Reference : https://github.com/pycontw/pycon.tw/blob/master/src/reviews/README.md + */ + function Call_for_Proposals() { + proposals_creatable.checked = true; + proposals_editable.checked = true; + proposals_withdrawable.checked = true; + reviews_stage.value = "0"; + reviews_visible_to_submitters.checked = false; + } + + function Locked() { + proposals_creatable.checked = false; + proposals_editable.checked = false; + proposals_withdrawable.checked = false; + reviews_stage.value = "0"; + reviews_visible_to_submitters.checked = false; + } + + function First_Round_Review() { + proposals_creatable.checked = false; + proposals_editable.checked = false; + proposals_withdrawable.checked = false; + reviews_stage.value = "1"; + reviews_visible_to_submitters.checked = false; + } + + function Modification_Stage() { + proposals_creatable.checked = false; + proposals_editable.checked = true; + proposals_withdrawable.checked = false; + reviews_stage.value = "0"; + reviews_visible_to_submitters.checked = true; + } + + function Second_Round_Review() { + proposals_creatable.checked = false; + proposals_editable.checked = false; + proposals_withdrawable.checked = false; + reviews_stage.value = "2"; + reviews_visible_to_submitters.checked = false; + } + + function Internal_Decision() { + proposals_creatable.checked = false; + proposals_editable.checked = false; + proposals_withdrawable.checked = false; + reviews_stage.value = "0"; + reviews_visible_to_submitters.checked = false; + } + + function Announcement_of_Acceptance() { + proposals_creatable.checked = false; + proposals_editable.checked = true; + proposals_withdrawable.checked = false; + reviews_stage.value = "0"; + reviews_visible_to_submitters.checked = true; + } - /* - Proposal Review Stage Setting - Reference : https://github.com/pycontw/pycon.tw/blob/master/src/reviews/README.md - */ - function Call_for_Proposals(){ - proposals_creatable.checked = true; - proposals_editable.checked = true; - proposals_withdrawable.checked = true; - reviews_stage.value = "0"; - reviews_visible_to_submitters.checked = false; - } - function Locked() { - proposals_creatable.checked = false; - proposals_editable.checked = false; - proposals_withdrawable.checked = false; - reviews_stage.value = "0"; - reviews_visible_to_submitters.checked = false; - } - function First_Round_Review() { - proposals_creatable.checked = false; - proposals_editable.checked = false; - proposals_withdrawable.checked = false; - reviews_stage.value = "1"; - reviews_visible_to_submitters.checked = false; - } - function Modification_Stage() { - proposals_creatable.checked = false; - proposals_editable.checked = true; - proposals_withdrawable.checked = false; - reviews_stage.value = "0"; - reviews_visible_to_submitters.checked = true; - } - function Second_Round_Review() { - proposals_creatable.checked = false; - proposals_editable.checked = false; - proposals_withdrawable.checked = false; - reviews_stage.value = "2"; - reviews_visible_to_submitters.checked = false; - } - function Internal_Decision() { - proposals_creatable.checked = false; - proposals_editable.checked = false; - proposals_withdrawable.checked = false; - reviews_stage.value = "0"; - reviews_visible_to_submitters.checked = false; - } - function Announcement_of_Acceptance() { - proposals_creatable.checked = false; - proposals_editable.checked = true; - proposals_withdrawable.checked = false; - reviews_stage.value = "0"; - reviews_visible_to_submitters.checked = true; - } - }); diff --git a/src/templates/default/reviews/review_stages.html b/src/templates/default/reviews/review_stages.html index 3427d22b8..57e49aa7c 100644 --- a/src/templates/default/reviews/review_stages.html +++ b/src/templates/default/reviews/review_stages.html @@ -35,7 +35,7 @@

    {% trans 'Set Review Stage' %}


    {% for rs in review_stages_list %} - + {% endfor %} @@ -51,7 +51,7 @@

    {% trans 'Set Review Stage' %}

  • {{ ".proposals.creatable"|configuration_switch }}
    - +
    @@ -59,7 +59,7 @@

    {% trans 'Set Review Stage' %}

  • {{ ".proposals.editable"|configuration_switch }}
    - +
    @@ -67,7 +67,7 @@

    {% trans 'Set Review Stage' %}

  • {{ ".proposals.withdrawable"|configuration_switch }}
    - +
    @@ -75,9 +75,9 @@

    {% trans 'Set Review Stage' %}

  • {{ ".reviews.visible.to.submitters"|configuration_switch }}
    - + + type="checkbox" value="true"/>
  • @@ -85,14 +85,14 @@

    {% trans 'Set Review Stage' %}

    {{ ".reviews.stage"|configuration_switch }}
    + placeholder="Int" required="required">

  • {{ ".proposals.disable.after"|configuration_switch }}
    - +
  • @@ -100,7 +100,7 @@

    {% trans 'Set Review Stage' %}

    @@ -124,11 +124,17 @@

    {% trans 'Set Review Stage' %}

    {% compress js %} {% endcompress %} {% endblock extra_js %} From d73d206f493800ff4b5e6295ddb58ff60de0a003 Mon Sep 17 00:00:00 2001 From: tomatoprinx Date: Sun, 21 Jul 2024 01:47:31 +0800 Subject: [PATCH 24/30] Update panel font color for user experience --- src/static/css/vendors/bootstrap/_panels.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/static/css/vendors/bootstrap/_panels.scss b/src/static/css/vendors/bootstrap/_panels.scss index be9410f5b..d2c65b749 100755 --- a/src/static/css/vendors/bootstrap/_panels.scss +++ b/src/static/css/vendors/bootstrap/_panels.scss @@ -15,6 +15,7 @@ // Panel contents .panel-body { padding: $panel-body-padding; + color: black; @include clearfix; } @@ -33,8 +34,7 @@ .panel-title { margin-top: 0; margin-bottom: 0; - font-size: ceil(($font-size-base * 1.125)); - color: inherit; + color: black; > a, > small, From 007022adb421254134ef01ec405f62b75f1c527e Mon Sep 17 00:00:00 2001 From: tomatoprinx Date: Sun, 21 Jul 2024 01:49:39 +0800 Subject: [PATCH 25/30] Update message files for translations --- src/locale/en_US/LC_MESSAGES/django.po | 37 ++++++++++++++++----- src/locale/zh_Hant/LC_MESSAGES/django.po | 41 +++++++++++------------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/locale/en_US/LC_MESSAGES/django.po b/src/locale/en_US/LC_MESSAGES/django.po index a402e1d86..6f617f9f9 100644 --- a/src/locale/en_US/LC_MESSAGES/django.po +++ b/src/locale/en_US/LC_MESSAGES/django.po @@ -13,7 +13,7 @@ msgid "" msgstr "" "Project-Id-Version: PyCon TW\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-21 07:48+0800\n" +"POT-Creation-Date: 2024-07-20 15:33+0800\n" "PO-Revision-Date: 2022-07-11 02:23+0800\n" "Last-Translator: Tom Chen \n" "Language-Team: English (United States) (http://www.transifex.com/pycon-" @@ -1563,6 +1563,14 @@ msgstr "Change Password" msgid "Reviews" msgstr "Reviews" +#: templates/default/_includes/dashboard_tablist.html:28 +#: templates/default/reviews/review_stages.html:16 +#: templates/default/reviews/review_stages.html:44 +#, fuzzy +#| msgid "Reviews" +msgid "Review Stages" +msgstr "Reviews" + #: templates/default/_includes/nav/dashboard_nav.html:10 msgid "Log out" msgstr "Log out" @@ -1791,6 +1799,7 @@ msgstr "Change Log In Password" #: templates/default/registration/password_change_form.html:22 #: templates/default/reviews/review_form.html:101 +#: templates/default/reviews/review_stages.html:114 msgid "Submit" msgstr "Submit" @@ -2010,6 +2019,18 @@ msgstr "My Previous Reviews" msgid "Review Proposal" msgstr "Review Proposal" +#: templates/default/reviews/review_stages.html:23 +#, fuzzy +#| msgid "Current Review Stage: %(review_stage)s" +msgid "Current Review Stage Setting" +msgstr "Current Review Stage: %(review_stage)s" + +#: templates/default/reviews/review_stages.html:35 +#, fuzzy +#| msgid "Personal Review Stats" +msgid "Set Review Stage" +msgstr "Personal Review Stats" + #: templates/default/reviews/talk_proposal_list.html:14 #, python-format msgid "Current Review Stage: %(review_stage)s" @@ -5108,28 +5129,28 @@ msgstr "latest agreed CoC version" msgid "agreed at" msgstr "agreed at" -#: users/views.py:44 +#: users/views.py:48 msgid "Sign up successful. You are now logged in." msgstr "Sign up successful. You are now logged in." -#: users/views.py:61 +#: users/views.py:65 msgid "Email verification successful." msgstr "Email verification successful." -#: users/views.py:73 +#: users/views.py:77 #, python-brace-format msgid "A verification email has been sent to {email}" msgstr "A verification email has been sent to {email}" -#: users/views.py:103 +#: users/views.py:107 msgid "Your profile has been updated successfully." msgstr "Your profile has been updated successfully." -#: users/views.py:116 +#: users/views.py:120 msgid "Your new password has been applied successfully." msgstr "Your new password has been applied successfully." -#: users/views.py:123 +#: users/views.py:127 msgid "" "An email is sent to your email account. Please check your inbox for furthur " "instructions to reset your password." @@ -5137,7 +5158,7 @@ msgstr "" "An email is sent to your email account. Please check your inbox for furthur " "instructions to reset your password." -#: users/views.py:131 +#: users/views.py:135 msgid "Password reset successful. You can now login." msgstr "Password reset successful. You can now login." diff --git a/src/locale/zh_Hant/LC_MESSAGES/django.po b/src/locale/zh_Hant/LC_MESSAGES/django.po index d65786fdb..90a41f541 100644 --- a/src/locale/zh_Hant/LC_MESSAGES/django.po +++ b/src/locale/zh_Hant/LC_MESSAGES/django.po @@ -20,7 +20,7 @@ msgid "" msgstr "" "Project-Id-Version: PyCon TW\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-21 07:48+0800\n" +"POT-Creation-Date: 2024-07-20 15:33+0800\n" "PO-Revision-Date: 2022-07-11 02:25+0800\n" "Last-Translator: Tom Chen \n" "Language-Team: Chinese Traditional (http://www.transifex.com/pycon-taiwan/" @@ -1517,23 +1517,11 @@ msgid "Reviews" msgstr "審查" #: templates/default/_includes/dashboard_tablist.html:28 -#: templates/default/reviews/review_stages.html:12 -#: templates/default/reviews/review_stages.html:18 +#: templates/default/reviews/review_stages.html:16 +#: templates/default/reviews/review_stages.html:44 msgid "Review Stages" msgstr "審查階段" -#: templates/default/_includes/dashboard_tablist.html:28 -#: templates/default/reviews/review_stages.html:12 -#: templates/default/reviews/review_stages.html:18 -msgid "Current Review Stage Setting" -msgstr "目前審查階段設定" - -#: templates/default/_includes/dashboard_tablist.html:28 -#: templates/default/reviews/review_stages.html:12 -#: templates/default/reviews/review_stages.html:18 -msgid "Set Review Stage" -msgstr "設定審查階段" - #: templates/default/_includes/nav/dashboard_nav.html:10 msgid "Log out" msgstr "登出" @@ -1757,6 +1745,7 @@ msgstr "更改密碼" #: templates/default/registration/password_change_form.html:22 #: templates/default/reviews/review_form.html:101 +#: templates/default/reviews/review_stages.html:114 msgid "Submit" msgstr "送出" @@ -1970,6 +1959,14 @@ msgstr "我之前的審查意見" msgid "Review Proposal" msgstr "審查提案" +#: templates/default/reviews/review_stages.html:23 +msgid "Current Review Stage Setting" +msgstr "目前審查階段設定" + +#: templates/default/reviews/review_stages.html:35 +msgid "Set Review Stage" +msgstr "設定審查階段" + #: templates/default/reviews/talk_proposal_list.html:14 #, python-format msgid "Current Review Stage: %(review_stage)s" @@ -5001,35 +4998,35 @@ msgstr "最後同意的 CoC 版本" msgid "agreed at" msgstr "同意於" -#: users/views.py:44 +#: users/views.py:48 msgid "Sign up successful. You are now logged in." msgstr "註冊成功。您現在已被登入。" -#: users/views.py:61 +#: users/views.py:65 msgid "Email verification successful." msgstr "Email 認證成功。" -#: users/views.py:73 +#: users/views.py:77 #, python-brace-format msgid "A verification email has been sent to {email}" msgstr "一封認證用的 email 已經寄送至 {email}" -#: users/views.py:103 +#: users/views.py:107 msgid "Your profile has been updated successfully." msgstr "您的講者資訊已成功地更新。" -#: users/views.py:116 +#: users/views.py:120 msgid "Your new password has been applied successfully." msgstr "已成功地使用您的新密碼。" -#: users/views.py:123 +#: users/views.py:127 msgid "" "An email is sent to your email account. Please check your inbox for furthur " "instructions to reset your password." msgstr "" "一封電子郵件已經發送至您的信箱。請檢查您的收件匣並參照信中指示重設密碼。" -#: users/views.py:131 +#: users/views.py:135 msgid "Password reset successful. You can now login." msgstr "密碼重設成功。您現在即可登入。" From ef2e0452c7be14c8b84da52d7e71051c66aa6bac Mon Sep 17 00:00:00 2001 From: tomatoprinx Date: Sun, 21 Jul 2024 23:11:13 +0800 Subject: [PATCH 26/30] Fix ruff check errors --- src/proposals/templatetags/proposals.py | 7 ++++--- src/reviews/views.py | 11 ++++++----- src/users/urls.py | 1 - src/users/views.py | 4 ---- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/proposals/templatetags/proposals.py b/src/proposals/templatetags/proposals.py index dedb8990b..d24ee2aa3 100644 --- a/src/proposals/templatetags/proposals.py +++ b/src/proposals/templatetags/proposals.py @@ -1,5 +1,6 @@ -from django.template import Library from django.conf import settings +from django.template import Library + from proposals.utils import SEP_DEFAULT, SEP_LAST, format_names register = Library() @@ -7,11 +8,11 @@ @register.filter def speaker_names_display( - proposal, sep_default=SEP_DEFAULT, sep_last=SEP_LAST): + proposal, sep_default=SEP_DEFAULT, sep_last=SEP_LAST): names = [info.user.speaker_name for info in proposal.speakers] return format_names(names, sep_default=sep_default, sep_last=sep_last) @register.filter def configuration_switch(value): - return settings.CONFERENCE_DEFAULT_SLUG + value \ No newline at end of file + return settings.CONFERENCE_DEFAULT_SLUG + value diff --git a/src/reviews/views.py b/src/reviews/views.py index 082d312ae..784cf617f 100644 --- a/src/reviews/views.py +++ b/src/reviews/views.py @@ -4,7 +4,6 @@ import random import pytz -from core.utils import SequenceQuerySet from django.conf import settings from django.conf.global_settings import DATETIME_INPUT_FORMATS from django.contrib import messages @@ -14,9 +13,11 @@ from django.shortcuts import render from django.urls import reverse from django.views.generic import ListView, UpdateView -from proposals.models import TalkProposal from registry.helper import reg +from core.utils import SequenceQuerySet +from proposals.models import TalkProposal + from .context import reviews_state from .forms import ReviewForm from .models import REVIEW_REQUIRED_PERMISSIONS, Review, TalkProposalSnapshot @@ -394,12 +395,12 @@ def update_current_review_stages_setting(tag, value, current_review_stages_setti current_review_stages_setting[tag] = value -def date_preprocess(DATETIME_INPUT_FORMATS, value): +def date_preprocess(datetime_input_format, value): # Add defined datetime formatx - DATETIME_INPUT_FORMATS += ['%Y-%m-%dT%H:%M:%S', '%Y-%m-%dT%H:%M'] + datetime_input_format += ['%Y-%m-%dT%H:%M:%S', '%Y-%m-%dT%H:%M'] value = value.strip() # Try to strptime against each input format. - for format in DATETIME_INPUT_FORMATS: + for format in datetime_input_format: try: return datetime.datetime.strptime(value, format) except (ValueError, TypeError): diff --git a/src/users/urls.py b/src/users/urls.py index 2a49cfa82..63b9d6636 100644 --- a/src/users/urls.py +++ b/src/users/urls.py @@ -1,5 +1,4 @@ from django.conf.urls import url -from django.contrib.auth import views as auth from django.urls import path from . import views diff --git a/src/users/views.py b/src/users/views.py index a3c88df8e..6d53b914b 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -25,10 +25,6 @@ UserProfileUpdateForm, ) from .models import CocRecord -from reviews.context import proposals_state, reviews_state - -from lxml import etree -import lxml.html User = auth.get_user_model() From 8b9d274b8b394122e1f251cdf98cf016e45f3929 Mon Sep 17 00:00:00 2001 From: tomatoprinx Date: Sun, 21 Jul 2024 23:25:50 +0800 Subject: [PATCH 27/30] Fix element id --- src/templates/default/reviews/review_stages.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/templates/default/reviews/review_stages.html b/src/templates/default/reviews/review_stages.html index 57e49aa7c..40c0e4f1a 100644 --- a/src/templates/default/reviews/review_stages.html +++ b/src/templates/default/reviews/review_stages.html @@ -91,7 +91,7 @@

    {% trans 'Set Review Stage' %}

  • {{ ".proposals.disable.after"|configuration_switch }}
    -
  • From 1edd88c4fc6273fe4f378e6e7488f89830c7ac50 Mon Sep 17 00:00:00 2001 From: tomatoprinx Date: Mon, 16 Sep 2024 16:07:00 +0800 Subject: [PATCH 28/30] Add test method for configuration_switch --- src/proposals/tests/test_templatetags.py | 31 +++++++++++++++++++ .../default/reviews/review_stages.html | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/proposals/tests/test_templatetags.py b/src/proposals/tests/test_templatetags.py index 97ba79818..0dc2de2f5 100644 --- a/src/proposals/tests/test_templatetags.py +++ b/src/proposals/tests/test_templatetags.py @@ -53,3 +53,34 @@ def test_speaker_names_display(talk_proposals, parser): """) assert actual == expected + +@pytest.fixture +def review_stage_keys(): + review_stage_keys = [ + '.proposals.creatable', '.proposals.editable', '.proposals.withdrawable', + '.reviews.visible.to.submitters', '.reviews.stage', + '.proposals.disable.after' + ] + return review_stage_keys + +def test_configuration_switch(review_stage_keys, parser): + result = render_template( + '{% load proposals %}' + '
      ' + '{% for review_stage_key in proposals %}' + '
    • {{ review_stage_key|configuration_switch }}
    • ' + '{% endfor %}' + '
    ', {'proposals': review_stage_keys}, + ) + actual = parser.arrange(parser.parse(text=result, create_parent=False)) + expected = parser.arrange(""" +
      +
    • pycontw-2021.proposals.creatable
    • +
    • pycontw-2021.proposals.editable
    • +
    • pycontw-2021.proposals.withdrawable
    • +
    • pycontw-2021.reviews.visible.to.submitters
    • +
    • pycontw-2021.reviews.stage
    • +
    • pycontw-2021.proposals.disable.after
    • +
    + """) + assert actual == expected diff --git a/src/templates/default/reviews/review_stages.html b/src/templates/default/reviews/review_stages.html index 40c0e4f1a..d47929ff3 100644 --- a/src/templates/default/reviews/review_stages.html +++ b/src/templates/default/reviews/review_stages.html @@ -23,7 +23,7 @@

    {% trans 'Current Review Stage Setting' %}
    • - {{ ".proposals.proposals.disable.after"|configuration_switch }} + {{ ".proposals.disable.after"|configuration_switch }}

      {{ current_review_stages_setting.proposals_disable_after }}

      From 978f2f6fc6de458e8f81665cd7e5e46bb065c6ce Mon Sep 17 00:00:00 2001 From: tomatoprinx Date: Sat, 4 Jan 2025 14:44:13 +0800 Subject: [PATCH 29/30] add test for review stages --- src/reviews/{tests.py => tests/__init__.py} | 0 src/reviews/tests/test_views.py | 84 +++++++++++++++++++++ 2 files changed, 84 insertions(+) rename src/reviews/{tests.py => tests/__init__.py} (100%) create mode 100644 src/reviews/tests/test_views.py diff --git a/src/reviews/tests.py b/src/reviews/tests/__init__.py similarity index 100% rename from src/reviews/tests.py rename to src/reviews/tests/__init__.py diff --git a/src/reviews/tests/test_views.py b/src/reviews/tests/test_views.py new file mode 100644 index 000000000..03b9651c0 --- /dev/null +++ b/src/reviews/tests/test_views.py @@ -0,0 +1,84 @@ +from unittest.mock import patch + +import pytest +from django.conf import settings +from django.contrib.messages import get_messages +from django.urls import reverse + + +@pytest.fixture +def review_stages_url(): + return reverse('review_stages') + +@pytest.mark.django_db +def test_review_stages_get(client, review_stages_url): + response = client.get(review_stages_url) + + assert response.status_code == 200 + assert 'review_stages_list' in response.context + assert 'current_review_stages_setting' in response.context + +@pytest.mark.django_db +@patch('reviews.views.reg') +@patch('reviews.views.messages') +def test_review_stages_post_valid_data(mock_messages, mock_reg, client, review_stages_url): + mock_reg.get.return_value = '' + mock_reg.__setitem__.side_effect = lambda key, value: None + + post_data = { + 'proposals.creatable': 'True', + 'proposals.editable': 'True', + 'proposals.withdrawable': 'True', + 'reviews.visible.to.submitters': 'True', + 'reviews.stage': '1', + 'proposals.disable.after': '2024-12-31T12:00', + 'review_timezone': 'UTC', + } + + response = client.post(review_stages_url, post_data) + + assert response.status_code == 200 + mock_messages.info.assert_called_once_with( + response.wsgi_request, 'This setting has been changed successfully.' + ) + +@pytest.mark.django_db +@patch('reviews.views.reg') +@patch('reviews.views.messages') +def test_review_stages_post_invalid_date(mock_messages, mock_reg, client, review_stages_url): + post_data = { + 'proposals.creatable': 'True', + 'proposals.editable': 'True', + 'proposals.withdrawable': 'True', + 'reviews.visible.to.submitters': 'True', + 'reviews.stage': '1', + 'proposals.disable.after': 'invalid-date', + 'review_timezone': '', + } + + response = client.post(review_stages_url, post_data) + + assert response.status_code == 200 + mock_messages.error.assert_called_once_with( + response.wsgi_request, 'Please input valid date format : " + "%Y-%m-%dT%H:%M' + ) + +@pytest.mark.django_db +def test_review_stages_timezone_conversion(client, review_stages_url): + post_data = { + 'proposals.creatable': 'True', + 'proposals.editable': 'True', + 'proposals.withdrawable': 'True', + 'reviews.visible.to.submitters': 'True', + 'reviews.stage': '1', + 'proposals.disable.after': '2024-12-31T12:00', + 'review_timezone': 'Asia/Taipei', + } + + with patch('reviews.views.pytz.timezone') as mock_timezone: + mock_timezone.return_value.localize.return_value.strftime.return_value = '2024-12-31 12:00:00-0500' + response = client.post(review_stages_url, post_data) + + assert response.status_code == 200 + assert mock_timezone.call_count == 1 + assert mock_timezone.called_with('Asia/Taipei') From e8e0e82c0432862ab5e04708e81967bc2ec6501b Mon Sep 17 00:00:00 2001 From: tomatoprinx Date: Sat, 4 Jan 2025 14:55:37 +0800 Subject: [PATCH 30/30] fix ruff check --- src/reviews/tests/test_views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/reviews/tests/test_views.py b/src/reviews/tests/test_views.py index 03b9651c0..6a837c77e 100644 --- a/src/reviews/tests/test_views.py +++ b/src/reviews/tests/test_views.py @@ -1,8 +1,6 @@ from unittest.mock import patch import pytest -from django.conf import settings -from django.contrib.messages import get_messages from django.urls import reverse