From 5b8c83f97254664189115142ebd2131c9b908b92 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 1 Feb 2026 23:23:53 +0100 Subject: [PATCH] UI to share user to other users --- backend/character/routes.go | 5 + backend/character/share_handlers.go | 146 ++++++++ frontend/src/assets/main.css | 2 +- frontend/src/components/VisibilityDialog.vue | 342 ++++++++++++++++++- frontend/src/locales/de | 11 +- frontend/src/locales/en | 11 +- 6 files changed, 509 insertions(+), 8 deletions(-) create mode 100644 backend/character/share_handlers.go diff --git a/backend/character/routes.go b/backend/character/routes.go index ab80ee5..9604c8f 100644 --- a/backend/character/routes.go +++ b/backend/character/routes.go @@ -16,6 +16,11 @@ func RegisterRoutes(r *gin.RouterGroup) { charGrp.PUT("/:id/image", UpdateCharacterImage) charGrp.GET("/:id/datasheet-options", GetDatasheetOptions) + // Character Sharing + charGrp.GET("/:id/shares", GetCharacterShares) + charGrp.PUT("/:id/shares", UpdateCharacterShares) + charGrp.GET("/:id/available-users", GetAvailableUsersForSharing) + // Erfahrung und Vermögen charGrp.GET("/:id/experience-wealth", GetCharacterExperienceAndWealth) // NewSystem charGrp.PUT("/:id/experience", UpdateCharacterExperience) // NewSystem diff --git a/backend/character/share_handlers.go b/backend/character/share_handlers.go new file mode 100644 index 0000000..2c326cd --- /dev/null +++ b/backend/character/share_handlers.go @@ -0,0 +1,146 @@ +package character + +import ( + "bamort/database" + "bamort/models" + "bamort/user" + "net/http" + + "github.com/gin-gonic/gin" +) + +// GetCharacterShares returns the list of users a character is shared with +func GetCharacterShares(c *gin.Context) { + charID := c.Param("id") + + var character models.Char + if err := character.FirstID(charID); err != nil { + respondWithError(c, http.StatusNotFound, "Character not found") + return + } + + // Check ownership + if !checkCharacterOwnership(c, &character) { + return + } + + var shares []models.CharShare + if err := database.DB.Where("character_id = ?", character.ID).Find(&shares).Error; err != nil { + respondWithError(c, http.StatusInternalServerError, "Failed to retrieve shares") + return + } + + // Get user details for each share + type ShareWithUser struct { + models.CharShare + Username string `json:"username"` + Email string `json:"email"` + } + + var sharesWithUsers []ShareWithUser + for _, share := range shares { + var u user.User + if err := u.FirstId(share.UserID); err == nil { + sharesWithUsers = append(sharesWithUsers, ShareWithUser{ + CharShare: share, + Username: u.Username, + Email: u.Email, + }) + } + } + + c.JSON(http.StatusOK, sharesWithUsers) +} + +// UpdateCharacterShares updates the list of users a character is shared with +func UpdateCharacterShares(c *gin.Context) { + charID := c.Param("id") + + var character models.Char + if err := character.FirstID(charID); err != nil { + respondWithError(c, http.StatusNotFound, "Character not found") + return + } + + // Check ownership + if !checkCharacterOwnership(c, &character) { + return + } + + type UpdateSharesRequest struct { + UserIDs []uint `json:"user_ids" binding:"required"` + } + + var request UpdateSharesRequest + if err := c.ShouldBindJSON(&request); err != nil { + respondWithError(c, http.StatusBadRequest, err.Error()) + return + } + + // Delete existing shares + if err := database.DB.Where("character_id = ?", character.ID).Delete(&models.CharShare{}).Error; err != nil { + respondWithError(c, http.StatusInternalServerError, "Failed to delete existing shares") + return + } + + // Create new shares + for _, userID := range request.UserIDs { + // Don't share with yourself + if userID == character.UserID { + continue + } + + share := models.CharShare{ + CharacterID: character.ID, + UserID: userID, + Permission: "read", + } + + if err := database.DB.Create(&share).Error; err != nil { + respondWithError(c, http.StatusInternalServerError, "Failed to create share") + return + } + } + + c.JSON(http.StatusOK, gin.H{"message": "Shares updated successfully"}) +} + +// GetAvailableUsersForSharing returns a list of users (excluding the owner) +func GetAvailableUsersForSharing(c *gin.Context) { + charID := c.Param("id") + + var character models.Char + if err := character.FirstID(charID); err != nil { + respondWithError(c, http.StatusNotFound, "Character not found") + return + } + + // Check ownership + if !checkCharacterOwnership(c, &character) { + return + } + + var users []user.User + if err := database.DB.Where("user_id != ?", character.UserID).Find(&users).Error; err != nil { + respondWithError(c, http.StatusInternalServerError, "Failed to retrieve users") + return + } + + // Remove sensitive data + type UserInfo struct { + UserID uint `json:"user_id"` + Username string `json:"username"` + Email string `json:"email"` + } + + var userInfos []UserInfo + for _, u := range users { + userInfos = append(userInfos, UserInfo{ + UserID: u.UserID, + Username: u.Username, + Email: u.Email, + }) + } + + c.JSON(http.StatusOK, userInfos) +} diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css index f017fb5..96ad088 100644 --- a/frontend/src/assets/main.css +++ b/frontend/src/assets/main.css @@ -2544,7 +2544,7 @@ a:focus { } .remove-btn { - position: absolute; + /*position: absolute;*/ right: 0; top: 50%; transform: translateY(-50%); diff --git a/frontend/src/components/VisibilityDialog.vue b/frontend/src/components/VisibilityDialog.vue index ecaccf9..e36a58a 100644 --- a/frontend/src/components/VisibilityDialog.vue +++ b/frontend/src/components/VisibilityDialog.vue @@ -1,6 +1,6 @@