346 lines
8.5 KiB
Go
346 lines
8.5 KiB
Go
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.UserGetWhole(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
|
|
}
|
|
|
|
cache.SaveUser(user)
|
|
|
|
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.UserProfileUpdate{}
|
|
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,
|
|
},
|
|
})
|
|
}
|
|
|
|
user.Mu.RLock()
|
|
hubs := slices.Collect(maps.Values(user.Hubs))
|
|
user.Mu.RUnlock()
|
|
|
|
for _, hub := range hubs {
|
|
hub.Mu.RLock()
|
|
hubUsers := slices.Collect(maps.Values(hub.Users))
|
|
hub.Mu.RUnlock()
|
|
for _, hubUser := range hubUsers {
|
|
if hubUser.OriginalId == user.Id {
|
|
continue
|
|
}
|
|
target, err := getUserById(ctx, hubUser.OriginalId)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
wsServer.WsSendMessageCloseIfTimeout(target, &types.WsHubSpecificHubEventMessage{
|
|
Type: WsEventType.UserProfileChange,
|
|
HubId: hub.Id,
|
|
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("target_id"))
|
|
if err != nil {
|
|
http.Error(response, "invalid target_id", 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)
|
|
}
|
|
|
|
func HandleUserGetUsers(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
|
|
}
|
|
|
|
targetIds, err := convertions.StringToUuids(request.URL.Query().Get("target_ids"))
|
|
if err != nil {
|
|
http.Error(response, "invalid targetids", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
users, err := cache.GetUsersByIds(targetIds)
|
|
if err != nil {
|
|
http.Error(response, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
userData, err := json.Marshal(users)
|
|
if err != nil {
|
|
http.Error(response, "json parse error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
response.WriteHeader(http.StatusAccepted)
|
|
response.Write(userData)
|
|
}
|
|
|
|
func HandleGetHubs(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.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
user.Mu.RLock()
|
|
hubs := slices.Collect(maps.Keys(user.Hubs))
|
|
user.Mu.RUnlock()
|
|
if len(hubs) == 0 {
|
|
response.WriteHeader(http.StatusNoContent)
|
|
response.Write([]byte("no hubs found"))
|
|
return
|
|
}
|
|
converted, err := json.Marshal(hubs)
|
|
if err != nil {
|
|
http.Error(response, "json error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
response.WriteHeader(http.StatusOK)
|
|
response.Write(converted)
|
|
}
|