package httpRequest import ( "encoding/json" "maps" "net/http" "slices" "time" "go-socket/packages/Enums/WsEventType" "go-socket/packages/cache" "go-socket/packages/convertions" "go-socket/packages/passwords" "go-socket/packages/postgresql" "go-socket/packages/tokens" "go-socket/packages/types" "go-socket/packages/wsServer" "golang.org/x/crypto/bcrypt" "github.com/google/uuid" ) func HandleUserNewToken(response http.ResponseWriter, request *http.Request) { if !validCheckWithResponseOnFail(response, request, normal) { return } username := request.FormValue("username") if len(username) < 4 { http.Error(response, "no or short username", http.StatusBadRequest) return } password := request.FormValue("password") if len(password) < 8 { http.Error(response, "no or short passwords", http.StatusBadRequest) return } var ( user *types.User err error ctx = request.Context() ) user, err = cache.GetUserByName(username) if err != nil { user = &types.User{Name: username, Hubs: make(map[uuid.UUID]*types.Hub)} if err = postgresql.UserGetStandardInfoByName(ctx, user); err != nil { http.Error(response, "bad login", http.StatusUnauthorized) return } if err = postgresql.GetWholeUser(ctx, user); err != nil { http.Error(response, err.Error(), http.StatusInternalServerError) return } } err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)) if err != nil { http.Error(response, "bad login", http.StatusUnauthorized) return } token, err := tokens.TokenCreate(user.Id) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } data, err := json.Marshal(types.LoginResponse{Token: token, UserId: user.Id}) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } response.WriteHeader(http.StatusCreated) response.Write(data) } func HandleUserNew(response http.ResponseWriter, request *http.Request) { if !validCheckWithResponseOnFail(response, request, normal) { return } username := request.FormValue("username") if len(username) < 4 || len(username) > 30 { http.Error(response, "no or short/too long username", http.StatusBadRequest) return } password := request.FormValue("password") if len(password) < 8 { http.Error(response, "no or short passwords", http.StatusBadRequest) return } hashedPassword, err := passwords.PasswordHash(password) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } newUser := &types.User{ Name: username, PasswordHash: hashedPassword, Color: types.RandomRgba(), CreatedAt: time.Now(), } ctx := request.Context() err = postgresql.UserSave(ctx, newUser) if err != nil { http.Error(response, "name taken", http.StatusConflict) return } response.WriteHeader(http.StatusCreated) } func HandleUserDelete(response http.ResponseWriter, request *http.Request) { if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() userId, err := tokens.TokenValidateGetId(request.Header.Get("token")) if err != nil { http.Error(response, "invalid token", http.StatusUnauthorized) return } err = postgresql.UserDelete(ctx, userId) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } cache.DeleteUser(userId) response.WriteHeader(http.StatusAccepted) } func HandleUserModProfile(response http.ResponseWriter, request *http.Request) { if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() user, err := getUserByToken(ctx, request.Header.Get("token")) if err != nil { http.Error(response, "invalid token", http.StatusUnauthorized) return } updateList := &types.UserProfileUpdateList{} updatedValues := map[string]any{} if pronouns := request.FormValue("pronouns"); pronouns != "" { if len(pronouns) > 32 { http.Error(response, "pronouns too long", http.StatusBadRequest) return } user.Pronouns = pronouns updateList.Pronouns = true updatedValues["pronouns"] = pronouns } if description := request.FormValue("description"); description != "" { if len(description) > 256 { http.Error(response, "description too long", http.StatusBadRequest) return } user.Description = description updateList.Description = true updatedValues["description"] = description } if colorStr := request.FormValue("color"); colorStr != "" { color, err := convertions.StringToRgba(colorStr) if err != nil { http.Error(response, "invalid color", http.StatusBadRequest) return } user.Color = color updateList.Color = true updatedValues["color"] = color } if len(updatedValues) == 0 { http.Error(response, "no values", http.StatusBadRequest) return } err = postgresql.UserUpdateProfile(ctx, user, updateList) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } user.Mu.RLock() connections := slices.Collect(maps.Values(user.Connections)) user.Mu.RUnlock() for _, conn := range connections { target, err := getUserById(ctx, conn.GetSecondUser(user.Id)) if err != nil { continue } wsServer.WsSendMessageCloseIfTimeout(target, types.WsEventMessage{ Type: WsEventType.UserProfileChange, Event: &map[string]any{ "userId": user.Id, "profileChangeList": updatedValues, }, }) } response.WriteHeader(http.StatusAccepted) } func HandleUserGetUser(response http.ResponseWriter, request *http.Request) { if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() _, err := getUserByToken(ctx, request.Header.Get("token")) if err != nil { http.Error(response, "invalid token", http.StatusUnauthorized) return } targetId, err := convertions.StringToUuid(request.URL.Query().Get("targetid")) if err != nil { http.Error(response, "invalid userid", http.StatusBadRequest) return } target, err := getUserById(ctx, targetId) if err != nil { http.Error(response, "user not found", http.StatusNotFound) return } userData, err := json.Marshal(target) if err != nil { http.Error(response, "json parse error", http.StatusInternalServerError) return } response.WriteHeader(http.StatusAccepted) response.Write(userData) }