Files
OnlineJudge/utils/shortcuts.py
yuetsh 927f235537 refactor: 移除邮件功能
发信能力整体下线,唯一的调用方(忘记密码)前端也从来没接过。

- utils/shortcuts.py 删 send_email,连带四个 django.core.mail 相关 import
- account/tasks.py 整个删除,里面只有 send_email_async 一个 actor
- 删 ApplyResetPasswordAPI / ResetPasswordAPI 及其路由、serializer,
  User.reset_password_token 和 reset_password_token_expire_time 两个
  字段(account/0010)
- 删 SMTPAPI / SMTPTestAPI 及其路由、三个 SMTP serializer、
  SysOptions.smtp_config
- account/templates/reset_password_email.html

options/0003 数据迁移删掉库里的 smtp_config 行:_init_option 会为每个
OptionKey 建行,key 从代码里去掉后它会变成孤儿,而且配过 SMTP 的话
value 里存着明文密码。

保留 ResetUserPasswordAPI(管理端直接重置密码,不发信,前端在用)和
User.email(注册要填)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 23:17:48 -06:00

76 lines
2.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import random
import re
from base64 import b64encode
from io import BytesIO
from django.utils.crypto import get_random_string
def rand_str(length=32, type="lower_hex"):
"""
生成指定长度的随机字符串或者数字, 可以用于密钥等安全场景
:param length: 字符串或者数字的长度
:param type: str 代表随机字符串num 代表随机数字
:return: 字符串
"""
if type == "str":
return get_random_string(length, allowed_chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
elif type == "lower_str":
return get_random_string(length, allowed_chars="abcdefghijklmnopqrstuvwxyz0123456789")
elif type == "lower_hex":
return random.choice("123456789abcdef") + get_random_string(length - 1, allowed_chars="0123456789abcdef")
else:
return random.choice("123456789") + get_random_string(length - 1, allowed_chars="0123456789")
def build_query_string(kv_data, ignore_none=True):
# {"a": 1, "b": "test"} -> "?a=1&b=test"
query_string = ""
for k, v in kv_data.items():
if ignore_none is True and kv_data[k] is None:
continue
if query_string != "":
query_string += "&"
else:
query_string = "?"
query_string += k + "=" + str(v)
return query_string
def img2base64(img):
with BytesIO() as buf:
img.save(buf, "gif")
buf_str = buf.getvalue()
img_prefix = "data:image/png;base64,"
b64_str = img_prefix + b64encode(buf_str).decode("utf-8")
return b64_str
def datetime2str(value, format="iso-8601"):
if format.lower() == "iso-8601":
value = value.isoformat()
if value.endswith("+00:00"):
value = value[:-6] + "Z"
return value
return value.strftime(format)
def natural_sort_key(s, _nsre=re.compile(r"(\d+)")):
return [int(text) if text.isdigit() else text.lower() for text in re.split(_nsre, s)]
def get_env(name, default=""):
return os.environ.get(name, default)
def DRAMATIQ_WORKER_ARGS(time_limit=3600_000, max_retries=0, max_age=7200_000):
return {"max_retries": max_retries, "time_limit": time_limit, "max_age": max_age}
def check_is_id(value):
try:
return int(value) > 0
except Exception:
return False