add new user set avatar and profile background
This commit is contained in:
@@ -3,13 +3,13 @@ module go-socket
|
|||||||
go 1.26
|
go 1.26
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/BurntSushi/toml v1.6.0
|
||||||
github.com/coder/websocket v1.8.14
|
github.com/coder/websocket v1.8.14
|
||||||
github.com/jackc/pgx/v5 v5.8.0
|
github.com/jackc/pgx/v5 v5.8.0
|
||||||
golang.org/x/crypto v0.49.0
|
golang.org/x/crypto v0.49.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.6.0 // indirect
|
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/go-ini/ini v1.67.0 // indirect
|
github.com/go-ini/ini v1.67.0 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
|||||||
@@ -83,7 +83,10 @@
|
|||||||
<button data-form="get-user-profilebg" onclick="showForm('get-user-profilebg')">GET /user/profilebg</button>
|
<button data-form="get-user-profilebg" onclick="showForm('get-user-profilebg')">GET /user/profilebg</button>
|
||||||
<button data-form="del-user" class="warn" onclick="showForm('del-user')">DELETE /user</button>
|
<button data-form="del-user" class="warn" onclick="showForm('del-user')">DELETE /user</button>
|
||||||
<button data-form="del-connection" class="warn" onclick="showForm('del-connection')">DELETE /connection</button>
|
<button data-form="del-connection" class="warn" onclick="showForm('del-connection')">DELETE /connection</button>
|
||||||
<button data-form="msg-user" onclick="showForm('msg-user')">POST /message</button>
|
<button data-form="msg-user" onclick="showForm('msg-user')">POST /connection/message</button>
|
||||||
|
<button data-form="hub-create" onclick="showForm('hub-create')">POST /hub</button>
|
||||||
|
<button data-form="hub-join" onclick="showForm('hub-join')">PUT /hub/join</button>
|
||||||
|
<button data-form="channel-message" onclick="showForm('channel-message')">POST /channel/message</button>
|
||||||
<button data-form="websocket" onclick="showForm('websocket')">WS /ws</button>
|
<button data-form="websocket" onclick="showForm('websocket')">WS /ws</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -220,7 +223,7 @@
|
|||||||
<div class="form-actions"><button class="send" onclick="submit('del-connection')">Send</button></div>
|
<div class="form-actions"><button class="send" onclick="submit('del-connection')">Send</button></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- POST /message -->
|
<!-- POST /connection/message -->
|
||||||
<div class="form-content" id="fc-msg-user">
|
<div class="form-content" id="fc-msg-user">
|
||||||
<div class="field"><label>token</label><input id="mu-token" placeholder=""></div>
|
<div class="field"><label>token</label><input id="mu-token" placeholder=""></div>
|
||||||
<div class="field"><label>connectionid</label><input id="mu-connectionid" placeholder="UUID"></div>
|
<div class="field"><label>connectionid</label><input id="mu-connectionid" placeholder="UUID"></div>
|
||||||
@@ -229,6 +232,30 @@
|
|||||||
<div class="form-actions"><button class="send" onclick="submit('msg-user')">Send</button></div>
|
<div class="form-actions"><button class="send" onclick="submit('msg-user')">Send</button></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- POST /hub -->
|
||||||
|
<div class="form-content" id="fc-hub-create">
|
||||||
|
<div class="field"><label>token</label><input id="hc-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubname</label><input id="hc-hubname" placeholder="name of new hub"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-create')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- PUT /hub/join -->
|
||||||
|
<div class="form-content" id="fc-hub-join">
|
||||||
|
<div class="field"><label>token</label><input id="hj-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="hj-hubid" placeholder="UUID"><span class="hint">sent as header</span></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('hub-join')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- POST /channel/message -->
|
||||||
|
<div class="form-content" id="fc-channel-message">
|
||||||
|
<div class="field"><label>token</label><input id="cm-token" placeholder=""></div>
|
||||||
|
<div class="field"><label>hubid</label><input id="cm-hubid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>channelid</label><input id="cm-channelid" placeholder="UUID"></div>
|
||||||
|
<div class="field"><label>msgContent</label><input id="cm-msgContent" placeholder="message text (optional if file set)"></div>
|
||||||
|
<div class="field"><label>attachedFile</label><input id="cm-attachedFile" placeholder="key from POST /file (optional)"></div>
|
||||||
|
<div class="form-actions"><button class="send" onclick="submit('channel-message')">Send</button></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- WS /ws -->
|
<!-- WS /ws -->
|
||||||
<div class="form-content" id="fc-websocket">
|
<div class="form-content" id="fc-websocket">
|
||||||
<div class="form-actions" style="margin-bottom:10px">
|
<div class="form-actions" style="margin-bottom:10px">
|
||||||
@@ -267,7 +294,10 @@
|
|||||||
'get-connection-messages': { method:'GET', path:'/connection/messages', title:'GET /connection/messages — message history', fields:[{id:'gcm-token',dest:'header',name:'token'},{id:'gcm-connectionid',dest:'query',name:'connectionid'},{id:'gcm-messages',dest:'query',name:'messages'},{id:'gcm-before',dest:'query',name:'before'}] },
|
'get-connection-messages': { method:'GET', path:'/connection/messages', title:'GET /connection/messages — message history', fields:[{id:'gcm-token',dest:'header',name:'token'},{id:'gcm-connectionid',dest:'query',name:'connectionid'},{id:'gcm-messages',dest:'query',name:'messages'},{id:'gcm-before',dest:'query',name:'before'}] },
|
||||||
'del-user': { method:'DELETE', path:'/user', title:'DELETE /user — delete own account', fields:[{id:'du-token',dest:'header',name:'token'}] },
|
'del-user': { method:'DELETE', path:'/user', title:'DELETE /user — delete own account', fields:[{id:'du-token',dest:'header',name:'token'}] },
|
||||||
'del-connection': { method:'DELETE', path:'/connection', title:'DELETE /connection — delete a connection', fields:[{id:'dc-token',dest:'header',name:'token'},{id:'dc-connectionid',dest:'query',name:'connectionid'}] },
|
'del-connection': { method:'DELETE', path:'/connection', title:'DELETE /connection — delete a connection', fields:[{id:'dc-token',dest:'header',name:'token'},{id:'dc-connectionid',dest:'query',name:'connectionid'}] },
|
||||||
'msg-user': { method:'POST', path:'/message', title:'POST /message — send direct message', fields:[{id:'mu-token',dest:'header',name:'token'},{id:'mu-connectionid',dest:'body',name:'connectionid'},{id:'mu-msgContent',dest:'body',name:'msgContent'},{id:'mu-attachedFile',dest:'body',name:'attachedFile'}] },
|
'msg-user': { method:'POST', path:'/connection/message', title:'POST /connection/message — send direct message', fields:[{id:'mu-token',dest:'header',name:'token'},{id:'mu-connectionid',dest:'body',name:'connectionid'},{id:'mu-msgContent',dest:'body',name:'msgContent'},{id:'mu-attachedFile',dest:'body',name:'attachedFile'}] },
|
||||||
|
'hub-create': { method:'POST', path:'/hub', title:'POST /hub — create a new hub', fields:[{id:'hc-token',dest:'header',name:'token'},{id:'hc-hubname',dest:'body',name:'hubname'}] },
|
||||||
|
'hub-join': { method:'PUT', path:'/hub/join', title:'PUT /hub/join — join hub (hubid as header)', fields:[{id:'hj-token',dest:'header',name:'token'},{id:'hj-hubid',dest:'header',name:'hubid'}] },
|
||||||
|
'channel-message': { method:'POST', path:'/channel/message', title:'POST /channel/message — send hub channel msg',fields:[{id:'cm-token',dest:'header',name:'token'},{id:'cm-hubid',dest:'body',name:'hubid'},{id:'cm-channelid',dest:'body',name:'channelid'},{id:'cm-msgContent',dest:'body',name:'msgContent'},{id:'cm-attachedFile',dest:'body',name:'attachedFile'}] },
|
||||||
'mod-user-avatar': { title:'PATCH /user/avatar — set avatar image' },
|
'mod-user-avatar': { title:'PATCH /user/avatar — set avatar image' },
|
||||||
'mod-user-profilebg': { title:'PATCH /user/profilebg — set profile background' },
|
'mod-user-profilebg': { title:'PATCH /user/profilebg — set profile background' },
|
||||||
'file-upload': { title:'POST /file — upload file (multipart)' },
|
'file-upload': { title:'POST /file — upload file (multipart)' },
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ func main() {
|
|||||||
http.HandleFunc("DELETE /user", withCORS(httpRequest.HandleUserDelete))
|
http.HandleFunc("DELETE /user", withCORS(httpRequest.HandleUserDelete))
|
||||||
http.HandleFunc("GET /user", withCORS(httpRequest.HandleUserGetUser))
|
http.HandleFunc("GET /user", withCORS(httpRequest.HandleUserGetUser))
|
||||||
http.HandleFunc("PATCH /user/profile", withCORS(httpRequest.HandleUserModProfile))
|
http.HandleFunc("PATCH /user/profile", withCORS(httpRequest.HandleUserModProfile))
|
||||||
http.HandleFunc("PATCH /user/avatar", withCORS(httpRequest.HandleUserModAvatar))
|
http.HandleFunc("PATCH /user/avatar", withCORS(httpRequest.HandleSetUserAvatar))
|
||||||
http.HandleFunc("PATCH /user/profilebg", withCORS(httpRequest.HandleUserModProfileBg))
|
http.HandleFunc("PATCH /user/profilebg", withCORS(httpRequest.HandleSetUserProfileBg))
|
||||||
http.HandleFunc("GET /user/avatar", withCORS(httpRequest.HandleGetUserAvatar))
|
http.HandleFunc("GET /user/avatar", withCORS(httpRequest.HandleGetUserAvatar))
|
||||||
http.HandleFunc("GET /user/profilebg", withCORS(httpRequest.HandleGetUserProfileBg))
|
http.HandleFunc("GET /user/profilebg", withCORS(httpRequest.HandleGetUserProfileBg))
|
||||||
|
|
||||||
@@ -56,7 +56,10 @@ func main() {
|
|||||||
http.HandleFunc("POST /file", withCORS(httpRequest.HandleAttachmentFileUpload))
|
http.HandleFunc("POST /file", withCORS(httpRequest.HandleAttachmentFileUpload))
|
||||||
http.HandleFunc("GET /file", withCORS(httpRequest.HandleAttachmentFileDownload))
|
http.HandleFunc("GET /file", withCORS(httpRequest.HandleAttachmentFileDownload))
|
||||||
|
|
||||||
http.HandleFunc("POST /message", withCORS(httpRequest.HandleDm))
|
http.HandleFunc("POST /hub", withCORS(httpRequest.HandleHubCreate))
|
||||||
|
http.HandleFunc("PUT /hub/join", withCORS(httpRequest.HandleHubJoin))
|
||||||
|
|
||||||
|
http.HandleFunc("POST /connection/message", withCORS(httpRequest.HandleDm))
|
||||||
http.HandleFunc("GET /ws", wsServer.ServeWsConnection)
|
http.HandleFunc("GET /ws", wsServer.ServeWsConnection)
|
||||||
|
|
||||||
log.Println("beep boop; server server started")
|
log.Println("beep boop; server server started")
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ type configFile struct {
|
|||||||
MaxRequestWithProfileBgBytes uint32 `toml:"max_request_with_profile_bg_bytes"`
|
MaxRequestWithProfileBgBytes uint32 `toml:"max_request_with_profile_bg_bytes"`
|
||||||
FileProcessingPartBytes uint64 `toml:"file_processing_part_bytes"`
|
FileProcessingPartBytes uint64 `toml:"file_processing_part_bytes"`
|
||||||
FileProcessingThreads uint `toml:"file_processing_threads"`
|
FileProcessingThreads uint `toml:"file_processing_threads"`
|
||||||
|
FileStorageBucketName string `toml:"file_storage_bucket_name"`
|
||||||
FileDownloadLinkTtl time.Duration `toml:"file_download_link_ttl"`
|
FileDownloadLinkTtl time.Duration `toml:"file_download_link_ttl"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package httpRequest
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
json2 "encoding/json"
|
json2 "encoding/json"
|
||||||
|
"go-socket/packages/postgresql"
|
||||||
|
"go-socket/packages/types"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -42,7 +44,7 @@ func HandleAttachmentFileUpload(response http.ResponseWriter, request *http.Requ
|
|||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
contentType := header.Header.Get("Content-Type")
|
contentType := header.Header.Get("Content-Type")
|
||||||
key := minio.GetKey(minio.GetKeyOptions{
|
key := minio.GetKey(&minio.GetKeyOptions{
|
||||||
ConnectionId: conn.Id,
|
ConnectionId: conn.Id,
|
||||||
MimeType: contentType,
|
MimeType: contentType,
|
||||||
UploadType: minio.ConnectionFile,
|
UploadType: minio.ConnectionFile,
|
||||||
@@ -60,6 +62,62 @@ func HandleAttachmentFileUpload(response http.ResponseWriter, request *http.Requ
|
|||||||
response.Write([]byte(key))
|
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.AvatarUrl != "" {
|
||||||
|
if err = minio.Delete(ctx, user.AvatarUrl); err != nil {
|
||||||
|
minio.Delete(ctx, key)
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user.AvatarUrl = 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.AvatarUrl)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusCreated)
|
||||||
|
}
|
||||||
|
|
||||||
func HandleGetUserAvatar(response http.ResponseWriter, request *http.Request) {
|
func HandleGetUserAvatar(response http.ResponseWriter, request *http.Request) {
|
||||||
if !validCheckWithResponseOnFail(&response, request, normal) {
|
if !validCheckWithResponseOnFail(&response, request, normal) {
|
||||||
return
|
return
|
||||||
@@ -85,18 +143,82 @@ func HandleGetUserAvatar(response http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if target.AvatarUrl == "" {
|
if target.AvatarUrl == "" {
|
||||||
http.Error(response, "no avatar", http.StatusNotFound)
|
http.Error(response, "user have no avatar", http.StatusNoContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
url, _, err := minio.GetDownloadUrlAndMetadata(ctx, target.AvatarUrl)
|
url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, target.AvatarUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "internal server error", http.StatusInternalServerError)
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
json, err := json2.Marshal(map[string]any{
|
||||||
|
"url": url.String(),
|
||||||
|
"metadata": meta,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "json error", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
response.WriteHeader(http.StatusOK)
|
response.WriteHeader(http.StatusOK)
|
||||||
response.Write([]byte(url.String()))
|
response.Write(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.ProfileBgUrl != "" {
|
||||||
|
if err = minio.Delete(ctx, user.ProfileBgUrl); err != nil {
|
||||||
|
minio.Delete(ctx, key)
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user.ProfileBgUrl = 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.ProfileBgUrl)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleGetUserProfileBg(response http.ResponseWriter, request *http.Request) {
|
func HandleGetUserProfileBg(response http.ResponseWriter, request *http.Request) {
|
||||||
@@ -105,7 +227,8 @@ func HandleGetUserProfileBg(response http.ResponseWriter, request *http.Request)
|
|||||||
}
|
}
|
||||||
ctx := request.Context()
|
ctx := request.Context()
|
||||||
|
|
||||||
if _, err := getUserByToken(ctx, request.Header.Get("token")); err != nil {
|
_, err := getUserByToken(ctx, request.Header.Get("token"))
|
||||||
|
if err != nil {
|
||||||
http.Error(response, "invalid token", http.StatusUnauthorized)
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -123,18 +246,26 @@ func HandleGetUserProfileBg(response http.ResponseWriter, request *http.Request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if target.ProfileBgUrl == "" {
|
if target.ProfileBgUrl == "" {
|
||||||
http.Error(response, "no profile background", http.StatusNotFound)
|
http.Error(response, "user have no profile background", http.StatusNoContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
url, _, err := minio.GetDownloadUrlAndMetadata(ctx, target.ProfileBgUrl)
|
url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, target.ProfileBgUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(response, "internal server error", http.StatusInternalServerError)
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
json, err := json2.Marshal(map[string]any{
|
||||||
|
"url": url.String(),
|
||||||
|
"metadata": meta,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "json error", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
response.WriteHeader(http.StatusOK)
|
response.WriteHeader(http.StatusOK)
|
||||||
response.Write([]byte(url.String()))
|
response.Write(json)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleAttachmentFileDownload(response http.ResponseWriter, request *http.Request) {
|
func HandleAttachmentFileDownload(response http.ResponseWriter, request *http.Request) {
|
||||||
|
|||||||
+19
-19
@@ -90,22 +90,22 @@ func getHubUserIfValidWithResponseOnFail(ctx context.Context, response http.Resp
|
|||||||
return user, hubUser, hub, nil
|
return user, hubUser, hub, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHubChannelIfValidWithResponseOnFail(ctx context.Context, response http.ResponseWriter, hub *types.Hub, hubUser *types.HubUser, channelId string) (
|
//func getHubChannelIfValidWithResponseOnFail(ctx context.Context, response http.ResponseWriter, hub *types.Hub, hubUser *types.HubUser, channelId string) (
|
||||||
*types.HubChannel, error) {
|
// *types.HubChannel, error) {
|
||||||
channelUuid, err := convertions.StringToUuid(channelId)
|
// channelUuid, err := convertions.StringToUuid(channelId)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
http.Error(response, "invalid channelid", http.StatusBadRequest)
|
// http.Error(response, "invalid channelid", http.StatusBadRequest)
|
||||||
return nil, errors.New("invalid channelid")
|
// return nil, errors.New("invalid channelid")
|
||||||
}
|
// }
|
||||||
channel, ok := hub.Channels[channelUuid]
|
// channel, ok := hub.Channels[channelUuid]
|
||||||
if !ok {
|
// if !ok {
|
||||||
http.Error(response, "invalid channelid", http.StatusBadRequest)
|
// http.Error(response, "invalid channelid", http.StatusBadRequest)
|
||||||
return nil, errors.New("invalid channelid")
|
// return nil, errors.New("invalid channelid")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if !haveHubUserPermissionsOnChannel(types.CachedUserCanView, hubUser, channel) {
|
// if !haveHubUserPermissionsOnChannel(types.CachedUserCanView, hubUser, channel) {
|
||||||
return nil, errors.New("invalid channelid")
|
// return nil, errors.New("invalid channelid")
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return channel, nil
|
// return channel, nil
|
||||||
}
|
//}
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go-socket/packages/Enums/WsEventType"
|
|
||||||
"go-socket/packages/cache"
|
"go-socket/packages/cache"
|
||||||
"go-socket/packages/types"
|
"go-socket/packages/types"
|
||||||
"go-socket/packages/wsServer"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
@@ -134,65 +132,6 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
|||||||
cache.SaveHub(hub)
|
cache.SaveHub(hub)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleChannelSendMessage(response http.ResponseWriter, request *http.Request) {
|
|
||||||
if !validCheckWithResponseOnFail(&response, request, normal) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx := request.Context()
|
|
||||||
user, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
msgContent := request.FormValue("msgContent")
|
|
||||||
attachedFile := request.FormValue("attachedFile")
|
|
||||||
|
|
||||||
if msgContent == "" && attachedFile == "" {
|
|
||||||
http.Error(response, "empty msgContent", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
channel, err := getHubChannelIfValidWithResponseOnFail(ctx, response, hub, hubUser, request.FormValue("channelid"))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !haveHubUserPermissionsOnChannel(types.CachedUserCanMessage, hubUser, channel) {
|
|
||||||
http.Error(response, "cannot send messages here", http.StatusUnauthorized)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
message := &types.Message{
|
|
||||||
Id: uuid.New(),
|
|
||||||
AttachedFile: "",
|
|
||||||
Content: msgContent,
|
|
||||||
Sender: user.Id,
|
|
||||||
Receiver: channel.Id,
|
|
||||||
CreatedAt: time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
channel.Mu.RLock()
|
|
||||||
recipients := make([]uuid.UUID, 0, len(channel.UsersCachedPermissions))
|
|
||||||
for id, userCachedPerms := range channel.UsersCachedPermissions {
|
|
||||||
if userCachedPerms.CanReadHistory() && id != user.Id {
|
|
||||||
recipients = append(recipients, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
channel.Mu.RUnlock()
|
|
||||||
|
|
||||||
for _, id := range recipients {
|
|
||||||
targetUser, err := cache.GetUserById(id)
|
|
||||||
if err != nil {
|
|
||||||
// todo Add to postgres in future
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
wsServer.WsSendMessageCloseIfTimeout(targetUser, types.WsEventMessage{
|
|
||||||
Type: WsEventType.HubMessage,
|
|
||||||
Event: message,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleHubJoin(response http.ResponseWriter, request *http.Request) {
|
func HandleHubJoin(response http.ResponseWriter, request *http.Request) {
|
||||||
if !validCheckWithResponseOnFail(&response, request, normal) {
|
if !validCheckWithResponseOnFail(&response, request, normal) {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -5,11 +5,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go-socket/packages/config"
|
|
||||||
"go-socket/packages/convertions"
|
|
||||||
"go-socket/packages/minio"
|
|
||||||
|
|
||||||
"go-socket/packages/cache"
|
"go-socket/packages/cache"
|
||||||
|
"go-socket/packages/convertions"
|
||||||
"go-socket/packages/passwords"
|
"go-socket/packages/passwords"
|
||||||
"go-socket/packages/postgresql"
|
"go-socket/packages/postgresql"
|
||||||
"go-socket/packages/tokens"
|
"go-socket/packages/tokens"
|
||||||
@@ -152,7 +149,7 @@ func HandleUserModProfile(response http.ResponseWriter, request *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var updateList types.UserProfileUpdateList
|
updateList := &types.UserProfileUpdateList{}
|
||||||
|
|
||||||
if pronouns := request.FormValue("pronouns"); pronouns != "" {
|
if pronouns := request.FormValue("pronouns"); pronouns != "" {
|
||||||
if len(pronouns) > 32 {
|
if len(pronouns) > 32 {
|
||||||
@@ -190,132 +187,6 @@ func HandleUserModProfile(response http.ResponseWriter, request *http.Request) {
|
|||||||
response.WriteHeader(http.StatusAccepted)
|
response.WriteHeader(http.StatusAccepted)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleUserModAvatar(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
|
|
||||||
}
|
|
||||||
|
|
||||||
request.Body = http.MaxBytesReader(response, request.Body, int64(config.MaxRequestWithAvatarBytes))
|
|
||||||
|
|
||||||
if err = request.ParseMultipartForm(int64(config.MaxRequestBytes)); err != nil {
|
|
||||||
http.Error(response, "invalid multipart form", http.StatusBadRequest)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.AvatarUrl != "" {
|
|
||||||
err = minio.Delete(ctx, user.AvatarUrl)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(response, "internal server error", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
key := minio.GetKey(minio.GetKeyOptions{
|
|
||||||
UserId: user.Id,
|
|
||||||
MimeType: contentType,
|
|
||||||
UploadType: minio.UserAvatar,
|
|
||||||
})
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
user.AvatarUrl = key
|
|
||||||
err = postgresql.UserUpdateProfile(ctx, user, types.UserProfileUpdateList{Avatar: true})
|
|
||||||
if err != nil {
|
|
||||||
http.Error(response, "internal server error", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
response.WriteHeader(http.StatusAccepted)
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleUserModProfileBg(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
|
|
||||||
}
|
|
||||||
|
|
||||||
request.Body = http.MaxBytesReader(response, request.Body, int64(config.MaxRequestWithProfileBgBytes))
|
|
||||||
|
|
||||||
if err = request.ParseMultipartForm(int64(config.MaxRequestBytes)); err != nil {
|
|
||||||
http.Error(response, "invalid multipart form", http.StatusBadRequest)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.ProfileBgUrl != "" {
|
|
||||||
err = minio.Delete(ctx, user.ProfileBgUrl)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(response, "internal server error", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
key := minio.GetKey(minio.GetKeyOptions{
|
|
||||||
UserId: user.Id,
|
|
||||||
MimeType: contentType,
|
|
||||||
UploadType: minio.UserProfileBg,
|
|
||||||
})
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
user.ProfileBgUrl = key
|
|
||||||
err = postgresql.UserUpdateProfile(ctx, user, types.UserProfileUpdateList{ProfileBg: true})
|
|
||||||
if err != nil {
|
|
||||||
http.Error(response, "internal server error", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
response.WriteHeader(http.StatusAccepted)
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleUserGetUser(response http.ResponseWriter, request *http.Request) {
|
func HandleUserGetUser(response http.ResponseWriter, request *http.Request) {
|
||||||
if !validCheckWithResponseOnFail(&response, request, normal) {
|
if !validCheckWithResponseOnFail(&response, request, normal) {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ type GetKeyOptions struct {
|
|||||||
UploadType DataType
|
UploadType DataType
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetKey(opts GetKeyOptions) string {
|
func GetKey(opts *GetKeyOptions) string {
|
||||||
extensions, err := mime.ExtensionsByType(opts.MimeType)
|
extensions, err := mime.ExtensionsByType(opts.MimeType)
|
||||||
if err != nil || len(extensions) == 0 {
|
if err != nil || len(extensions) == 0 {
|
||||||
extensions = []string{".unknown"}
|
extensions = []string{".unknown"}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ func UserGetById(ctx context.Context, user *types.User) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func UserUpdateProfile(ctx context.Context, user *types.User, updateList types.UserProfileUpdateList) error {
|
func UserUpdateProfile(ctx context.Context, user *types.User, updateList *types.UserProfileUpdateList) error {
|
||||||
setClauses := make([]string, 0, 3)
|
setClauses := make([]string, 0, 3)
|
||||||
args := make([]any, 0, 4)
|
args := make([]any, 0, 4)
|
||||||
argIdx := 1
|
argIdx := 1
|
||||||
|
|||||||
Reference in New Issue
Block a user