diff --git a/Readme.md b/Readme.md index 59d5032..bf11e61 100644 --- a/Readme.md +++ b/Readme.md @@ -10,14 +10,14 @@ - [ ] status - [ ] bio - [ ] profile picture -- [ ] provide user info +- [x] provide user info - manage rights and roles - [ ] edit roles - [ ] bind roles to users - manage messages - - [ ] send - - [ ] alert - - [ ] query + - [x] send + - [x] alert + - [x] query - files - [ ] upload - [ ] serve diff --git a/api/chat.go b/api/chat.go index 00e0d58..933e686 100644 --- a/api/chat.go +++ b/api/chat.go @@ -4,13 +4,17 @@ import ( "fmt" "net/http" "strconv" + "time" "git.tek.govt.hu/dowerx/chat/server/model" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" ) -const CHANNEL_ID string = "id" +const ( + CHANNEL_ID string = "id" + DEFAULT_MESSAGE_LIMIT int = 100 +) var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, @@ -42,7 +46,36 @@ func getMessages(c *gin.Context) { return } - messages, msgErr := chatController.GetMessages(id) + limitStr := c.Query("limit") + fromStr := c.Query("from") + + var limit int = DEFAULT_MESSAGE_LIMIT + var from time.Time = time.Now().UTC() + var parseErr error + + if limitStr != "" { + limit, parseErr = strconv.Atoi(limitStr) + if parseErr != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "error": "invalid limit parameter", + }) + return + } + } + + if fromStr != "" { + from, parseErr = time.Parse(time.RFC3339, fromStr) + if parseErr != nil { + c.JSON(http.StatusBadRequest, gin.H{ + "error": "invalid from parameter", + }) + return + } + } + + fmt.Println(from, limit) + + messages, msgErr := chatController.GetMessages(id, from, limit) if msgErr != nil { sendError(c, msgErr) return diff --git a/controller/ChatController.go b/controller/ChatController.go index ed2c7df..982c132 100644 --- a/controller/ChatController.go +++ b/controller/ChatController.go @@ -26,8 +26,8 @@ func (c ChatController) ListAvailableChannels(token string) ([]model.Channel, *u return c.channelDAO.ListAvailableChannels(userID) } -func (c ChatController) GetMessages(channel int) ([]model.Message, *util.ChatError) { - return c.messageDAO.List(model.Channel{ID: channel}) +func (c ChatController) GetMessages(channel int, from time.Time, limit int) ([]model.Message, *util.ChatError) { + return c.messageDAO.List(model.Channel{ID: channel}, from, limit) } func (c ChatController) SendMessage(token string, channel int, content string) *util.ChatError { diff --git a/dao/IMessageDAO.go b/dao/IMessageDAO.go index fe70d41..de3d4b2 100644 --- a/dao/IMessageDAO.go +++ b/dao/IMessageDAO.go @@ -1,6 +1,8 @@ package dao import ( + "time" + "git.tek.govt.hu/dowerx/chat/server/model" "git.tek.govt.hu/dowerx/chat/server/util" ) @@ -8,7 +10,7 @@ import ( type IMessageDAO interface { Create(message model.Message) (int, *util.ChatError) Read(id int) (model.Message, *util.ChatError) - List(channel model.Channel) ([]model.Message, *util.ChatError) + List(channel model.Channel, from time.Time, limit int) ([]model.Message, *util.ChatError) Update(message model.Message) *util.ChatError Delete(id int) *util.ChatError } diff --git a/dao/postgres/MessageDAO.go b/dao/postgres/MessageDAO.go index 23199e4..8f767af 100644 --- a/dao/postgres/MessageDAO.go +++ b/dao/postgres/MessageDAO.go @@ -1,6 +1,9 @@ package postgres import ( + "slices" + "time" + "git.tek.govt.hu/dowerx/chat/server/model" "git.tek.govt.hu/dowerx/chat/server/util" "github.com/jmoiron/sqlx" @@ -50,9 +53,18 @@ func (d MessageDAO) Read(id int) (model.Message, *util.ChatError) { } // List all messages in channel by ID or name -func (d MessageDAO) List(channel model.Channel) ([]model.Message, *util.ChatError) { +func (d MessageDAO) List(channel model.Channel, from time.Time, limit int) ([]model.Message, *util.ChatError) { + + type queryInfo struct { + ID int `db:"id"` + Name string `db:"name"` + From time.Time `db:"from"` + Limit int `db:"limit"` + } + var rows *sqlx.Rows var err error + if channel.ID != 0 { rows, err = d.db.NamedQuery( `select @@ -63,8 +75,10 @@ func (d MessageDAO) List(channel model.Channel) ([]model.Message, *util.ChatErro "m"."content" as "content" from "message" as "m" inner join "user" "u" on "u"."id" = "m"."sender_id" - where "m"."channel_id" = :id order by "time"`, - &channel) + where "m"."channel_id" = :id and "m"."time" < :from + order by "time" desc + limit :limit`, + &queryInfo{ID: channel.ID, From: from, Limit: limit}) } else { rows, err = d.db.NamedQuery( `select @@ -76,8 +90,10 @@ func (d MessageDAO) List(channel model.Channel) ([]model.Message, *util.ChatErro from "message" as "m" inner join "user" "u" on "u"."id" = "m"."sender_id" inner join "channel" "c" on "c"."id" = "m"."channel_id" - where "c"."name" = :name order by "time"`, - &channel) + where "c"."name" = :name and "m"."time" < :from + order by "time" desc + limit :limit`, + &queryInfo{Name: channel.Name, From: from, Limit: limit}) } if err != nil { @@ -98,6 +114,7 @@ func (d MessageDAO) List(channel model.Channel) ([]model.Message, *util.ChatErro messages = append(messages, message) } + slices.Reverse(messages) return messages, util.MakeError(err, util.DATABASE_QUERY_FAULT) }