当然,包含的徽章……很不错。它们没有任何问题。但是,如果你想要更多呢?如果你想_超越预定义的符号集_呢?当然,有一个管理页面可以让你上传它们。但是如果你想制作大量的徽章呢?
好消息!你可以通过 API 来实现。这里是用 Python 代码展示它是如何工作的。(而且它最后还会授予徽章,以防万一。)
即使你不是 Python 程序员,这段代码也应该很容易阅读。如果你愿意,甚至可以用 curl 在命令行中复制它。
这期望你的 API 密钥存在于名为 DISCOURSE_API_KEY 的环境变量中。
#!/usr/bin/python3
import os # 用于读取环境变量
import sys # 用于退出。:)
import hashlib # 用于图像哈希
import requests # 完成所有实际工作
# 站点和认证信息
DISCOURSE = "discussion.fedoraproject.org"
DISCOURSE_API_USER = "mattdm"
DISCOURSE_API_KEY = os.getenv("DISCOURSE_API_KEY")
if not DISCOURSE_API_KEY:
print(f"错误:DISCOURSE_API_KEY 必须在环境变量中设置", file=sys.stderr)
sys.exit(2)
# 你的徽章信息。假设在实际使用中你不会硬编码这些。
NAME = "Apex"
IMAGE = "apex.png"
DESCRIPTION = "FPL 的祝福"
MORE = "你很棒,大家都应该知道!"
TARGET_USER = "mattdm"
# 我们的认证头,来自上面。
HEADERS = {'Api-Key': DISCOURSE_API_KEY, 'Api-Username': DISCOURSE_API_USER}
# 从这里,你可以获取徽章组的 ID 和描述,以及
# 各种徽章类型。如果你愿意的话。此示例不使用它们。
r = requests.get(f"https://{DISCOURSE}/admin/badges.json", headers=HEADERS)
if r.status_code != 200:
print(f"获取徽章列表时出错:收到 {r.status_code}", file=sys.stderr)
sys.exit(1)
# 检查名称是否已存在。
# 可能有更好的方法来做到这一点,但这足够了。
if NAME in list(map(lambda x: x['name'], r.json()['badges'])):
print(f"错误:徽章 '{NAME}' 已存在。")
sys.exit(3)
# 读取图像。在实际代码中,你应该在这里进行更好的错误处理!
with open(IMAGE, "rb") as f:
image_data = f.read()
# 在这里进行一些关于
# 图像文件大小/尺寸的健全性检查可能比较好....
# 但无论如何,组装一个关于它的信息包以供上传。
# 这里唯一棘手的事情是获取图像校验和。
file_info = {'file_name': f'{IMAGE}',
'file_size': f'{len(image_data)}',
'type': 'badge_image',
'metadata[sha1-checksum]': hashlib.sha1(image_data).hexdigest(),
}
# 并询问 Discourse 将其发送到何处。
r = requests.post(
f"https://{DISCOURSE}/uploads/generate-presigned-put", json=file_info, headers=HEADERS)
if r.status_code != 200:
print(
f"询问图像上传位置时出错:收到 {r.status_code}", file=sys.stderr)
sys.exit(1)
upload_url = r.json()['url']
upload_uid = r.json()['unique_identifier']
# 现在将其放到我们被告知的地方。
r = requests.put(upload_url, data=image_data)
if r.status_code != 200:
print(
f"上传图像到外部存储时出错:收到 {r.status_code}", file=sys.stderr)
sys.exit(1)
# 并告诉 Discourse 已成功,并获取一个稍后可以引用的 ID。
r = requests.post(f"https://{DISCOURSE}/uploads/complete-external-upload",
data=f'unique_identifier={upload_uid}', headers=HEADERS)
if r.status_code != 200:
print(f"完成上传时出错:收到 {r.status_code}", file=sys.stderr)
sys.exit(1)
image_id = r.json()['id']
# 注意:如果你想使用 Font Awesome,请将 `image_upload_id` 留空,
# 并将 `icon` 设置为相应的 Font Awesome 名称。当然,
# 在这种情况下,你可以跳过所有图像上传的东西!
badge = {'allow_title': 'true',
'multiple_grant': 'false',
'listable': 'true',
'show_posts': 'false',
'target_posts': 'false',
'name': f'{NAME}',
'description': f'{DESCRIPTION}',
'long_description': f'{DESCRIPTION} {MORE}',
'image_upload_id': f'{image_id}',
'badge_grouping_id': '5',
'badge_type_id': '1',
}
r = requests.post(
f"https://{DISCOURSE}/admin/badges.json", json=badge, headers=HEADERS)
if r.status_code != 200:
print(f"创建徽章时出错:收到 {r.status_code}", file=sys.stderr)
sys.exit(1)
badge_id = r.json()['badge']['id']
print(f'徽章 "{NAME}: {DESCRIPTION}" 已创建,ID 为 {badge_id}!')
# 并为了完整起见,授予徽章!
# 你还可以添加一个“原因”,它必须链接到一个帖子或主题。
bestow = {'username': f"{TARGET_USER}", 'badge_id': f'{badge_id}'}
r = requests.post(f"https://{DISCOURSE}/user_badges",
json=bestow, headers=HEADERS)
if r.status_code != 200:
print(f"授予徽章时出错:收到 {r.status_code}", file=sys.stderr)
sys.exit(1)
print(f'用户 {TARGET_USER} 已获得新徽章!')