package httpRequest import ( "encoding/json" "maps" "net/http" "slices" "strings" "go-socket/packages/Enums/WsEventType" "go-socket/packages/postgresql" "go-socket/packages/types" "go-socket/packages/wsServer" "go-socket/packages/config" "go-socket/packages/convertions" "go-socket/packages/minio" ) func HandleAttachmentFileUpload(response http.ResponseWriter, request *http.Request) { if !validCheckWithResponseOnFail(response, request, file) { return } ctx := request.Context() user, err := getUserByToken(ctx, request.Header.Get("token")) if err != nil { http.Error(response, "invalid token", http.StatusUnauthorized) return } if err = request.ParseMultipartForm(int64(config.MaxRequestBytes)); err != nil { http.Error(response, "invalid multipart form", http.StatusBadRequest) return } target := request.FormValue("target_id") file, header, err := request.FormFile("file") if err != nil { http.Error(response, "missing file", http.StatusBadRequest) return } defer file.Close() contentType := header.Header.Get("Content-Type") var key string if conn, ok := getConnection(ctx, target, user); ok { key = minio.GetKey(&minio.GetKeyOptions{ ConnectionId: conn.Id, MimeType: contentType, UploadType: minio.ConnectionFile, }) } else if channel, ok := getChannelFromUser(user, target); ok { channel.Mu.RLock() perms := channel.UsersCachedPermissions[user.Id] channel.Mu.RUnlock() if !perms.CanMessage() { http.Error(response, "forbidden", http.StatusForbidden) return } key = minio.GetKey(&minio.GetKeyOptions{ ChannelId: channel.Id, MimeType: contentType, UploadType: minio.HubChannelFile, }) } else { http.Error(response, "cannot find target", http.StatusBadRequest) return } if err = minio.Upload(ctx, key, file, header.Size, contentType, map[string]string{ "originalName": header.Filename, "uploaderId": user.Id.String(), }); err != nil { http.Error(response, "upload failed", http.StatusInternalServerError) return } response.WriteHeader(http.StatusCreated) response.Write([]byte(key)) } func HandleSetUserAvatar(response http.ResponseWriter, request *http.Request) { if !validCheckWithResponseOnFail(response, request, avatar) { return } ctx := request.Context() user, err := getUserByToken(ctx, request.Header.Get("token")) if err != nil { http.Error(response, "invalid token", http.StatusUnauthorized) return } file, header, err := request.FormFile("file") if err != nil { http.Error(response, "missing file", http.StatusBadRequest) return } defer file.Close() isImg, contentType, err := isImage(file) if err != nil || !isImg { http.Error(response, "invalid file", http.StatusBadRequest) return } key := minio.GetKey(&minio.GetKeyOptions{ MimeType: contentType, UploadType: minio.UserAvatar, UserId: user.Id, }) err = minio.Upload(ctx, key, file, header.Size, contentType, map[string]string{ "originalName": header.Filename, "uploaderId": user.Id.String(), }) if err != nil { http.Error(response, "upload failed", http.StatusInternalServerError) return } if user.AvatarKey != "" { if err = minio.Delete(ctx, user.AvatarKey); err != nil { minio.Delete(ctx, key) http.Error(response, "internal server error", http.StatusInternalServerError) return } } user.AvatarKey = key err = postgresql.UserUpdateProfile(ctx, user, &types.UserProfileUpdateList{Avatar: true}) if err != nil { http.Error(response, "failed to update user avatar", http.StatusInternalServerError) minio.Delete(ctx, user.AvatarKey) return } user.Mu.RLock() connections := slices.Collect(maps.Values(user.Connections)) user.Mu.RUnlock() for _, conn := range connections { targetId := conn.GetSecondUser(user.Id) target, err := getUserById(ctx, targetId) if err != nil { continue } wsServer.WsSendMessageCloseIfTimeout(target, types.WsEventMessage{ Type: WsEventType.UserAvatarChange, Event: &map[string]any{ "userId": user.Id, }, }) } response.WriteHeader(http.StatusCreated) } func HandleGetUserAvatar(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("user_id")) if err != nil { http.Error(response, "invalid user_id", http.StatusBadRequest) return } target, err := getUserById(ctx, targetId) if err != nil { http.Error(response, "user not found", http.StatusNotFound) return } if target.AvatarKey == "" { http.Error(response, "user have no avatar", http.StatusNoContent) return } url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, target.AvatarKey) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } avatarData, err := json.Marshal(map[string]any{ "url": url.String(), "metadata": meta, }) if err != nil { http.Error(response, "json error", http.StatusInternalServerError) return } response.WriteHeader(http.StatusOK) response.Write(avatarData) } func HandleSetUserProfileBg(response http.ResponseWriter, request *http.Request) { if !validCheckWithResponseOnFail(response, request, profileBg) { return } ctx := request.Context() user, err := getUserByToken(ctx, request.Header.Get("token")) if err != nil { http.Error(response, "invalid token", http.StatusUnauthorized) return } file, header, err := request.FormFile("file") if err != nil { http.Error(response, "missing file", http.StatusBadRequest) return } defer file.Close() isImg, contentType, err := isImage(file) if err != nil || !isImg { http.Error(response, "invalid file", http.StatusBadRequest) return } key := minio.GetKey(&minio.GetKeyOptions{ MimeType: contentType, UploadType: minio.UserProfileBg, UserId: user.Id, }) err = minio.Upload(ctx, key, file, header.Size, contentType, map[string]string{ "originalName": header.Filename, "uploaderId": user.Id.String(), }) if err != nil { http.Error(response, "upload failed", http.StatusInternalServerError) return } if user.ProfileBgKey != "" { if err = minio.Delete(ctx, user.ProfileBgKey); err != nil { minio.Delete(ctx, key) http.Error(response, "internal server error", http.StatusInternalServerError) return } } user.ProfileBgKey = key err = postgresql.UserUpdateProfile(ctx, user, &types.UserProfileUpdateList{ProfileBg: true}) if err != nil { http.Error(response, "failed to update user profile background", http.StatusInternalServerError) minio.Delete(ctx, user.ProfileBgKey) 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.UserProfileBgChange, Event: &map[string]any{ "userId": user.Id, }, }) } response.WriteHeader(http.StatusCreated) } func HandleGetUserProfileBg(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("user_id")) if err != nil { http.Error(response, "invalid user_id", http.StatusBadRequest) return } target, err := getUserById(ctx, targetId) if err != nil { http.Error(response, "user not found", http.StatusNotFound) return } if target.ProfileBgKey == "" { http.Error(response, "user have no profile background", http.StatusNoContent) return } url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, target.ProfileBgKey) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } profileBgData, err := json.Marshal(map[string]any{ "url": url.String(), "metadata": meta, }) if err != nil { http.Error(response, "json error", http.StatusInternalServerError) return } response.WriteHeader(http.StatusOK) response.Write(profileBgData) } func HandleAttachmentFileDownload(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 } target := request.URL.Query().Get("target_id") key := request.URL.Query().Get("key") var validPrefix string if conn, ok := getConnection(ctx, target, user); ok { validPrefix = string(minio.ConnectionFilePrefix) + conn.Id.String() + "/" } else if channel, ok := getChannelFromUser(user, target); ok { channel.Mu.RLock() perms := channel.UsersCachedPermissions[user.Id] channel.Mu.RUnlock() if !perms.CanReadHistory() { http.Error(response, "forbidden", http.StatusForbidden) return } validPrefix = string(minio.HubChannelFilePrefix) + channel.Id.String() + "/" } else { http.Error(response, "cannot find target", http.StatusBadRequest) return } if !strings.HasPrefix(key, validPrefix) { http.Error(response, "no such file", http.StatusUnauthorized) return } url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, key) if err != nil { http.Error(response, "no such file", http.StatusUnauthorized) return } fileData, err := json.Marshal(map[string]string{ "url": url.String(), "originalName": meta["originalName"], }) if err != nil { http.Error(response, "metadata error", http.StatusInternalServerError) return } response.WriteHeader(http.StatusOK) response.Write(fileData) }