| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703 |
- package controller
- import (
- "fmt"
- "net/http"
- "strconv"
- "time"
- "github.com/bytedance/sonic"
- "github.com/gin-gonic/gin"
- "github.com/labring/aiproxy/core/common/network"
- "github.com/labring/aiproxy/core/controller/utils"
- "github.com/labring/aiproxy/core/middleware"
- "github.com/labring/aiproxy/core/model"
- )
- // TokenResponse represents the response structure for token endpoints
- type TokenResponse struct {
- *model.Token
- AccessedAt time.Time `json:"accessed_at"`
- }
- func (t *TokenResponse) MarshalJSON() ([]byte, error) {
- type Alias TokenResponse
- return sonic.Marshal(&struct {
- *Alias
- CreatedAt int64 `json:"created_at"`
- PeriodLastUpdateTime int64 `json:"period_last_update_time"`
- AccessedAt int64 `json:"accessed_at"`
- }{
- Alias: (*Alias)(t),
- CreatedAt: t.CreatedAt.UnixMilli(),
- PeriodLastUpdateTime: t.PeriodLastUpdateTime.UnixMilli(),
- AccessedAt: t.AccessedAt.UnixMilli(),
- })
- }
- type (
- AddTokenRequest struct {
- Name string `json:"name"`
- Subnets []string `json:"subnets"`
- Models []string `json:"models"`
- Quota float64 `json:"quota"`
- PeriodQuota float64 `json:"period_quota"`
- PeriodType string `json:"period_type"`
- PeriodLastUpdateTime int64 `json:"period_last_update_time"`
- }
- UpdateTokenStatusRequest struct {
- Status int `json:"status"`
- }
- UpdateTokenNameRequest struct {
- Name string `json:"name"`
- }
- )
- func (at *AddTokenRequest) ToToken() *model.Token {
- token := &model.Token{
- Name: model.EmptyNullString(at.Name),
- Subnets: at.Subnets,
- Models: at.Models,
- Quota: at.Quota,
- PeriodQuota: at.PeriodQuota,
- PeriodType: model.EmptyNullString(at.PeriodType),
- }
- if at.PeriodLastUpdateTime > 0 {
- token.PeriodLastUpdateTime = time.UnixMilli(at.PeriodLastUpdateTime)
- }
- return token
- }
- func validateToken(token AddTokenRequest) error {
- if err := network.IsValidSubnets(token.Subnets); err != nil {
- return fmt.Errorf("invalid subnet: %w", err)
- }
- return nil
- }
- func validateSubnets(subnets []string) error {
- if err := network.IsValidSubnets(subnets); err != nil {
- return fmt.Errorf("invalid subnet: %w", err)
- }
- return nil
- }
- func buildTokenResponse(token *model.Token) *TokenResponse {
- lastRequestAt, _ := model.GetGroupTokenLastRequestTimeMinute(token.GroupID, string(token.Name))
- return &TokenResponse{
- Token: token,
- AccessedAt: lastRequestAt,
- }
- }
- func buildTokenResponses(tokens []*model.Token) []*TokenResponse {
- responses := make([]*TokenResponse, len(tokens))
- for i, token := range tokens {
- responses[i] = buildTokenResponse(token)
- }
- return responses
- }
- // GetTokens godoc
- //
- // @Summary Get all tokens
- // @Description Returns a paginated list of all tokens
- // @Tags tokens
- // @Produce json
- // @Security ApiKeyAuth
- // @Param page query int false "Page number"
- // @Param per_page query int false "Items per page"
- // @Param group query string false "Group name"
- // @Param order query string false "Order"
- // @Param status query int false "Status"
- // @Success 200 {object} middleware.APIResponse{data=map[string]any{tokens=[]TokenResponse,total=int}}
- // @Router /api/tokens/ [get]
- func GetTokens(c *gin.Context) {
- page, perPage := utils.ParsePageParams(c)
- group := c.Query("group")
- order := c.Query("order")
- status, _ := strconv.Atoi(c.Query("status"))
- tokens, total, err := model.GetTokens(group, page, perPage, order, status)
- if err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, gin.H{
- "tokens": buildTokenResponses(tokens),
- "total": total,
- })
- }
- // GetGroupTokens godoc
- //
- // @Summary Get all tokens for a specific group
- // @Description Returns a paginated list of all tokens for a specific group
- // @Tags tokens
- // @Produce json
- // @Security ApiKeyAuth
- // @Param group path string true "Group name"
- // @Param page query int false "Page number"
- // @Param per_page query int false "Items per page"
- // @Param order query string false "Order"
- // @Param status query int false "Status"
- // @Success 200 {object} middleware.APIResponse{data=map[string]any{tokens=[]TokenResponse,total=int}}
- // @Router /api/tokens/{group} [get]
- func GetGroupTokens(c *gin.Context) {
- group := c.Param("group")
- if group == "" {
- middleware.ErrorResponse(c, http.StatusBadRequest, "group is required")
- return
- }
- page, perPage := utils.ParsePageParams(c)
- order := c.Query("order")
- status, _ := strconv.Atoi(c.Query("status"))
- tokens, total, err := model.GetTokens(group, page, perPage, order, status)
- if err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, gin.H{
- "tokens": buildTokenResponses(tokens),
- "total": total,
- })
- }
- // SearchTokens godoc
- //
- // @Summary Search tokens
- // @Description Returns a paginated list of tokens based on search criteria
- // @Tags tokens
- // @Produce json
- // @Security ApiKeyAuth
- // @Param keyword query string false "Keyword"
- // @Param page query int false "Page number"
- // @Param per_page query int false "Items per page"
- // @Param order query string false "Order"
- // @Param name query string false "Name"
- // @Param key query string false "Key"
- // @Param status query int false "Status"
- // @Param group query string false "Group"
- // @Success 200 {object} middleware.APIResponse{data=map[string]any{tokens=[]TokenResponse,total=int}}
- // @Router /api/tokens/search [get]
- func SearchTokens(c *gin.Context) {
- page, perPage := utils.ParsePageParams(c)
- keyword := c.Query("keyword")
- order := c.Query("order")
- name := c.Query("name")
- key := c.Query("key")
- status, _ := strconv.Atoi(c.Query("status"))
- group := c.Query("group")
- tokens, total, err := model.SearchTokens(
- group,
- keyword,
- page,
- perPage,
- order,
- status,
- name,
- key,
- )
- if err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, gin.H{
- "tokens": buildTokenResponses(tokens),
- "total": total,
- })
- }
- // SearchGroupTokens godoc
- //
- // @Summary Search tokens for a specific group
- // @Description Returns a paginated list of tokens for a specific group based on search criteria
- // @Tags token
- // @Produce json
- // @Security ApiKeyAuth
- // @Param group path string true "Group name"
- // @Param keyword query string false "Keyword"
- // @Param page query int false "Page number"
- // @Param per_page query int false "Items per page"
- // @Param order query string false "Order"
- // @Param name query string false "Name"
- // @Param key query string false "Key"
- // @Param status query int false "Status"
- // @Success 200 {object} middleware.APIResponse{data=map[string]any{tokens=[]TokenResponse,total=int}}
- // @Router /api/token/{group}/search [get]
- func SearchGroupTokens(c *gin.Context) {
- group := c.Param("group")
- if group == "" {
- middleware.ErrorResponse(c, http.StatusBadRequest, "group is required")
- return
- }
- page, perPage := utils.ParsePageParams(c)
- keyword := c.Query("keyword")
- order := c.Query("order")
- name := c.Query("name")
- key := c.Query("key")
- status, _ := strconv.Atoi(c.Query("status"))
- tokens, total, err := model.SearchGroupTokens(
- group,
- keyword,
- page,
- perPage,
- order,
- status,
- name,
- key,
- )
- if err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, gin.H{
- "tokens": buildTokenResponses(tokens),
- "total": total,
- })
- }
- // GetToken godoc
- //
- // @Summary Get token by ID
- // @Description Returns detailed information about a specific token
- // @Tags tokens
- // @Produce json
- // @Security ApiKeyAuth
- // @Param id path int true "Token ID"
- // @Success 200 {object} middleware.APIResponse{data=TokenResponse}
- // @Router /api/tokens/{id} [get]
- func GetToken(c *gin.Context) {
- id, err := strconv.Atoi(c.Param("id"))
- if err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- token, err := model.GetTokenByID(id)
- if err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, buildTokenResponse(token))
- }
- // GetGroupToken godoc
- //
- // @Summary Get token by ID for a specific group
- // @Description Returns detailed information about a specific token for a specific group
- // @Tags token
- // @Produce json
- // @Security ApiKeyAuth
- // @Param group path string true "Group name"
- // @Param id path int true "Token ID"
- // @Success 200 {object} middleware.APIResponse{data=TokenResponse}
- // @Router /api/token/{group}/{id} [get]
- func GetGroupToken(c *gin.Context) {
- group := c.Param("group")
- if group == "" {
- middleware.ErrorResponse(c, http.StatusBadRequest, "group is required")
- return
- }
- id, err := strconv.Atoi(c.Param("id"))
- if err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- token, err := model.GetGroupTokenByID(group, id)
- if err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, buildTokenResponse(token))
- }
- // AddGroupToken godoc
- //
- // @Summary Add group token
- // @Description Adds a new token to a specific group
- // @Tags token
- // @Accept json
- // @Produce json
- // @Security ApiKeyAuth
- // @Param group path string true "Group name"
- // @Param auto_create_group query bool false "Auto create group"
- // @Param ignore_exist query bool false "Ignore exist"
- // @Param token body AddTokenRequest true "Token information"
- // @Success 200 {object} middleware.APIResponse{data=TokenResponse}
- // @Router /api/token/{group} [post]
- func AddGroupToken(c *gin.Context) {
- group := c.Param("group")
- var req AddTokenRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- if err := validateToken(req); err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, "parameter error: "+err.Error())
- return
- }
- token := req.ToToken()
- token.GroupID = group
- if err := model.InsertToken(token, c.Query("auto_create_group") == "true", c.Query("ignore_exist") == "true"); err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, &TokenResponse{Token: token})
- }
- // DeleteToken godoc
- //
- // @Summary Delete token
- // @Description Deletes a specific token by ID
- // @Tags tokens
- // @Produce json
- // @Security ApiKeyAuth
- // @Param id path int true "Token ID"
- // @Success 200 {object} middleware.APIResponse
- // @Router /api/tokens/{id} [delete]
- func DeleteToken(c *gin.Context) {
- id, err := strconv.Atoi(c.Param("id"))
- if err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- if err := model.DeleteTokenByID(id); err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, nil)
- }
- // DeleteTokens godoc
- //
- // @Summary Delete multiple tokens
- // @Description Deletes multiple tokens by their IDs
- // @Tags tokens
- // @Accept json
- // @Produce json
- // @Security ApiKeyAuth
- // @Param ids body []int true "Token IDs"
- // @Success 200 {object} middleware.APIResponse
- // @Router /api/tokens/batch_delete [post]
- func DeleteTokens(c *gin.Context) {
- var ids []int
- if err := c.ShouldBindJSON(&ids); err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- if err := model.DeleteTokensByIDs(ids); err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, nil)
- }
- // DeleteGroupToken godoc
- //
- // @Summary Delete group token
- // @Description Deletes a specific token from a group
- // @Tags token
- // @Produce json
- // @Security ApiKeyAuth
- // @Param group path string true "Group name"
- // @Param id path int true "Token ID"
- // @Success 200 {object} middleware.APIResponse
- // @Router /api/token/{group}/{id} [delete]
- func DeleteGroupToken(c *gin.Context) {
- group := c.Param("group")
- id, err := strconv.Atoi(c.Param("id"))
- if err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- if err := model.DeleteGroupTokenByID(group, id); err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, nil)
- }
- // DeleteGroupTokens godoc
- //
- // @Summary Delete group tokens
- // @Description Deletes multiple tokens from a specific group
- // @Tags token
- // @Produce json
- // @Security ApiKeyAuth
- // @Param group path string true "Group name"
- // @Param ids body []int true "Token IDs"
- // @Success 200 {object} middleware.APIResponse
- // @Router /api/token/{group}/batch_delete [post]
- func DeleteGroupTokens(c *gin.Context) {
- group := c.Param("group")
- var ids []int
- if err := c.ShouldBindJSON(&ids); err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- if err := model.DeleteGroupTokensByIDs(group, ids); err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, nil)
- }
- // UpdateToken godoc
- //
- // @Summary Update token
- // @Description Updates an existing token's information
- // @Tags tokens
- // @Accept json
- // @Produce json
- // @Security ApiKeyAuth
- // @Param id path int true "Token ID"
- // @Param token body model.UpdateTokenRequest true "Updated token information"
- // @Success 200 {object} middleware.APIResponse{data=TokenResponse}
- // @Router /api/tokens/{id} [put]
- func UpdateToken(c *gin.Context) {
- id, err := strconv.Atoi(c.Param("id"))
- if err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- var req model.UpdateTokenRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- if req.Subnets != nil {
- if err := validateSubnets(*req.Subnets); err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, "parameter error: "+err.Error())
- return
- }
- }
- token, err := model.UpdateToken(id, req)
- if err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, &TokenResponse{Token: token})
- }
- // UpdateGroupToken godoc
- //
- // @Summary Update group token
- // @Description Updates an existing token in a specific group
- // @Tags token
- // @Accept json
- // @Produce json
- // @Security ApiKeyAuth
- // @Param group path string true "Group name"
- // @Param id path int true "Token ID"
- // @Param token body model.UpdateTokenRequest true "Updated token information"
- // @Success 200 {object} middleware.APIResponse{data=TokenResponse}
- // @Router /api/token/{group}/{id} [put]
- func UpdateGroupToken(c *gin.Context) {
- group := c.Param("group")
- id, err := strconv.Atoi(c.Param("id"))
- if err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- var req model.UpdateTokenRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- if req.Subnets != nil {
- if err := validateSubnets(*req.Subnets); err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, "parameter error: "+err.Error())
- return
- }
- }
- token, err := model.UpdateGroupToken(id, group, req)
- if err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, &TokenResponse{Token: token})
- }
- // UpdateTokenStatus godoc
- //
- // @Summary Update token status
- // @Description Updates the status of a specific token
- // @Tags tokens
- // @Accept json
- // @Produce json
- // @Security ApiKeyAuth
- // @Param id path int true "Token ID"
- // @Param status body UpdateTokenStatusRequest true "Status information"
- // @Success 200 {object} middleware.APIResponse
- // @Router /api/tokens/{id}/status [post]
- func UpdateTokenStatus(c *gin.Context) {
- id, err := strconv.Atoi(c.Param("id"))
- if err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- var req UpdateTokenStatusRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- if err := model.UpdateTokenStatus(id, req.Status); err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, nil)
- }
- // UpdateGroupTokenStatus godoc
- //
- // @Summary Update group token status
- // @Description Updates the status of a token in a specific group
- // @Tags token
- // @Accept json
- // @Produce json
- // @Security ApiKeyAuth
- // @Param group path string true "Group name"
- // @Param id path int true "Token ID"
- // @Param status body UpdateTokenStatusRequest true "Status information"
- // @Success 200 {object} middleware.APIResponse
- // @Router /api/token/{group}/{id}/status [post]
- func UpdateGroupTokenStatus(c *gin.Context) {
- group := c.Param("group")
- id, err := strconv.Atoi(c.Param("id"))
- if err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- var req UpdateTokenStatusRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- if err := model.UpdateGroupTokenStatus(group, id, req.Status); err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, nil)
- }
- // UpdateTokenName godoc
- //
- // @Summary Update token name
- // @Description Updates the name of a specific token
- // @Tags tokens
- // @Accept json
- // @Produce json
- // @Security ApiKeyAuth
- // @Param id path int true "Token ID"
- // @Param name body UpdateTokenNameRequest true "Name information"
- // @Success 200 {object} middleware.APIResponse
- // @Router /api/tokens/{id}/name [post]
- func UpdateTokenName(c *gin.Context) {
- id, err := strconv.Atoi(c.Param("id"))
- if err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- var req UpdateTokenNameRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- if err := model.UpdateTokenName(id, req.Name); err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, nil)
- }
- // UpdateGroupTokenName godoc
- //
- // @Summary Update group token name
- // @Description Updates the name of a token in a specific group
- // @Tags token
- // @Accept json
- // @Produce json
- // @Security ApiKeyAuth
- // @Param group path string true "Group name"
- // @Param id path int true "Token ID"
- // @Param name body UpdateTokenNameRequest true "Name information"
- // @Success 200 {object} middleware.APIResponse
- // @Router /api/token/{group}/{id}/name [post]
- func UpdateGroupTokenName(c *gin.Context) {
- group := c.Param("group")
- id, err := strconv.Atoi(c.Param("id"))
- if err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- var req UpdateTokenNameRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- middleware.ErrorResponse(c, http.StatusBadRequest, err.Error())
- return
- }
- if err := model.UpdateGroupTokenName(group, id, req.Name); err != nil {
- middleware.ErrorResponse(c, http.StatusInternalServerError, err.Error())
- return
- }
- middleware.SuccessResponse(c, nil)
- }
|