Sakuten/backend

View on GitHub
cards/id.py

Summary

Maintainability
A
0 mins
Test Coverage
import json
import random
from secrets import token_urlsafe


max_public_id = 34991   # 6 ([3-79]) * 18 ([AC-HJ-NPRTW-Y]) * 18 * 18


encoder = "ACDEFGHJKLMNPRTWXY"


def encode_public_id(num_id):
    """
        make 4-letter ID from numeric ID
        Args:
            num_id (int): ID consisting of a number and 3 alphabets
        Return:
            str_id (str): encoded ID
    """
    def one_alpha(num):
        return encoder[num]

    def one_digit(num):
        return '9' if num == 5 else str(num + 3)

    latter_3_num = num_id // (18**3)
    letters = []
    for i in range(1, 4):
        data = num_id % (18**i) // 18**(i-1)
        letters.insert(0, data)
        sub = data * (18**(i-1))
        num_id -= sub
    return one_digit(latter_3_num) + ''.join(one_alpha(n) for n in letters)


def decode_public_id(str_id):
    """
        make numeric ID from 4-letter ID
        Args:
            str_id (str): ID consisting of a number and 3 alphabets
        Return:
            num_id (int): numeric ID
    """
    def alpha2num(c):
        return encoder.find(c)

    def num2num(c):
        return 5 if c == '9' else int(c) - 3

    alphas = [alpha2num(c) for c in str_id[1:]]
    alphas.insert(0, num2num(str_id[0]))
    return sum(alphas[i] * 18**(3-i) for i in range(4))


def generate_ids(for_admin, for_checkers, for_students, for_visitors):
    """
        generate a list of dictionaries that have IDs,
        authority and kind
        return the generated IDs for the use in making
        QR codes
        Args:
            for_admin (int): number of IDs for admin
            for_checkers (int): number of IDs for
            for_students (int): number of IDs for
            for_visitors (int): number of IDs for
        Return:
            secret_ids (list): all generated IDs
    """
    public_raw_ids = random.sample(
        range(max_public_id + 1),
        for_admin + for_checkers + for_students + for_visitors)

    def given_auth_kind(num, auth, kind):
        nonlocal public_raw_ids
        public_ids = public_raw_ids[:num]
        public_raw_ids = public_raw_ids[num:]
        secret_ids = [token_urlsafe(24) for _ in range(num)]
        return [{
                "secret_id": secret,
                "public_id": encode_public_id(public),
                "authority": auth,
                "kind": kind
                }
                for (secret, public) in zip(secret_ids, public_ids)]

    return ( given_auth_kind(for_admin, "admin", "admin")           # noqa
           + given_auth_kind(for_checkers, "checker", "checker")    # noqa
           + given_auth_kind(for_students, "normal", "student")     # noqa
           + given_auth_kind(for_visitors, "normal", "visitor")     # noqa
           )                                                        # noqa


def save_id_json_file(json_path, id_dicts):
    """
        create a new JSON file and save the given IDs
        Args:
            json_path (str): where to create a JSON file
    """
    with open(json_path, 'w') as f:
        json.dump(id_dicts, f, indent=4)


def load_id_json_file(json_path):
    """
        load the JSON file and get the data inside
        all this function does is to call json.load(f)
        inside a with statement
        Args:
            json_path (str): where the target JSON file is
        Return:
            ID list (list): all the data found in the file
    """
    with open(json_path, 'r') as f:
        return json.load(f)