From 67e4d137b68d991803277cdde0867992e14c8183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1?= <git@imaniti.org> Date: Fri, 27 Jan 2023 10:14:37 +0100 Subject: [PATCH] figure out popular options and move votes, finish initial sorting --- .../templates/rv_voting_calc/index.html | 7 +- .../rv_voting_calc/steps/initial_sort.html | 29 ++++++- rv_voting_calc/templatetags/__init__.py | 0 rv_voting_calc/templatetags/index.py | 10 +++ rv_voting_calc/views.py | 84 +++++++++++++++---- 5 files changed, 108 insertions(+), 22 deletions(-) create mode 100644 rv_voting_calc/templatetags/__init__.py create mode 100644 rv_voting_calc/templatetags/index.py diff --git a/rv_voting_calc/templates/rv_voting_calc/index.html b/rv_voting_calc/templates/rv_voting_calc/index.html index 919785c..6e9ea05 100644 --- a/rv_voting_calc/templates/rv_voting_calc/index.html +++ b/rv_voting_calc/templates/rv_voting_calc/index.html @@ -43,9 +43,12 @@ {% endfor %} </ul> - <div id="result"> + <ul + class="flex flex-col gap-3" + id="result" + > - </div> + </ul> </div> </main> diff --git a/rv_voting_calc/templates/rv_voting_calc/steps/initial_sort.html b/rv_voting_calc/templates/rv_voting_calc/steps/initial_sort.html index 44de8e4..b9353e8 100644 --- a/rv_voting_calc/templates/rv_voting_calc/steps/initial_sort.html +++ b/rv_voting_calc/templates/rv_voting_calc/steps/initial_sort.html @@ -1,3 +1,28 @@ -CIRNO CHIRUMIRU +{% load index %} -{{ options }} +<li class="bg-gray-100 drop-shadow-md p-4"> + <div class="pb-2 mb-2 border-b border-gray-300"> + <h2 class="text-2xl font-semibold font-bebas">Počáteční rozdělení</h2> + <small class="text-sm"> + <strong>{{ total_ticket_count }}</strong> lístků, + hranice pro nadpoloviční podporu <strong>{{ has_support_treshold }}</strong> + </small> + </div> + + {% for option_key, option in options.items %} + <h3 class="text-xl font-semibold">{{ option_key }}</h3> + + <ul class="flex gap-2"> + {% for vote in option.votes %} + <li class="bg-gray-200 px-3 py-2"> + {{ vote.member }} + <ul class="flex gap-1"> + {% for option in options_by_member|index:vote.member %} + <li>{{ option }}{% if not forloop.last %}, {% endif %}</li> + {% endfor %} + </ul> + </li> + {% endfor %} + </ul> + {% endfor %} +</li> diff --git a/rv_voting_calc/templatetags/__init__.py b/rv_voting_calc/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rv_voting_calc/templatetags/index.py b/rv_voting_calc/templatetags/index.py new file mode 100644 index 0000000..d20f7e2 --- /dev/null +++ b/rv_voting_calc/templatetags/index.py @@ -0,0 +1,10 @@ +from django import template +register = template.Library() + +# https://stackoverflow.com/a/29664945 +# Thanks to WeizhongTu and Bakuutin! + + +@register.filter +def index(indexable, i): + return indexable[i] diff --git a/rv_voting_calc/views.py b/rv_voting_calc/views.py index 210acb7..d17426a 100644 --- a/rv_voting_calc/views.py +++ b/rv_voting_calc/views.py @@ -124,6 +124,7 @@ def get_calculated_votes(request): options = {} total_ticket_count = len(options_by_member) # 1 member = 1 ticket + has_support_treshold = math.ceil(total_ticket_count * 0.5) + 1 max_vote_position = 0 for member, selected_options in options_by_member.items(): @@ -144,7 +145,7 @@ def get_calculated_votes(request): options[option]["votes"].append({ "position": position, - "member": member + "member": member, }) if option_is_ticket: @@ -154,18 +155,6 @@ def get_calculated_votes(request): option_is_ticket = False - steps.append( - render_to_string( - "rv_voting_calc/steps/initial_sort.html", - { - "options": options, - "options_by_member": options_by_member, - "rv_members": rv_members - }, - request=request, - ) - ) - # END Sorting # BEGIN Filtering out options without enough support and figuring out @@ -176,7 +165,7 @@ def get_calculated_votes(request): for option_key, option in options.items(): if ( (option["vote_count"] + option["ticket_count"]) - >= math.ceil(total_ticket_count * 0.5) + >= has_support_treshold ): option["has_support"] = True @@ -193,15 +182,74 @@ def get_calculated_votes(request): + 1 ) - for option_key in options_to_remove: - options.pop(option_key) - options = { key: value for key, value - in sorted(options.items(), key=lambda option: option[1]["points"]) + in sorted( + options.items(), + reverse=True, + key=lambda option: option[1]["points"], + ) } + for option in options.values(): + votes_to_remove = [] + + for vote_list_position, vote in enumerate(option["votes"]): + if vote.get("was_moved", False): + continue + + for other_acceptable_option_position, other_acceptable_option in ( + enumerate(options_by_member[vote["member"]]) + ): + if not options[other_acceptable_option]["has_support"]: + continue + + if ( + other_acceptable_option_position >= vote["position"] + and option["has_support"] + ): + break + + already_voted_for_acceptable_option = False + + for other_acceptable_option_vote in options[other_acceptable_option]["votes"]: + if other_acceptable_option_vote["member"] == vote["member"]: + already_voted_for_acceptable_option = True + + if already_voted_for_acceptable_option: + votes_to_remove.append(vote_list_position) + break + + vote["was_moved"] = True + options[other_acceptable_option]["votes"].append(vote) + + break + + index_offset = 0 + + for vote_list_position in votes_to_remove: + option["votes"].pop(vote_list_position - index_offset) + + index_offset += 1 + + steps.append( + render_to_string( + "rv_voting_calc/steps/initial_sort.html", + { + "options": options, + "options_by_member": options_by_member, + "rv_members": rv_members, + "total_ticket_count": total_ticket_count, + "has_support_treshold": has_support_treshold + }, + request=request, + ) + ) + + for option_key in options_to_remove: + options.pop(option_key) + steps.append( render_to_string( "rv_voting_calc/steps/with_support.html", -- GitLab