yearning
18 小时以前 e3e6db2d9974588f91ac1567a58fa4846655ce1b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import hashlib
import string
 
from sqlalchemy import select
from sqlalchemy.orm import Session
 
from app.models import ExaminationExamExaminee
 
_ALPHABET = string.digits + string.ascii_uppercase  # 0-9A-Z, 36 chars
 
 
def _to_base36(num: int, length: int) -> str:
    """将非负整数编码为定长 base36 字符串。"""
    chars: list[str] = []
    for _ in range(length):
        num, rem = divmod(num, 36)
        chars.append(_ALPHABET[rem])
    return "".join(reversed(chars))
 
 
def generate_student_no(examinee_id: int, exam_id: int) -> str:
    """根据考生ID + 考试ID 生成 10 位字母数字编码。"""
    raw = f"{examinee_id}:{exam_id}".encode()
    digest = hashlib.sha256(raw).digest()
    num = int.from_bytes(digest[:8], "big")
    return _to_base36(num, 10)
 
 
def ensure_student_no(db: Session, attempt: ExaminationExamExaminee) -> str:
    """获取或生成 attempt 的 student_no(幂等,已有则直接返回)。"""
    if attempt.student_no:
        return attempt.student_no
    code = generate_student_no(attempt.examinee_id, attempt.exam_id)
    # 极小概率碰撞时追加区分
    existing = db.scalar(
        select(ExaminationExamExaminee.id).where(
            ExaminationExamExaminee.student_no == code,
            ExaminationExamExaminee.id != attempt.id,
        )
    )
    if existing is not None:
        digest = hashlib.sha256(
            f"{attempt.examinee_id}:{attempt.exam_id}:{attempt.id}".encode()
        ).digest()
        code = _to_base36(int.from_bytes(digest[:8], "big"), 10)
    attempt.student_no = code
    db.flush()
    return code
 
 
def find_attempt_by_student_no(
    db: Session, student_no: str
) -> ExaminationExamExaminee | None:
    """通过编码反查答卷记录。"""
    return db.scalar(
        select(ExaminationExamExaminee).where(
            ExaminationExamExaminee.student_no == student_no.strip().upper()
        )
    )