From 2bdf7b64d64b40308e64a09b9a215494813c446d Mon Sep 17 00:00:00 2001 From: Kevin Chung Date: Wed, 24 Jul 2019 01:44:20 -0400 Subject: [PATCH] Fix place ordinal calculation (#1067) * Fix scoreboard place ordinalization in Python 3 * Extract ordinalization code to `CTFd.utils.humanize.numbers.ordinalize`. --- CTFd/models/__init__.py | 20 +++++++++----------- CTFd/utils/humanize/__init__.py | 0 CTFd/utils/humanize/numbers.py | 6 ++++++ tests/utils/test_humanize.py | 19 +++++++++++++++++++ 4 files changed, 34 insertions(+), 11 deletions(-) create mode 100644 CTFd/utils/humanize/__init__.py create mode 100644 CTFd/utils/humanize/numbers.py create mode 100644 tests/utils/test_humanize.py diff --git a/CTFd/models/__init__.py b/CTFd/models/__init__.py index a40c66e..5dee907 100644 --- a/CTFd/models/__init__.py +++ b/CTFd/models/__init__.py @@ -3,6 +3,7 @@ from flask_marshmallow import Marshmallow from sqlalchemy.orm import validates, column_property from sqlalchemy.ext.hybrid import hybrid_property from CTFd.utils.crypto import hash_password +from CTFd.utils.humanize.numbers import ordinalize from CTFd.cache import cache import datetime import six @@ -349,14 +350,11 @@ class Users(db.Model): standings = get_user_standings(admin=admin) - # http://codegolf.stackexchange.com/a/4712 try: - i = standings.index((self.id,)) + 1 + n = standings.index((self.id,)) + 1 if numeric: - return i - else: - k = i % 10 - return "%d%s" % (i, "tsnrhtdd"[(i / 10 % 10 != 1) * (k < 4) * k :: 4]) + return n + return ordinalize(n) except ValueError: return None @@ -469,7 +467,7 @@ class Teams(db.Model): score += member.get_score(admin=admin) return score - def get_place(self, admin=False): + def get_place(self, admin=False, numeric=False): """ This method is generally a clone of CTFd.scoreboard.get_standings. The point being that models.py must be self-reliant and have little @@ -480,11 +478,11 @@ class Teams(db.Model): standings = get_team_standings(admin=admin) - # http://codegolf.stackexchange.com/a/4712 try: - i = standings.index((self.id,)) + 1 - k = i % 10 - return "%d%s" % (i, "tsnrhtdd"[(i / 10 % 10 != 1) * (k < 4) * k :: 4]) + n = standings.index((self.id,)) + 1 + if numeric: + return n + return ordinalize(n) except ValueError: return None diff --git a/CTFd/utils/humanize/__init__.py b/CTFd/utils/humanize/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/CTFd/utils/humanize/numbers.py b/CTFd/utils/humanize/numbers.py new file mode 100644 index 0000000..ae4a418 --- /dev/null +++ b/CTFd/utils/humanize/numbers.py @@ -0,0 +1,6 @@ +def ordinalize(n): + """ + http://codegolf.stackexchange.com/a/4712 + """ + k = n % 10 + return "%d%s" % (n, "tsnrhtdd"[(n // 10 % 10 != 1) * (k < 4) * k :: 4]) diff --git a/tests/utils/test_humanize.py b/tests/utils/test_humanize.py new file mode 100644 index 0000000..2119488 --- /dev/null +++ b/tests/utils/test_humanize.py @@ -0,0 +1,19 @@ +from CTFd.utils.humanize.numbers import ordinalize + + +def test_ordinalize(): + tests = { + 1: "1st", + 2: "2nd", + 3: "3rd", + 4: "4th", + 11: "11th", + 12: "12th", + 13: "13th", + 101: "101st", + 102: "102nd", + 103: "103rd", + 111: "111th", + } + for t, v in tests.items(): + assert ordinalize(t) == v