package controller import ( "errors" "net/http" "strconv" "github.com/QuantumNous/new-api/common" "github.com/QuantumNous/new-api/model" user_migration "github.com/QuantumNous/new-api/service/user_migration" "github.com/gin-gonic/gin" ) func ListMigrationUsers(c *gin.Context) { page, _ := strconv.Atoi(c.DefaultQuery("page", "0")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "50")) if pageSize <= 0 || pageSize > 200 { pageSize = 50 } users, total, err := model.ListLocalUsersForMigration(page, pageSize) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "database error"}) return } snapshots := make([]user_migration.RemoteUserSnapshot, 0, len(users)) for _, user := range users { bindings, _ := model.GetUserOAuthBindingsByUserId(user.Id) snapshots = append(snapshots, buildRemoteUserSnapshot(user, bindings)) } c.JSON(http.StatusOK, gin.H{"success": true, "data": snapshots, "total": total}) } func GetMigrationUser(c *gin.Context) { userId, err := strconv.Atoi(c.Param("id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "invalid user id"}) return } user, err := model.GetUserById(userId, true) if err != nil || user == nil { c.JSON(http.StatusNotFound, gin.H{"success": false, "error": "user not found"}) return } if user.Role == common.RoleRootUser { c.JSON(http.StatusNotFound, gin.H{"success": false, "error": "user not found"}) return } bindings, _ := model.GetUserOAuthBindingsByUserId(userId) c.JSON(http.StatusOK, gin.H{"success": true, "data": buildRemoteUserSnapshot(user, bindings)}) } func ConvertMigrationUserToSynced(c *gin.Context) { userId, err := strconv.Atoi(c.Param("id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "invalid user id"}) return } var req user_migration.ConvertRemoteUserRequest if err := c.ShouldBindJSON(&req); err != nil || req.RemoteUserId == 0 { c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "invalid request body"}) return } if err := model.ConvertUserToSynced(userId, req.RemoteUserId, req.SyncedQuota); err != nil { if errors.Is(err, model.ErrConvertRootUserToSynced) || errors.Is(err, model.ErrSyncedUserRemoteUserIDImmutable) { c.JSON(http.StatusConflict, gin.H{"success": false, "error": err.Error()}) return } c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"success": true}) } func CheckSyncedCopy(c *gin.Context) { cnUserId, err := strconv.Atoi(c.Query("cn_user_id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "invalid cn_user_id"}) return } hasCopy, err := model.HasOVSyncedCopyByRemoteId(cnUserId) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"success": true, "has_copy": hasCopy}) } func buildRemoteUserSnapshot(user *model.User, bindings []*model.UserOAuthBinding) user_migration.RemoteUserSnapshot { snapshot := user_migration.RemoteUserSnapshot{ Id: user.Id, Username: user.Username, Password: user.Password, Email: user.Email, DisplayName: user.DisplayName, Status: user.Status, Role: user.Role, Group: user.Group, Quota: user.Quota, AffCode: user.AffCode, CreatedAt: user.CreatedAt, Setting: user.Setting, GitHubId: user.GitHubId, DiscordId: user.DiscordId, OidcId: user.OidcId, WeChatId: user.WeChatId, TelegramId: user.TelegramId, LinuxDOId: user.LinuxDOId, Source: user.Source, RemoteUserId: user.RemoteUserId, SyncedQuota: user.SyncedQuota, } for _, binding := range bindings { provider, err := model.GetCustomOAuthProviderById(binding.ProviderId) if err != nil { continue } snapshot.OAuthBindings = append(snapshot.OAuthBindings, user_migration.RemoteOAuthBinding{ ProviderSlug: provider.Slug, ProviderUserId: binding.ProviderUserId, }) } return snapshot }