diff --git a/rv_voting_calc/templates/rv_voting_calc/index.html b/rv_voting_calc/templates/rv_voting_calc/index.html index 919785c438075676bf560c5e24961ec3d0e4fdae..6e9ea05f9ffb0f0ba7d53053784f7cf466ffc24f 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 44de8e4893ef7a817d6e60c4238cae76e3921f21..b9353e87d4f6df207ba16bcd82faf659cea355b4 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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/rv_voting_calc/templatetags/index.py b/rv_voting_calc/templatetags/index.py new file mode 100644 index 0000000000000000000000000000000000000000..d20f7e2cdf360fcea86219b84130c7f5499efab5 --- /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 210acb746c162e90c4c636fba021754f3eac5e9b..d17426ae85e4c3e50ac0c6b9e35bb420e29a6e02 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",