split http across files
This commit is contained in:
+25
-11
@@ -54,13 +54,12 @@ func DbInit(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err = dbConn.Exec(ctx, `
|
_, err = dbConn.Exec(ctx, `
|
||||||
CREATE TABLE IF NOT EXISTS messages (
|
CREATE TABLE IF NOT EXISTS direct_messages (
|
||||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
sender_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
sender_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
receiver_id UUID NOT NULL REFERENCES user_connections(id) ON DELETE CASCADE,
|
receiver_id UUID NOT NULL REFERENCES user_connections(id) ON DELETE CASCADE,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||||
content TEXT NOT NULL,
|
content TEXT NOT NULL
|
||||||
is_group_message BOOLEAN DEFAULT FALSE
|
|
||||||
)
|
)
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -162,6 +161,21 @@ func DbUserSetPronouns(ctx context.Context, user *User) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DbGetWholeUser(ctx context.Context, user *User) error {
|
||||||
|
if err := DbUserGetById(ctx, user); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := DbUserGetGroups(ctx, user); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := DbConnectionsGetBelongingToUser(ctx, user); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
CacheSaveUser(user)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func DbGroupSetColor(ctx context.Context, group *Group) error {
|
func DbGroupSetColor(ctx context.Context, group *Group) error {
|
||||||
_, err := dbConn.Exec(ctx, `
|
_, err := dbConn.Exec(ctx, `
|
||||||
UPDATE chat_groups SET color_red = $1, color_green = $2, color_blue = $3 WHERE id = $4
|
UPDATE chat_groups SET color_red = $1, color_green = $2, color_blue = $3 WHERE id = $4
|
||||||
@@ -219,22 +233,22 @@ func DbConnectionUpdateState(ctx context.Context, conn *Connection) error {
|
|||||||
func DbMessageSave(ctx context.Context, message *Message) error {
|
func DbMessageSave(ctx context.Context, message *Message) error {
|
||||||
if message.Id != (uuid.UUID{}) {
|
if message.Id != (uuid.UUID{}) {
|
||||||
_, err := dbConn.Exec(ctx, `
|
_, err := dbConn.Exec(ctx, `
|
||||||
INSERT INTO messages (id, sender_id, receiver_id, created_at, content, is_group_message) VALUES ($1, $2, $3, $4, $5, $6)
|
INSERT INTO direct_messages (id, sender_id, receiver_id, created_at, content) VALUES ($1, $2, $3, $4, $5)
|
||||||
`, message.Id, message.Sender, message.Receiver, message.CreatedAt, message.Content, message.IsGroupMessage)
|
`, message.Id, message.Sender, message.Receiver, message.CreatedAt, message.Content)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return dbConn.QueryRow(ctx, `
|
return dbConn.QueryRow(ctx, `
|
||||||
INSERT INTO messages (sender_id, receiver_id, created_at, content, is_group_message) VALUES ($1, $2, $3, $4, $5)
|
INSERT INTO direct_messages (sender_id, receiver_id, created_at, content) VALUES ($1, $2, $3, $4)
|
||||||
RETURNING id
|
RETURNING id
|
||||||
`, message.Sender, message.Receiver, message.CreatedAt, message.Content, message.IsGroupMessage).Scan(&message.Id)
|
`, message.Sender, message.Receiver, message.CreatedAt, message.Content).Scan(&message.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DbConnectionGetMessagesBefore(ctx context.Context, before time.Time, connection uuid.UUID, cap uint32) ([]*Message, error) {
|
func DbConnectionGetMessagesBefore(ctx context.Context, before time.Time, connection uuid.UUID, cap uint32) ([]*Message, error) {
|
||||||
rows, err := dbConn.Query(ctx, `
|
rows, err := dbConn.Query(ctx, `
|
||||||
SELECT id, sender_id, receiver_id, created_at, content, is_group_message
|
SELECT id, sender_id, receiver_id, created_at, content
|
||||||
FROM (
|
FROM (
|
||||||
SELECT id, sender_id, receiver_id, created_at, content, is_group_message
|
SELECT id, sender_id, receiver_id, created_at, content
|
||||||
FROM messages
|
FROM direct_messages
|
||||||
WHERE receiver_id = $1
|
WHERE receiver_id = $1
|
||||||
AND created_at < $2
|
AND created_at < $2
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
@@ -250,7 +264,7 @@ func DbConnectionGetMessagesBefore(ctx context.Context, before time.Time, connec
|
|||||||
messages := make([]*Message, 0, cap)
|
messages := make([]*Message, 0, cap)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
msg := &Message{}
|
msg := &Message{}
|
||||||
if err = rows.Scan(&msg.Id, &msg.Sender, &msg.Receiver, &msg.CreatedAt, &msg.Content, &msg.IsGroupMessage); err != nil {
|
if err = rows.Scan(&msg.Id, &msg.Sender, &msg.Receiver, &msg.CreatedAt, &msg.Content); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
messages = append(messages, msg)
|
messages = append(messages, msg)
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
func GetUserById(ctx context.Context, userId uint32) (*User, error) {
|
||||||
|
user, err := CacheGetUserById(userId)
|
||||||
|
if err != nil {
|
||||||
|
user = &User{Id: userId}
|
||||||
|
err = DbGetWholeUser(ctx, user)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUserByToken(ctx context.Context, token string) (*User, error) {
|
||||||
|
userId, err := TokenValidateGetId(token)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return GetUserById(ctx, userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroup(ctx context.Context, groupId uint32) (*Group, error) {
|
||||||
|
group, err := CacheGetGroup(groupId)
|
||||||
|
if err != nil {
|
||||||
|
group = &Group{Id: groupId}
|
||||||
|
if err = DbGroupGetById(ctx, group); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = DbGroupGetMembers(ctx, group); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
CacheSaveGroup(group)
|
||||||
|
}
|
||||||
|
return group, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,331 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
json2 "encoding/json"
|
||||||
|
"maps"
|
||||||
|
"net/http"
|
||||||
|
"slices"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go-socket/Enums/ConnectionState"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HttpHandleUserMessage(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := request.Context()
|
||||||
|
user, err := GetUserByToken(ctx, request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
targetConnection, err := ConvertStringUuid(request.FormValue("connectionid"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid connectionid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn, ok := CacheGetConnection(user, targetConnection)
|
||||||
|
if !ok {
|
||||||
|
http.Error(response, "invalid connectionid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msgContent := request.FormValue("msgContent")
|
||||||
|
if msgContent == "" {
|
||||||
|
http.Error(response, "empty msgContent", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var target *User
|
||||||
|
|
||||||
|
if user.Id == conn.RequestorId {
|
||||||
|
target, err = GetUserById(ctx, conn.RecipientId)
|
||||||
|
} else if user.Id == conn.RecipientId {
|
||||||
|
target, err = GetUserById(ctx, conn.RequestorId)
|
||||||
|
} else {
|
||||||
|
http.Error(response, "invalid connectionid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
message := &Message{
|
||||||
|
Id: uuid.New(),
|
||||||
|
Content: msgContent,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
Sender: user.Id,
|
||||||
|
Receiver: conn.Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
WsMessageSendToUser(target, message)
|
||||||
|
|
||||||
|
err = DbMessageSave(ctx, message)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleUserGetConnectionMessages(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := request.Context()
|
||||||
|
user, err := GetUserByToken(ctx, request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
connectionId, err := ConvertStringUuid(request.FormValue("connectionid"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid connectionid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
before, err := ConvertStringTimestamp(request.FormValue("before"))
|
||||||
|
if err != nil {
|
||||||
|
before = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
messagesCap, err := ConvertStringUint32(request.FormValue("messages"))
|
||||||
|
if err != nil {
|
||||||
|
messagesCap = MaxDirectMsgCache
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, ok := CacheGetConnection(user, connectionId)
|
||||||
|
if !ok {
|
||||||
|
http.Error(response, "invalid connectionid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer, bufferSize := conn.GetSortedMessagesBuff()
|
||||||
|
|
||||||
|
var validBufCount uint32
|
||||||
|
for validBufCount < bufferSize && buffer[validBufCount].CreatedAt.Before(before) {
|
||||||
|
validBufCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
var messages []*Message
|
||||||
|
|
||||||
|
if validBufCount >= messagesCap {
|
||||||
|
start := validBufCount - messagesCap
|
||||||
|
messages = make([]*Message, messagesCap)
|
||||||
|
for i := uint32(0); i < messagesCap; i++ {
|
||||||
|
messages[i] = buffer[start+i]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remaining := messagesCap - validBufCount
|
||||||
|
cutoff := before
|
||||||
|
if validBufCount > 0 {
|
||||||
|
cutoff = buffer[0].CreatedAt
|
||||||
|
}
|
||||||
|
dbMessages, err := DbConnectionGetMessagesBefore(ctx, cutoff, connectionId, remaining)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
messages = make([]*Message, 0, uint32(len(dbMessages))+validBufCount)
|
||||||
|
messages = append(messages, dbMessages...)
|
||||||
|
for i := uint32(0); i < validBufCount; i++ {
|
||||||
|
messages = append(messages, buffer[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
json, err := json2.Marshal(messages)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusOK)
|
||||||
|
response.Write(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleUserNewConnection(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := request.Context()
|
||||||
|
requestor, err := GetUserByToken(ctx, request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
recipientId, err := ConvertStringUint32(request.FormValue("recipient"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "no such user", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
recipient, err := GetUserById(ctx, recipientId)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "no such user", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if requestor.Id == recipient.Id {
|
||||||
|
http.Error(response, "cannot connect to yourself", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
requestor.Mu.RLock()
|
||||||
|
for _, connection := range requestor.Connections {
|
||||||
|
if (connection.RequestorId == requestor.Id && connection.RecipientId == recipient.Id) ||
|
||||||
|
(connection.RecipientId == requestor.Id && connection.RequestorId == recipient.Id) {
|
||||||
|
requestor.Mu.RUnlock()
|
||||||
|
http.Error(response, "connection already exists", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requestor.Mu.RUnlock()
|
||||||
|
|
||||||
|
connection := &Connection{
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
RequestorId: requestor.Id,
|
||||||
|
RecipientId: recipient.Id,
|
||||||
|
State: ConnectionState.Stranger,
|
||||||
|
}
|
||||||
|
err = DbConnectionSave(ctx, connection)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
CacheAddConnection(requestor, recipient, connection)
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusCreated)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleUserDeleteConnection(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := request.Context()
|
||||||
|
|
||||||
|
user, err := GetUserByToken(ctx, request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
connectionId, err := ConvertStringUuid(request.FormValue("connectionid"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid connectionid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, ok := CacheGetConnection(user, connectionId)
|
||||||
|
if !ok {
|
||||||
|
http.Error(response, "invalid connectionid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var user2 *User
|
||||||
|
if conn.RequestorId == user.Id {
|
||||||
|
recipient, err := GetUserById(ctx, conn.RecipientId)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
user2 = recipient
|
||||||
|
} else if conn.RecipientId == user.Id {
|
||||||
|
requestor, err := GetUserById(ctx, conn.RequestorId)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
user2 = requestor
|
||||||
|
} else {
|
||||||
|
http.Error(response, "invalid connectionid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = DbConnectionDelete(ctx, conn)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
CacheDeleteConnection(user, user2, connectionId)
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleUserElevateConnection(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := request.Context()
|
||||||
|
user, err := GetUserByToken(ctx, request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
connectionId, err := ConvertStringUuid(request.FormValue("connectionid"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid connectionid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn, ok := CacheGetConnection(user, connectionId)
|
||||||
|
if !ok {
|
||||||
|
http.Error(response, "invalid connectionid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if conn.RecipientId != user.Id {
|
||||||
|
http.Error(response, "invalid connectionid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch conn.State {
|
||||||
|
case ConnectionState.Stranger:
|
||||||
|
conn.State = ConnectionState.Friend
|
||||||
|
break
|
||||||
|
case ConnectionState.GroupFellow:
|
||||||
|
conn.State = ConnectionState.Stranger
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
http.Error(response, "cannot elevate further", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = DbConnectionUpdateState(ctx, conn)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleUserGetConnections(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := request.Context()
|
||||||
|
user, err := GetUserByToken(ctx, request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Mu.RLock()
|
||||||
|
connections := slices.Collect(maps.Values(user.Connections))
|
||||||
|
user.Mu.RUnlock()
|
||||||
|
json, err := json2.Marshal(connections)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusOK)
|
||||||
|
response.Write(json)
|
||||||
|
}
|
||||||
+431
@@ -0,0 +1,431 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
json2 "encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"maps"
|
||||||
|
"net/http"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func isOwnerOfGroup(user *User, group *Group) bool {
|
||||||
|
if group.OwnerId == user.Id {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIfOwnerUserAndGroup(ctx context.Context, response *http.ResponseWriter, request *http.Request) (*User, *Group, error) {
|
||||||
|
user, err := GetUserByToken(ctx, request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(*response, "invalid token", http.StatusUnauthorized)
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
affectedGroupId, err := ConvertStringUint32(request.FormValue("groupid"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(*response, "no such group", http.StatusUnauthorized)
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
group, err := GetGroup(ctx, affectedGroupId)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(*response, "no such group", http.StatusUnauthorized)
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isOwnerOfGroup(user, group) {
|
||||||
|
http.Error(*response, "no such group", http.StatusUnauthorized)
|
||||||
|
return nil, nil, errors.New("not an owner")
|
||||||
|
}
|
||||||
|
return user, group, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandeGroupCreate(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := request.Context()
|
||||||
|
|
||||||
|
user, err := GetUserByToken(ctx, request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
name := request.FormValue("name")
|
||||||
|
if name == "" {
|
||||||
|
name = "Best group ever"
|
||||||
|
}
|
||||||
|
|
||||||
|
colorString := request.FormValue("color")
|
||||||
|
color, err := ConvertStringToRgb(colorString)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid color", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
group := Group{
|
||||||
|
Name: name,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
OwnerId: user.Id,
|
||||||
|
CreatorId: user.Id,
|
||||||
|
Color: color,
|
||||||
|
Users: map[uint32]struct{}{user.Id: {}},
|
||||||
|
}
|
||||||
|
|
||||||
|
enableUserColors := request.FormValue("enableUserColors")
|
||||||
|
if enableUserColors == "1" {
|
||||||
|
group.EnableUserColors = true
|
||||||
|
}
|
||||||
|
|
||||||
|
err = DbGroupSave(ctx, &group)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.WriteHeader(http.StatusCreated)
|
||||||
|
fmt.Fprintf(response, "%d", group.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleGroupDelete(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := request.Context()
|
||||||
|
_, group, err := getIfOwnerUserAndGroup(ctx, &response, request)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = DbGroupDelete(ctx, group)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
CacheDeleteGroup(group.Id)
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleGroupAddUsers(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := request.Context()
|
||||||
|
|
||||||
|
_, group, err := getIfOwnerUserAndGroup(ctx, &response, request)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
usersString := request.FormValue("users")
|
||||||
|
var remainingUsersCount = int(MaxUsersInGroup) - len(group.Users)
|
||||||
|
if remainingUsersCount < 1 {
|
||||||
|
http.Error(response, "max users", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
usersStringSlice := strings.SplitN(usersString, ",", remainingUsersCount+1)
|
||||||
|
if len(usersStringSlice) == 0 {
|
||||||
|
http.Error(response, "no users to add", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var ids [MaxUsersInGroup]uint32
|
||||||
|
var idx uint32 = 0
|
||||||
|
for _, s := range usersStringSlice {
|
||||||
|
if idx >= MaxUsersInGroup {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
id, err := ConvertStringUint32(strings.TrimSpace(s))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ids[idx] = id
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
if idx == 0 {
|
||||||
|
http.Error(response, "no valid users", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = DbGroupAddUsers(ctx, group.Id, &ids)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint32(0); i < idx; i++ {
|
||||||
|
group.Users[ids[i]] = struct{}{}
|
||||||
|
if cachedUser, err := CacheGetUserById(ids[i]); err == nil {
|
||||||
|
cachedUser.Mu.Lock()
|
||||||
|
cachedUser.Groups[group.Id] = struct{}{}
|
||||||
|
cachedUser.Mu.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleGroupRemoveUser(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := request.Context()
|
||||||
|
|
||||||
|
_, group, err := getIfOwnerUserAndGroup(ctx, &response, request)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
usersString := request.FormValue("users")
|
||||||
|
|
||||||
|
usersStringSlice := strings.SplitN(usersString, ",", int(MaxUsersInGroup)+1)
|
||||||
|
|
||||||
|
var ids [MaxUsersInGroup]uint32
|
||||||
|
var idx uint32 = 0
|
||||||
|
for _, s := range usersStringSlice {
|
||||||
|
if idx >= MaxUsersInGroup {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
id, err := ConvertStringUint32(strings.TrimSpace(s))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ids[idx] = id
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
if idx == 0 {
|
||||||
|
http.Error(response, "no valid users", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err := DbGroupRemoveUsers(ctx, group.Id, &ids)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint32(0); i < idx; i++ {
|
||||||
|
delete(group.Users, ids[i])
|
||||||
|
if cachedUser, err := CacheGetUserById(ids[i]); err == nil {
|
||||||
|
cachedUser.Mu.Lock()
|
||||||
|
delete(cachedUser.Groups, group.Id)
|
||||||
|
cachedUser.Mu.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
response.Write([]byte(strconv.Itoa(count)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleGroupChangeColor(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := request.Context()
|
||||||
|
_, group, err := getIfOwnerUserAndGroup(ctx, &response, request)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
color, err := ConvertStringToRgb(request.FormValue("color"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid color", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
group.Color = color
|
||||||
|
err = DbGroupSetColor(ctx, group)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
response.Write([]byte("changed"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleGroupChangeOwner(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := request.Context()
|
||||||
|
_, group, err := getIfOwnerUserAndGroup(ctx, &response, request)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newOwnerName := request.FormValue("newOwner")
|
||||||
|
|
||||||
|
newOwner, err := CacheGetUserByName(newOwnerName)
|
||||||
|
if err != nil {
|
||||||
|
newOwner = &User{Name: newOwnerName}
|
||||||
|
err = DbUserGetStandardInfoByName(ctx, newOwner)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "user not in group", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = DbGetWholeUser(ctx, newOwner); err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok := group.Users[newOwner.Id]
|
||||||
|
if !ok {
|
||||||
|
http.Error(response, "user not in group", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
group.OwnerId = newOwner.Id
|
||||||
|
err = DbGroupSetOwnerId(ctx, group)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleGroupMessage(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := request.Context()
|
||||||
|
|
||||||
|
user, err := GetUserByToken(ctx, request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
groupIdStr := request.FormValue("groupid")
|
||||||
|
groupId, err := ConvertStringUint32(groupIdStr)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "no such group", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
group, err := GetGroup(ctx, groupId)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "no such group", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
content := request.FormValue("content")
|
||||||
|
if content == "" {
|
||||||
|
http.Error(response, "empty message", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok := group.Users[user.Id]
|
||||||
|
if !ok {
|
||||||
|
http.Error(response, "no such group", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = WsSendToGroup(group, user, content)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleGroupsGetWithoutMembers(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := request.Context()
|
||||||
|
|
||||||
|
user, err := GetUserByToken(ctx, request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Mu.RLock()
|
||||||
|
groupIds := make([]uint32, 0, len(user.Groups))
|
||||||
|
for groupId := range user.Groups {
|
||||||
|
groupIds = append(groupIds, groupId)
|
||||||
|
}
|
||||||
|
user.Mu.RUnlock()
|
||||||
|
|
||||||
|
groups := make(map[uint32]*Group, len(groupIds))
|
||||||
|
for _, groupId := range groupIds {
|
||||||
|
group, err := GetGroup(ctx, groupId)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
groups[groupId] = group
|
||||||
|
}
|
||||||
|
|
||||||
|
json, err := json2.Marshal(groups)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
response.Write(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleGroupMembersGet(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := request.Context()
|
||||||
|
user, err := GetUserByToken(ctx, request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
groupStr := request.FormValue("group")
|
||||||
|
groupId, err := ConvertStringUint32(groupStr)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid group", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Mu.RLock()
|
||||||
|
_, ok := user.Groups[groupId]
|
||||||
|
user.Mu.RUnlock()
|
||||||
|
if !ok {
|
||||||
|
http.Error(response, "no such group", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
group, err := GetGroup(ctx, groupId)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "no such group", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
groupMembers := slices.Collect(maps.Keys(group.Users))
|
||||||
|
|
||||||
|
json, err := json2.Marshal(groupMembers)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
response.Write(json)
|
||||||
|
}
|
||||||
+192
@@ -0,0 +1,192 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
json2 "encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HttpHandleTokenNew(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
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 password", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
user *User
|
||||||
|
err error
|
||||||
|
ctx = request.Context()
|
||||||
|
)
|
||||||
|
|
||||||
|
user, err = CacheGetUserByName(username)
|
||||||
|
if err != nil {
|
||||||
|
user = &User{Name: username}
|
||||||
|
if err = DbUserGetStandardInfoByName(ctx, user); err != nil {
|
||||||
|
http.Error(response, "bad login", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = DbGetWholeUser(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 := TokenCreate(user.Id)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error2", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
json, err := json2.Marshal(LoginReturn{Token: token, UserId: user.Id})
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error3", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusCreated)
|
||||||
|
response.Write(json)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleUserNew(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
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 password", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
color, err := ConvertStringToRgb(request.FormValue("color"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "bad color", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hashedPassword, err := PasswordHash(password)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newUser := &User{
|
||||||
|
Name: username,
|
||||||
|
PasswordHash: hashedPassword,
|
||||||
|
Color: color,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := request.Context()
|
||||||
|
|
||||||
|
err = DbUserSave(ctx, newUser)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "name taken", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteHeader(http.StatusCreated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpHandleUserDelete(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := request.Context()
|
||||||
|
|
||||||
|
userId, err := TokenValidateGetId(request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = DbUserDelete(ctx, userId)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
CacheDeleteUser(userId)
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HttpHandleUserModifyAppearance currently just color
|
||||||
|
func HttpHandleUserModifyAppearance(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := request.Context()
|
||||||
|
user, err := GetUserByToken(ctx, request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
color, err := ConvertStringToRgb(request.FormValue("color"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid color", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
user.Color = color
|
||||||
|
err = DbUserSetColor(ctx, user)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HttpHandleUserModifyAbout currently just pronouns
|
||||||
|
func HttpHandleUserModifyAbout(response http.ResponseWriter, request *http.Request) {
|
||||||
|
if !HttpMethodAllowed(&response, request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := request.Context()
|
||||||
|
user, err := GetUserByToken(ctx, request.FormValue("token"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "invalid token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pronouns := request.FormValue("pronouns")
|
||||||
|
if len(pronouns) > 25 || len(pronouns) < 2 {
|
||||||
|
http.Error(response, "invalid pronouns", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Pronouns = pronouns
|
||||||
|
err = DbUserSetPronouns(ctx, user)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(response, "internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.WriteHeader(http.StatusAccepted)
|
||||||
|
}
|
||||||
@@ -68,7 +68,6 @@ type Message struct {
|
|||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
Sender uint32 `json:"sender"`
|
Sender uint32 `json:"sender"`
|
||||||
Receiver uuid.UUID `json:"receiver"`
|
Receiver uuid.UUID `json:"receiver"`
|
||||||
IsGroupMessage bool `json:"isGroupMessage"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Group struct {
|
type Group struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user