feat: expose account registration, login and admin recovery over HTTP

This commit is contained in:
DiheChen committed 2026-11-08 22:01:12 +08:00
1 parent d8a79e8bc8
commit 4c75a5c609
17 files changed
+1453 -51

No files matched your search

+118
View File
@@ -10,6 +10,8 @@ import (
var (
patternAdminCreateRoomRequestSlug = regexp.MustCompile(`^[a-z0-9-]{1,32}$`)
patternAdminUpdateRoomRequestSlug = regexp.MustCompile(`^[a-z0-9-]{0,32}$`)
patternLoginRequestUsername = regexp.MustCompile(`^[a-z0-9_-]{3,32}$`)
patternRegisterRequestUsername = regexp.MustCompile(`^[a-z0-9_-]{3,32}$`)
patternTrackIDWhenBilibili = regexp.MustCompile(`^BV[1-9A-HJ-NP-Za-km-z]{10}(?:/([2-9]|[1-9][0-9]{1,3}))?$`)
)
@@ -72,6 +74,18 @@ func DecodeUpdateMeRequest(body []byte) (UpdateMeRequest, error) {
return decodeUpdateMeRequest(body, "")
}
func DecodeRegisterRequest(body []byte) (RegisterRequest, error) {
return decodeRegisterRequest(body, "")
}
func DecodeChangePasswordRequest(body []byte) (ChangePasswordRequest, error) {
return decodeChangePasswordRequest(body, "")
}
func DecodeLoginRequest(body []byte) (LoginRequest, error) {
return decodeLoginRequest(body, "")
}
func DecodeCreateRoomRequest(body []byte) (CreateRoomRequest, error) {
return decodeCreateRoomRequest(body, "")
}
@@ -124,6 +138,14 @@ func DecodeAdminUpdateSiteRequest(body []byte) (AdminUpdateSiteRequest, error) {
return decodeAdminUpdateSiteRequest(body, "")
}
func DecodeAdminOpenRegistrationRequest(body []byte) (AdminOpenRegistrationRequest, error) {
return decodeAdminOpenRegistrationRequest(body, "")
}
func DecodeAdminResetAccountPasswordRequest(body []byte) (AdminResetAccountPasswordRequest, error) {
return decodeAdminResetAccountPasswordRequest(body, "")
}
func decodeAdminCheckBilibiliLoginRequest(raw json.RawMessage, path string) (AdminCheckBilibiliLoginRequest, error) {
var v AdminCheckBilibiliLoginRequest
m, err := decodeObject(raw, path, "key")
@@ -225,6 +247,18 @@ func decodeAdminCreateRoomRequest(raw json.RawMessage, path string) (AdminCreate
return v, nil
}
func decodeAdminOpenRegistrationRequest(raw json.RawMessage, path string) (AdminOpenRegistrationRequest, error) {
var v AdminOpenRegistrationRequest
_, err := decodeObject(raw, path)
return v, err
}
func decodeAdminResetAccountPasswordRequest(raw json.RawMessage, path string) (AdminResetAccountPasswordRequest, error) {
var v AdminResetAccountPasswordRequest
_, err := decodeObject(raw, path)
return v, err
}
func decodeAdminResetRoomApiKeyRequest(raw json.RawMessage, path string) (AdminResetRoomApiKeyRequest, error) {
var v AdminResetRoomApiKeyRequest
_, err := decodeObject(raw, path)
@@ -340,6 +374,36 @@ func decodeAdminUpdateSiteRequest(raw json.RawMessage, path string) (AdminUpdate
return v, nil
}
func decodeChangePasswordRequest(raw json.RawMessage, path string) (ChangePasswordRequest, error) {
var v ChangePasswordRequest
m, err := decodeObject(raw, path, "currentPassword", "newPassword")
if err != nil {
return v, err
}
if err = requireFields(m, path, "currentPassword", "newPassword"); err != nil {
return v, err
}
if v.CurrentPassword, err = decodeString(m["currentPassword"], field(path, "currentPassword")); err != nil {
return v, err
}
if err = checkMinLength(v.CurrentPassword, field(path, "currentPassword"), 8); err != nil {
return v, err
}
if err = checkMaxLength(v.CurrentPassword, field(path, "currentPassword"), 128); err != nil {
return v, err
}
if v.NewPassword, err = decodeString(m["newPassword"], field(path, "newPassword")); err != nil {
return v, err
}
if err = checkMinLength(v.NewPassword, field(path, "newPassword"), 8); err != nil {
return v, err
}
if err = checkMaxLength(v.NewPassword, field(path, "newPassword"), 128); err != nil {
return v, err
}
return v, nil
}
func decodeChatSendRequest(raw json.RawMessage, path string) (ChatSendRequest, error) {
var v ChatSendRequest
m, err := decodeObject(raw, path, "content")
@@ -432,6 +496,33 @@ func decodeHelloRequest(raw json.RawMessage, path string) (HelloRequest, error)
return v, nil
}
func decodeLoginRequest(raw json.RawMessage, path string) (LoginRequest, error) {
var v LoginRequest
m, err := decodeObject(raw, path, "password", "username")
if err != nil {
return v, err
}
if err = requireFields(m, path, "password", "username"); err != nil {
return v, err
}
if v.Password, err = decodeString(m["password"], field(path, "password")); err != nil {
return v, err
}
if err = checkMinLength(v.Password, field(path, "password"), 8); err != nil {
return v, err
}
if err = checkMaxLength(v.Password, field(path, "password"), 128); err != nil {
return v, err
}
if v.Username, err = decodeString(m["username"], field(path, "username")); err != nil {
return v, err
}
if err = checkPattern(v.Username, field(path, "username"), patternLoginRequestUsername); err != nil {
return v, err
}
return v, nil
}
func decodePingRequest(raw json.RawMessage, path string) (PingRequest, error) {
var v PingRequest
m, err := decodeObject(raw, path, "clientTimeMs")
@@ -583,6 +674,33 @@ func decodeRecommendListRequest(raw json.RawMessage, path string) (RecommendList
return v, err
}
func decodeRegisterRequest(raw json.RawMessage, path string) (RegisterRequest, error) {
var v RegisterRequest
m, err := decodeObject(raw, path, "password", "username")
if err != nil {
return v, err
}
if err = requireFields(m, path, "password", "username"); err != nil {
return v, err
}
if v.Password, err = decodeString(m["password"], field(path, "password")); err != nil {
return v, err
}
if err = checkMinLength(v.Password, field(path, "password"), 8); err != nil {
return v, err
}
if err = checkMaxLength(v.Password, field(path, "password"), 128); err != nil {
return v, err
}
if v.Username, err = decodeString(m["username"], field(path, "username")); err != nil {
return v, err
}
if err = checkPattern(v.Username, field(path, "username"), patternRegisterRequestUsername); err != nil {
return v, err
}
return v, nil
}
func decodeRoomSyncRequest(raw json.RawMessage, path string) (RoomSyncRequest, error) {
var v RoomSyncRequest
_, err := decodeObject(raw, path)
+171 -5
View File
@@ -12,6 +12,7 @@
"enum": [
"INVALID_ARGUMENT",
"UNAUTHORIZED",
"INVALID_CREDENTIALS",
"FORBIDDEN",
"NOT_FOUND",
"CONFLICT",
@@ -26,6 +27,7 @@
"x-httpStatus": {
"INVALID_ARGUMENT": 400,
"UNAUTHORIZED": 401,
"INVALID_CREDENTIALS": 401,
"FORBIDDEN": 403,
"NOT_FOUND": 404,
"CONFLICT": 409,
@@ -139,6 +141,34 @@
},
"required": ["id", "name", "avatarHash"]
},
"Username": {
"type": "string",
"description": "用户名:3 到 32 个小写字母、数字、下划线或连字符",
"pattern": "^[a-z0-9_-]{3,32}$"
},
"AccountPassword": {
"type": "string",
"description": "账号密码",
"minLength": 8,
"maxLength": 128
},
"Account": {
"type": "object",
"additionalProperties": false,
"properties": {
"username": {"type": "string"}
},
"required": ["username"]
},
"AdminAccount": {
"type": "object",
"additionalProperties": false,
"properties": {
"member": {"$ref": "#/$defs/Member"},
"username": {"type": "string"}
},
"required": ["member", "username"]
},
"Members": {
"type": "object",
"additionalProperties": false,
@@ -658,7 +688,7 @@
},
{
"name": "getMe",
"description": "当前成员的资料",
"description": "当前成员的资料;已注册的成员带上账号",
"method": "GET",
"path": "/api/me",
"auth": "member",
@@ -666,7 +696,8 @@
"type": "object",
"additionalProperties": false,
"properties": {
"member": {"$ref": "#/$defs/Member"}
"member": {"$ref": "#/$defs/Member"},
"account": {"$ref": "#/$defs/Account"}
},
"required": ["member"]
}
@@ -694,6 +725,91 @@
"required": ["member"]
}
},
{
"name": "register",
"description": "游客注册账号:设置用户名和密码,成员和成员 token 都不变;站点关闭注册时返回 FORBIDDEN",
"method": "POST",
"path": "/api/account",
"auth": "member",
"status": 201,
"request": {
"type": "object",
"additionalProperties": false,
"properties": {
"username": {"$ref": "#/$defs/Username"},
"password": {"$ref": "#/$defs/AccountPassword"}
},
"required": ["username", "password"]
},
"response": {
"type": "object",
"additionalProperties": false,
"properties": {
"account": {"$ref": "#/$defs/Account"}
},
"required": ["account"]
}
},
{
"name": "changePassword",
"description": "修改密码:账号在其他设备上的成员 token 随即失效,发出请求的这个不变;当前密码错误时返回 INVALID_CREDENTIALS",
"method": "PUT",
"path": "/api/account/password",
"auth": "member",
"status": 204,
"request": {
"type": "object",
"additionalProperties": false,
"properties": {
"currentPassword": {"$ref": "#/$defs/AccountPassword"},
"newPassword": {"$ref": "#/$defs/AccountPassword"}
},
"required": ["currentPassword", "newPassword"]
}
},
{
"name": "login",
"description": "游客登录账号:返回账号的新成员 token,发出请求的游客 token 随即失效;用户名或密码错误时返回 INVALID_CREDENTIALS,已经登录了账号时返回 CONFLICT",
"method": "POST",
"path": "/api/sessions",
"auth": "member",
"status": 201,
"request": {
"type": "object",
"additionalProperties": false,
"properties": {
"username": {"$ref": "#/$defs/Username"},
"password": {"$ref": "#/$defs/AccountPassword"}
},
"required": ["username", "password"]
},
"response": {
"type": "object",
"additionalProperties": false,
"properties": {
"memberToken": {"type": "string"},
"member": {"$ref": "#/$defs/Member"},
"account": {"$ref": "#/$defs/Account"}
},
"required": ["memberToken", "member", "account"]
}
},
{
"name": "logout",
"description": "退出登录:发出请求的成员 token 随即失效",
"method": "DELETE",
"path": "/api/sessions/current",
"auth": "member",
"status": 204
},
{
"name": "logoutOtherSessions",
"description": "退出其他设备:同一成员的其他成员 token 都失效,发出请求的这个不变",
"method": "DELETE",
"path": "/api/sessions/others",
"auth": "member",
"status": 204
},
{
"name": "listRooms",
"description": "房间列表",
@@ -769,7 +885,7 @@
},
{
"name": "getSite",
"description": "品牌名;没有设置过时是 Alisten",
"description": "品牌名和是否开放注册;没有设置过品牌名时是 Alisten",
"method": "GET",
"path": "/api/site",
"auth": "none",
@@ -777,9 +893,10 @@
"type": "object",
"additionalProperties": false,
"properties": {
"brandName": {"type": "string"}
"brandName": {"type": "string"},
"registrationOpen": {"type": "boolean"}
},
"required": ["brandName"]
"required": ["brandName", "registrationOpen"]
}
},
{
@@ -1097,6 +1214,55 @@
},
"required": ["brandName"]
}
},
{
"name": "adminOpenRegistration",
"description": "开放注册",
"method": "PUT",
"path": "/api/admin/registration",
"auth": "admin",
"status": 204,
"request": {
"type": "object",
"additionalProperties": false,
"properties": {}
}
},
{
"name": "adminCloseRegistration",
"description": "关闭注册:不能再注册新账号,已有账号照常登录,游客照常使用",
"method": "DELETE",
"path": "/api/admin/registration",
"auth": "admin",
"status": 204
},
{
"name": "adminGetAccount",
"description": "按用户名查找账号",
"method": "GET",
"path": "/api/admin/accounts/{username}",
"auth": "admin",
"response": {"$ref": "#/$defs/AdminAccount"}
},
{
"name": "adminResetAccountPassword",
"description": "重置账号的密码:生成随机的新密码,只在这次响应中返回;账号在所有设备上的成员 token 随即失效",
"method": "POST",
"path": "/api/admin/accounts/{username}/password",
"auth": "admin",
"request": {
"type": "object",
"additionalProperties": false,
"properties": {}
},
"response": {
"type": "object",
"additionalProperties": false,
"properties": {
"password": {"type": "string"}
},
"required": ["password"]
}
}
]
}
+487 -4
View File
@@ -14,6 +14,18 @@
],
"type": "object"
},
"Account": {
"additionalProperties": false,
"properties": {
"username": {
"type": "string"
}
},
"required": [
"username"
],
"type": "object"
},
"ActivityKind": {
"enum": [
"added",
@@ -25,6 +37,22 @@
],
"type": "string"
},
"AdminAccount": {
"additionalProperties": false,
"properties": {
"member": {
"$ref": "#/components/schemas/Member"
},
"username": {
"type": "string"
}
},
"required": [
"member",
"username"
],
"type": "object"
},
"AdminCheckBilibiliLoginRequest": {
"additionalProperties": false,
"properties": {
@@ -246,6 +274,26 @@
],
"type": "object"
},
"AdminOpenRegistrationRequest": {
"additionalProperties": false,
"type": "object"
},
"AdminResetAccountPasswordRequest": {
"additionalProperties": false,
"type": "object"
},
"AdminResetAccountPasswordResponse": {
"additionalProperties": false,
"properties": {
"password": {
"type": "string"
}
},
"required": [
"password"
],
"type": "object"
},
"AdminResetRoomApiKeyRequest": {
"additionalProperties": false,
"type": "object"
@@ -331,6 +379,28 @@
],
"type": "object"
},
"ChangePasswordRequest": {
"additionalProperties": false,
"properties": {
"currentPassword": {
"description": "账号密码",
"maxLength": 128,
"minLength": 8,
"type": "string"
},
"newPassword": {
"description": "账号密码",
"maxLength": 128,
"minLength": 8,
"type": "string"
}
},
"required": [
"currentPassword",
"newPassword"
],
"type": "object"
},
"ChatSendRequest": {
"additionalProperties": false,
"properties": {
@@ -479,6 +549,7 @@
"enum": [
"INVALID_ARGUMENT",
"UNAUTHORIZED",
"INVALID_CREDENTIALS",
"FORBIDDEN",
"NOT_FOUND",
"CONFLICT",
@@ -496,6 +567,7 @@
"FORBIDDEN": 403,
"INTERNAL": 500,
"INVALID_ARGUMENT": 400,
"INVALID_CREDENTIALS": 401,
"NOTHING_PLAYING": 409,
"NOT_FOUND": 404,
"PROVIDER_ERROR": 502,
@@ -537,6 +609,9 @@
"GetMeResponse": {
"additionalProperties": false,
"properties": {
"account": {
"$ref": "#/components/schemas/Account"
},
"member": {
"$ref": "#/components/schemas/Member"
}
@@ -551,10 +626,14 @@
"properties": {
"brandName": {
"type": "string"
},
"registrationOpen": {
"type": "boolean"
}
},
"required": [
"brandName"
"brandName",
"registrationOpen"
],
"type": "object"
},
@@ -573,6 +652,47 @@
],
"type": "object"
},
"LoginRequest": {
"additionalProperties": false,
"properties": {
"password": {
"description": "账号密码",
"maxLength": 128,
"minLength": 8,
"type": "string"
},
"username": {
"description": "用户名:3 到 32 个小写字母、数字、下划线或连字符",
"pattern": "^[a-z0-9_-]{3,32}$",
"type": "string"
}
},
"required": [
"username",
"password"
],
"type": "object"
},
"LoginResponse": {
"additionalProperties": false,
"properties": {
"account": {
"$ref": "#/components/schemas/Account"
},
"member": {
"$ref": "#/components/schemas/Member"
},
"memberToken": {
"type": "string"
}
},
"required": [
"memberToken",
"member",
"account"
],
"type": "object"
},
"Member": {
"additionalProperties": false,
"properties": {
@@ -892,6 +1012,39 @@
],
"type": "object"
},
"RegisterRequest": {
"additionalProperties": false,
"properties": {
"password": {
"description": "账号密码",
"maxLength": 128,
"minLength": 8,
"type": "string"
},
"username": {
"description": "用户名:3 到 32 个小写字母、数字、下划线或连字符",
"pattern": "^[a-z0-9_-]{3,32}$",
"type": "string"
}
},
"required": [
"username",
"password"
],
"type": "object"
},
"RegisterResponse": {
"additionalProperties": false,
"properties": {
"account": {
"$ref": "#/components/schemas/Account"
}
},
"required": [
"account"
],
"type": "object"
},
"RoomInfo": {
"additionalProperties": false,
"properties": {
@@ -1343,10 +1496,185 @@
},
"info": {
"title": "Alisten",
"version": "473ee31f5ef912b4"
"version": "812b22c0beac413d"
},
"openapi": "3.1.0",
"paths": {
"/api/account": {
"post": {
"operationId": "register",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RegisterRequest"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RegisterResponse"
}
}
},
"description": "成功"
},
"default": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "失败"
}
},
"security": [
{
"memberToken": []
}
],
"summary": "游客注册账号:设置用户名和密码,成员和成员 token 都不变;站点关闭注册时返回 FORBIDDEN"
}
},
"/api/account/password": {
"put": {
"operationId": "changePassword",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ChangePasswordRequest"
}
}
},
"required": true
},
"responses": {
"204": {
"description": "成功"
},
"default": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "失败"
}
},
"security": [
{
"memberToken": []
}
],
"summary": "修改密码:账号在其他设备上的成员 token 随即失效,发出请求的这个不变;当前密码错误时返回 INVALID_CREDENTIALS"
}
},
"/api/admin/accounts/{username}": {
"get": {
"operationId": "adminGetAccount",
"parameters": [
{
"in": "path",
"name": "username",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AdminAccount"
}
}
},
"description": "成功"
},
"default": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "失败"
}
},
"security": [
{
"adminToken": []
}
],
"summary": "按用户名查找账号"
}
},
"/api/admin/accounts/{username}/password": {
"post": {
"operationId": "adminResetAccountPassword",
"parameters": [
{
"in": "path",
"name": "username",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AdminResetAccountPasswordRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AdminResetAccountPasswordResponse"
}
}
},
"description": "成功"
},
"default": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "失败"
}
},
"security": [
{
"adminToken": []
}
],
"summary": "重置账号的密码:生成随机的新密码,只在这次响应中返回;账号在所有设备上的成员 token 随即失效"
}
},
"/api/admin/credentials/bilibili": {
"get": {
"operationId": "adminGetBilibiliCredential",
@@ -1864,6 +2192,66 @@
"summary": "删除一首已存储的歌的音频和封面,并清除它的准备结果"
}
},
"/api/admin/registration": {
"delete": {
"operationId": "adminCloseRegistration",
"responses": {
"204": {
"description": "成功"
},
"default": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "失败"
}
},
"security": [
{
"adminToken": []
}
],
"summary": "关闭注册:不能再注册新账号,已有账号照常登录,游客照常使用"
},
"put": {
"operationId": "adminOpenRegistration",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AdminOpenRegistrationRequest"
}
}
},
"required": true
},
"responses": {
"204": {
"description": "成功"
},
"default": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "失败"
}
},
"security": [
{
"adminToken": []
}
],
"summary": "开放注册"
}
},
"/api/admin/rooms": {
"get": {
"operationId": "adminListRooms",
@@ -2201,7 +2589,7 @@
"memberToken": []
}
],
"summary": "当前成员的资料"
"summary": "当前成员的资料;已注册的成员带上账号"
},
"patch": {
"operationId": "updateMe",
@@ -2973,6 +3361,101 @@
"summary": "按 UUID 或别名查找房间"
}
},
"/api/sessions": {
"post": {
"operationId": "login",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginRequest"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginResponse"
}
}
},
"description": "成功"
},
"default": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "失败"
}
},
"security": [
{
"memberToken": []
}
],
"summary": "游客登录账号:返回账号的新成员 token,发出请求的游客 token 随即失效;用户名或密码错误时返回 INVALID_CREDENTIALS,已经登录了账号时返回 CONFLICT"
}
},
"/api/sessions/current": {
"delete": {
"operationId": "logout",
"responses": {
"204": {
"description": "成功"
},
"default": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "失败"
}
},
"security": [
{
"memberToken": []
}
],
"summary": "退出登录:发出请求的成员 token 随即失效"
}
},
"/api/sessions/others": {
"delete": {
"operationId": "logoutOtherSessions",
"responses": {
"204": {
"description": "成功"
},
"default": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
},
"description": "失败"
}
},
"security": [
{
"memberToken": []
}
],
"summary": "退出其他设备:同一成员的其他成员 token 都失效,发出请求的这个不变"
}
},
"/api/site": {
"get": {
"operationId": "getSite",
@@ -2999,7 +3482,7 @@
}
},
"security": [],
"summary": "品牌名;没有设置过时是 Alisten"
"summary": "品牌名和是否开放注册;没有设置过品牌名时是 Alisten"
}
}
}
+81 -26
View File
@@ -4,12 +4,16 @@ package protocol
import "encoding/json"
const Version = "473ee31f5ef912b4"
const Version = "812b22c0beac413d"
type APIKey struct {
Key string `json:"key"`
}
type Account struct {
Username string `json:"username"`
}
type ActivityKind string
const (
@@ -21,6 +25,11 @@ const (
ActivityKindFailed ActivityKind = "failed"
)
type AdminAccount struct {
Member Member `json:"member"`
Username string `json:"username"`
}
type AdminCheckBilibiliLoginRequest struct {
Key string `json:"key"`
}
@@ -94,6 +103,14 @@ func (v AdminListRoomsResponse) MarshalJSON() ([]byte, error) {
return json.Marshal(plain(v))
}
type AdminOpenRegistrationRequest struct{}
type AdminResetAccountPasswordRequest struct{}
type AdminResetAccountPasswordResponse struct {
Password string `json:"password"`
}
type AdminResetRoomApiKeyRequest struct{}
type AdminSetYoutubeCredentialRequest struct {
@@ -123,6 +140,11 @@ type AdminUpdateSiteResponse struct {
BrandName string `json:"brandName"`
}
type ChangePasswordRequest struct {
CurrentPassword string `json:"currentPassword"`
NewPassword string `json:"newPassword"`
}
type ChatMessageEvent struct {
Content string `json:"content"`
Member Member `json:"member"`
@@ -180,18 +202,19 @@ const (
type ErrorCode string
const (
ErrorCodeInvalidArgument ErrorCode = "INVALID_ARGUMENT"
ErrorCodeUnauthorized ErrorCode = "UNAUTHORIZED"
ErrorCodeForbidden ErrorCode = "FORBIDDEN"
ErrorCodeNotFound ErrorCode = "NOT_FOUND"
ErrorCodeConflict ErrorCode = "CONFLICT"
ErrorCodeQueueFull ErrorCode = "QUEUE_FULL"
ErrorCodeNothingPlaying ErrorCode = "NOTHING_PLAYING"
ErrorCodeRateLimited ErrorCode = "RATE_LIMITED"
ErrorCodeProviderError ErrorCode = "PROVIDER_ERROR"
ErrorCodeUnavailable ErrorCode = "UNAVAILABLE"
ErrorCodeClientOutdated ErrorCode = "CLIENT_OUTDATED"
ErrorCodeInternal ErrorCode = "INTERNAL"
ErrorCodeInvalidArgument ErrorCode = "INVALID_ARGUMENT"
ErrorCodeUnauthorized ErrorCode = "UNAUTHORIZED"
ErrorCodeInvalidCredentials ErrorCode = "INVALID_CREDENTIALS"
ErrorCodeForbidden ErrorCode = "FORBIDDEN"
ErrorCodeNotFound ErrorCode = "NOT_FOUND"
ErrorCodeConflict ErrorCode = "CONFLICT"
ErrorCodeQueueFull ErrorCode = "QUEUE_FULL"
ErrorCodeNothingPlaying ErrorCode = "NOTHING_PLAYING"
ErrorCodeRateLimited ErrorCode = "RATE_LIMITED"
ErrorCodeProviderError ErrorCode = "PROVIDER_ERROR"
ErrorCodeUnavailable ErrorCode = "UNAVAILABLE"
ErrorCodeClientOutdated ErrorCode = "CLIENT_OUTDATED"
ErrorCodeInternal ErrorCode = "INTERNAL"
)
type ErrorInfo struct {
@@ -200,11 +223,13 @@ type ErrorInfo struct {
}
type GetMeResponse struct {
Member Member `json:"member"`
Account *Account `json:"account,omitempty"`
Member Member `json:"member"`
}
type GetSiteResponse struct {
BrandName string `json:"brandName"`
BrandName string `json:"brandName"`
RegistrationOpen bool `json:"registrationOpen"`
}
type HelloRequest struct {
@@ -231,6 +256,17 @@ func (v ListRoomsResponse) MarshalJSON() ([]byte, error) {
return json.Marshal(plain(v))
}
type LoginRequest struct {
Password string `json:"password"`
Username string `json:"username"`
}
type LoginResponse struct {
Account Account `json:"account"`
Member Member `json:"member"`
MemberToken string `json:"memberToken"`
}
type Member struct {
AvatarHash string `json:"avatarHash"`
ID string `json:"id"`
@@ -397,6 +433,15 @@ func (v RecommendListResponse) MarshalJSON() ([]byte, error) {
return json.Marshal(plain(v))
}
type RegisterRequest struct {
Password string `json:"password"`
Username string `json:"username"`
}
type RegisterResponse struct {
Account Account `json:"account"`
}
type RoomActivityEvent struct {
Entry *Entry `json:"entry,omitempty"`
Kind ActivityKind `json:"kind"`
@@ -609,6 +654,11 @@ var (
RouteCreateMember = Route{Pattern: "POST /api/members", Auth: AuthNone, Status: 201}
RouteGetMe = Route{Pattern: "GET /api/me", Auth: AuthMember, Status: 200}
RouteUpdateMe = Route{Pattern: "PATCH /api/me", Auth: AuthMember, Status: 200}
RouteRegister = Route{Pattern: "POST /api/account", Auth: AuthMember, Status: 201}
RouteChangePassword = Route{Pattern: "PUT /api/account/password", Auth: AuthMember, Status: 204}
RouteLogin = Route{Pattern: "POST /api/sessions", Auth: AuthMember, Status: 201}
RouteLogout = Route{Pattern: "DELETE /api/sessions/current", Auth: AuthMember, Status: 204}
RouteLogoutOtherSessions = Route{Pattern: "DELETE /api/sessions/others", Auth: AuthMember, Status: 204}
RouteListRooms = Route{Pattern: "GET /api/rooms", Auth: AuthNone, Status: 200}
RouteGetRoom = Route{Pattern: "GET /api/rooms/{ref}", Auth: AuthNone, Status: 200}
RouteCreateRoom = Route{Pattern: "POST /api/rooms", Auth: AuthNone, Status: 201, Location: true}
@@ -635,6 +685,10 @@ var (
RouteAdminListMedia = Route{Pattern: "GET /api/admin/media", Auth: AuthAdmin, Status: 200}
RouteAdminDeleteMedia = Route{Pattern: "DELETE /api/admin/media/{key}", Auth: AuthAdmin, Status: 204}
RouteAdminUpdateSite = Route{Pattern: "PATCH /api/admin/site", Auth: AuthAdmin, Status: 200}
RouteAdminOpenRegistration = Route{Pattern: "PUT /api/admin/registration", Auth: AuthAdmin, Status: 204}
RouteAdminCloseRegistration = Route{Pattern: "DELETE /api/admin/registration", Auth: AuthAdmin, Status: 204}
RouteAdminGetAccount = Route{Pattern: "GET /api/admin/accounts/{username}", Auth: AuthAdmin, Status: 200}
RouteAdminResetAccountPassword = Route{Pattern: "POST /api/admin/accounts/{username}/password", Auth: AuthAdmin, Status: 200}
)
var RoomRoutes = []RoomRoute{
@@ -652,17 +706,18 @@ var RoomRoutes = []RoomRoute{
}
var errorCodeHTTPStatus = map[ErrorCode]int{
ErrorCodeInvalidArgument: 400,
ErrorCodeUnauthorized: 401,
ErrorCodeForbidden: 403,
ErrorCodeNotFound: 404,
ErrorCodeConflict: 409,
ErrorCodeQueueFull: 409,
ErrorCodeNothingPlaying: 409,
ErrorCodeRateLimited: 429,
ErrorCodeProviderError: 502,
ErrorCodeUnavailable: 503,
ErrorCodeInternal: 500,
ErrorCodeInvalidArgument: 400,
ErrorCodeUnauthorized: 401,
ErrorCodeInvalidCredentials: 401,
ErrorCodeForbidden: 403,
ErrorCodeNotFound: 404,
ErrorCodeConflict: 409,
ErrorCodeQueueFull: 409,
ErrorCodeNothingPlaying: 409,
ErrorCodeRateLimited: 429,
ErrorCodeProviderError: 502,
ErrorCodeUnavailable: 503,
ErrorCodeInternal: 500,
}
// IDL 没有为某个取值指定 HTTP 状态码时返回 0。