dkforest

A forum and chat platform (onion)
git clone https://git.dasho.dev/n0tr1v/dkforest.git
Log | Files | Refs | LICENSE

commit 0f28720d39dbc79636a7c7e566990d316af1d2f3
parent 8be8abdf59cf72c8d6c1dbc225dc2ecc5aac0bf9
Author: n0tr1v <n0tr1v@protonmail.com>
Date:   Mon, 12 Jun 2023 20:16:01 -0700

move code

Diffstat:
Mpkg/web/handlers/chat.go | 235+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpkg/web/handlers/handlers.go | 231-------------------------------------------------------------------------------
2 files changed, 235 insertions(+), 231 deletions(-)

diff --git a/pkg/web/handlers/chat.go b/pkg/web/handlers/chat.go @@ -4,11 +4,19 @@ import ( "dkforest/pkg/captcha" "dkforest/pkg/config" "dkforest/pkg/database" + dutils "dkforest/pkg/database/utils" + "dkforest/pkg/hashset" "dkforest/pkg/managers" "dkforest/pkg/utils" hutils "dkforest/pkg/web/handlers/utils" + "github.com/PuerkitoBio/goquery" + "github.com/asaskevich/govalidator" + "github.com/jinzhu/gorm" "github.com/labstack/echo" + "github.com/sirupsen/logrus" "net/http" + "strconv" + "strings" "time" ) @@ -190,3 +198,230 @@ func handleChatPasswordPost(db *database.DkfDB, c echo.Context, data chatData, a hutils.CreateRoomCookie(c, int64(data.Room.ID), hashedPassword, key) return c.Redirect(http.StatusFound, "/chat/"+data.Room.Name) } + +func ChatArchiveHandler(c echo.Context) error { + authUser := c.Get("authUser").(*database.User) + db := c.Get("database").(*database.DkfDB) + var data chatArchiveData + data.DateFormat = authUser.GetDateFormat() + roomName := c.Param("roomName") + + room, roomKey, err := dutils.GetRoomAndKey(db, c, roomName) + if err != nil { + return c.Redirect(http.StatusFound, "/chat") + } + + data.UUID = c.QueryParam("uuid") + data.Room = room + + if data.UUID != "" { + msg, err := db.GetRoomChatMessageByUUID(room.ID, data.UUID) + if err != nil { + return c.Redirect(http.StatusFound, "/") + } + nbMsg := 150 + args := []any{room.ID, authUser.ID, authUser.ID} + whereClause := `room_id = ? AND group_id IS NULL AND (to_user_id is null OR to_user_id = ? OR user_id = ?)` + if !authUser.DisplayIgnored { + args = append(args, authUser.ID) + whereClause += ` AND user_id NOT IN (SELECT ignored_user_id FROM ignored_users WHERE user_id = ?)` + } + raw := ` + SELECT * FROM ( + SELECT * + FROM chat_messages + WHERE ` + whereClause + ` + AND id >= ? + ORDER BY id ASC + LIMIT ? + ) + UNION + SELECT * FROM ( + SELECT * + FROM chat_messages + WHERE ` + whereClause + ` + AND id < ? + ORDER BY id DESC + LIMIT ? + ) ORDER BY id DESC` + args = append(args, msg.ID, nbMsg) + args = append(args, args...) + db.DB().Raw(raw, args...).Scan(&data.Messages) + + // Manually do Preload("Room") + for _, m := range data.Messages { + m.Room = data.Room + } + + //--- < Manually do a Preload("User") Preload("ToUser") > --- + usersIDs := hashset.New[database.UserID]() + for _, m := range data.Messages { + usersIDs.Insert(m.UserID) + if m.ToUserID != nil { + usersIDs.Insert(*m.ToUserID) + } + } + users, _ := db.GetUsersByID(usersIDs.ToArray()) + usersMap := make(map[database.UserID]database.User) + for _, u := range users { + usersMap[u.ID] = u + } + for i, m := range data.Messages { + if u, ok := usersMap[m.UserID]; ok { + data.Messages[i].User = u + } + if m.ToUserID != nil { + if u, ok := usersMap[*m.ToUserID]; ok { + data.Messages[i].ToUser = &u + } + } + } + //--- </ Manually do a Preload("User") Preload("ToUser") > --- + + } else { + if err := db.DB().Table("chat_messages"). + Where("room_id = ? AND group_id IS NULL AND (to_user_id is null OR to_user_id = ? OR user_id = ?)", room.ID, authUser.ID, authUser.ID). + Scopes(func(query *gorm.DB) *gorm.DB { + if !authUser.DisplayIgnored { + query = query.Where(`user_id NOT IN (SELECT ignored_user_id FROM ignored_users WHERE user_id = ?)`, authUser.ID) + } + data.CurrentPage, data.MaxPage, data.MessagesCount, query = NewPaginator().SetResultPerPage(300).Paginate(c, query) + return query + }). + Order("id DESC"). + Preload("Room"). + Preload("User"). + Preload("ToUser"). + Find(&data.Messages).Error; err != nil { + logrus.Error(err) + } + } + + if roomKey != "" { + if err := data.Messages.DecryptAll(roomKey); err != nil { + return c.NoContent(http.StatusInternalServerError) + } + } + + return c.Render(http.StatusOK, "chat-archive", data) +} + +func ChatDeleteHandler(c echo.Context) error { + authUser := c.Get("authUser").(*database.User) + db := c.Get("database").(*database.DkfDB) + var data chatDeleteData + roomName := c.Param("roomName") + room, err := db.GetChatRoomByName(roomName) + if err != nil { + return c.Redirect(http.StatusFound, "/") + } + if !room.IsRoomOwner(*authUser) { + return c.Redirect(http.StatusFound, "/") + } + data.Room = room + + if c.Request().Method == http.MethodPost { + if room.IsProtected() { + hutils.DeleteRoomCookie(c, int64(room.ID)) + } + db.DeleteChatRoomByID(room.ID) + return c.Redirect(http.StatusFound, "/chat") + } + + return c.Render(http.StatusOK, "chat-delete", data) +} + +func RoomChatSettingsHandler(c echo.Context) error { + authUser := c.Get("authUser").(*database.User) + db := c.Get("database").(*database.DkfDB) + var data roomChatSettingsData + roomName := c.Param("roomName") + room, err := db.GetChatRoomByName(roomName) + if err != nil { + return c.Redirect(http.StatusFound, "/") + } + if !room.IsRoomOwner(*authUser) { + return c.Redirect(http.StatusFound, "/") + } + data.Room = room + + if c.Request().Method == http.MethodPost { + return c.Redirect(http.StatusFound, "/chat") + } + + return c.Render(http.StatusOK, "chat-room-settings", data) +} + +func ChatCreateRoomHandler(c echo.Context) error { + authUser := c.Get("authUser").(*database.User) + db := c.Get("database").(*database.DkfDB) + var data chatCreateRoomData + data.CaptchaID, data.CaptchaImg = captcha.New() + data.IsEphemeral = true + if c.Request().Method == http.MethodPost { + data.RoomName = c.Request().PostFormValue("room_name") + data.Password = c.Request().PostFormValue("password") + data.IsListed = utils.DoParseBool(c.Request().PostFormValue("is_listed")) + data.IsEphemeral = utils.DoParseBool(c.Request().PostFormValue("is_ephemeral")) + if !govalidator.Matches(data.RoomName, "^[a-zA-Z0-9_]{3,50}$") { + data.ErrorRoomName = "invalid room name" + return c.Render(http.StatusOK, "chat-create-room", data) + } + captchaID := c.Request().PostFormValue("captcha_id") + captchaInput := c.Request().PostFormValue("captcha") + if err := hutils.CaptchaVerifyString(c, captchaID, captchaInput); err != nil { + data.ErrCaptcha = err.Error() + return c.Render(http.StatusOK, "chat-create-room", data) + } + passwordHash := "" + if data.Password != "" { + passwordHash = database.GetRoomPasswordHash(data.Password) + } + if _, err := db.CreateRoom(data.RoomName, passwordHash, authUser.ID, data.IsListed); err != nil { + data.Error = err.Error() + return c.Render(http.StatusOK, "chat-create-room", data) + } + return c.Redirect(http.StatusFound, "/chat/"+data.RoomName) + } + return c.Render(http.StatusOK, "chat-create-room", data) +} + +func ChatCodeHandler(c echo.Context) error { + messageUUID := c.Param("messageUUID") + idx, err := strconv.Atoi(c.Param("idx")) + if err != nil { + return c.Redirect(http.StatusFound, "/") + } + + authUser := c.Get("authUser").(*database.User) + db := c.Get("database").(*database.DkfDB) + msg, err := db.GetChatMessageByUUID(messageUUID) + if err != nil { + return c.Redirect(http.StatusFound, "/") + } + + if !verifyMsgAuth(db, authUser, &msg) { + return c.Redirect(http.StatusFound, "/") + } + + doc, err := goquery.NewDocumentFromReader(strings.NewReader(msg.Message)) + if err != nil { + return c.Redirect(http.StatusFound, "/") + } + n := doc.Find("pre").Eq(idx) + if n == nil { + return c.Redirect(http.StatusFound, "/") + } + + var data chatCodepData + data.Code, err = n.Html() + if err != nil { + return c.Redirect(http.StatusFound, "/") + } + return c.Render(http.StatusOK, "chat-code", data) +} + +func ChatHelpHandler(c echo.Context) error { + var data chatHelpData + return c.Render(http.StatusOK, "chat-help", data) +} diff --git a/pkg/web/handlers/handlers.go b/pkg/web/handlers/handlers.go @@ -4,7 +4,6 @@ import ( "bytes" "context" dutils "dkforest/pkg/database/utils" - "dkforest/pkg/hashset" "dkforest/pkg/odometer" "dkforest/pkg/pubsub" v1 "dkforest/pkg/web/handlers/api/v1" @@ -13,8 +12,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/PuerkitoBio/goquery" - "github.com/jinzhu/gorm" _ "golang.org/x/image/bmp" _ "golang.org/x/image/webp" "image" @@ -28,7 +25,6 @@ import ( "os/signal" "path/filepath" "regexp" - "strconv" "strings" "syscall" "time" @@ -1309,32 +1305,6 @@ func getWaitPageDuration() int64 { return secs } -func ChatHelpHandler(c echo.Context) error { - var data chatHelpData - return c.Render(http.StatusOK, "chat-help", data) -} - -func RoomChatSettingsHandler(c echo.Context) error { - authUser := c.Get("authUser").(*database.User) - db := c.Get("database").(*database.DkfDB) - var data roomChatSettingsData - roomName := c.Param("roomName") - room, err := db.GetChatRoomByName(roomName) - if err != nil { - return c.Redirect(http.StatusFound, "/") - } - if !room.IsRoomOwner(*authUser) { - return c.Redirect(http.StatusFound, "/") - } - data.Room = room - - if c.Request().Method == http.MethodPost { - return c.Redirect(http.StatusFound, "/chat") - } - - return c.Render(http.StatusOK, "chat-room-settings", data) -} - func ExternalLink1Handler(c echo.Context) error { original, _ := url.PathUnescape(c.Param("original")) var data externalLink1Data @@ -1362,40 +1332,6 @@ func ExternalLinkHandler(c echo.Context) error { return c.Redirect(http.StatusFound, baseURL+"/"+original) } -func ChatCreateRoomHandler(c echo.Context) error { - authUser := c.Get("authUser").(*database.User) - db := c.Get("database").(*database.DkfDB) - var data chatCreateRoomData - data.CaptchaID, data.CaptchaImg = captcha.New() - data.IsEphemeral = true - if c.Request().Method == http.MethodPost { - data.RoomName = c.Request().PostFormValue("room_name") - data.Password = c.Request().PostFormValue("password") - data.IsListed = utils.DoParseBool(c.Request().PostFormValue("is_listed")) - data.IsEphemeral = utils.DoParseBool(c.Request().PostFormValue("is_ephemeral")) - if !govalidator.Matches(data.RoomName, "^[a-zA-Z0-9_]{3,50}$") { - data.ErrorRoomName = "invalid room name" - return c.Render(http.StatusOK, "chat-create-room", data) - } - captchaID := c.Request().PostFormValue("captcha_id") - captchaInput := c.Request().PostFormValue("captcha") - if err := hutils.CaptchaVerifyString(c, captchaID, captchaInput); err != nil { - data.ErrCaptcha = err.Error() - return c.Render(http.StatusOK, "chat-create-room", data) - } - passwordHash := "" - if data.Password != "" { - passwordHash = database.GetRoomPasswordHash(data.Password) - } - if _, err := db.CreateRoom(data.RoomName, passwordHash, authUser.ID, data.IsListed); err != nil { - data.Error = err.Error() - return c.Render(http.StatusOK, "chat-create-room", data) - } - return c.Redirect(http.StatusFound, "/chat/"+data.RoomName) - } - return c.Render(http.StatusOK, "chat-create-room", data) -} - func DonateHandler(c echo.Context) error { return c.Render(http.StatusOK, "donate", nil) } @@ -1420,138 +1356,6 @@ func ShopHandler(c echo.Context) error { return c.Render(http.StatusOK, "shop", data) } -func ChatDeleteHandler(c echo.Context) error { - authUser := c.Get("authUser").(*database.User) - db := c.Get("database").(*database.DkfDB) - var data chatDeleteData - roomName := c.Param("roomName") - room, err := db.GetChatRoomByName(roomName) - if err != nil { - return c.Redirect(http.StatusFound, "/") - } - if !room.IsRoomOwner(*authUser) { - return c.Redirect(http.StatusFound, "/") - } - data.Room = room - - if c.Request().Method == http.MethodPost { - if room.IsProtected() { - hutils.DeleteRoomCookie(c, int64(room.ID)) - } - db.DeleteChatRoomByID(room.ID) - return c.Redirect(http.StatusFound, "/chat") - } - - return c.Render(http.StatusOK, "chat-delete", data) -} - -func ChatArchiveHandler(c echo.Context) error { - authUser := c.Get("authUser").(*database.User) - db := c.Get("database").(*database.DkfDB) - var data chatArchiveData - data.DateFormat = authUser.GetDateFormat() - roomName := c.Param("roomName") - - room, roomKey, err := dutils.GetRoomAndKey(db, c, roomName) - if err != nil { - return c.Redirect(http.StatusFound, "/chat") - } - - data.UUID = c.QueryParam("uuid") - data.Room = room - - if data.UUID != "" { - msg, err := db.GetRoomChatMessageByUUID(room.ID, data.UUID) - if err != nil { - return c.Redirect(http.StatusFound, "/") - } - nbMsg := 150 - args := []any{room.ID, authUser.ID, authUser.ID} - whereClause := `room_id = ? AND group_id IS NULL AND (to_user_id is null OR to_user_id = ? OR user_id = ?)` - if !authUser.DisplayIgnored { - args = append(args, authUser.ID) - whereClause += ` AND user_id NOT IN (SELECT ignored_user_id FROM ignored_users WHERE user_id = ?)` - } - raw := ` - SELECT * FROM ( - SELECT * - FROM chat_messages - WHERE ` + whereClause + ` - AND id >= ? - ORDER BY id ASC - LIMIT ? - ) - UNION - SELECT * FROM ( - SELECT * - FROM chat_messages - WHERE ` + whereClause + ` - AND id < ? - ORDER BY id DESC - LIMIT ? - ) ORDER BY id DESC` - args = append(args, msg.ID, nbMsg) - args = append(args, args...) - db.DB().Raw(raw, args...).Scan(&data.Messages) - - // Manually do Preload("Room") - for _, m := range data.Messages { - m.Room = data.Room - } - - //--- < Manually do a Preload("User") Preload("ToUser") > --- - usersIDs := hashset.New[database.UserID]() - for _, m := range data.Messages { - usersIDs.Insert(m.UserID) - if m.ToUserID != nil { - usersIDs.Insert(*m.ToUserID) - } - } - users, _ := db.GetUsersByID(usersIDs.ToArray()) - usersMap := make(map[database.UserID]database.User) - for _, u := range users { - usersMap[u.ID] = u - } - for i, m := range data.Messages { - if u, ok := usersMap[m.UserID]; ok { - data.Messages[i].User = u - } - if m.ToUserID != nil { - if u, ok := usersMap[*m.ToUserID]; ok { - data.Messages[i].ToUser = &u - } - } - } - //--- </ Manually do a Preload("User") Preload("ToUser") > --- - - } else { - if err := db.DB().Table("chat_messages"). - Where("room_id = ? AND group_id IS NULL AND (to_user_id is null OR to_user_id = ? OR user_id = ?)", room.ID, authUser.ID, authUser.ID). - Scopes(func(query *gorm.DB) *gorm.DB { - if !authUser.DisplayIgnored { - query = query.Where(`user_id NOT IN (SELECT ignored_user_id FROM ignored_users WHERE user_id = ?)`, authUser.ID) - } - data.CurrentPage, data.MaxPage, data.MessagesCount, query = NewPaginator().SetResultPerPage(300).Paginate(c, query) - return query - }). - Order("id DESC"). - Preload("Room"). - Preload("User"). - Preload("ToUser"). - Find(&data.Messages).Error; err != nil { - logrus.Error(err) - } - } - - if roomKey != "" { - if err := data.Messages.DecryptAll(roomKey); err != nil { - return c.NoContent(http.StatusInternalServerError) - } - } - - return c.Render(http.StatusOK, "chat-archive", data) -} - type ValueTokenCache struct { Value string // Either age/pgp token or msg to sign PKey string // age/pgp public key @@ -2579,38 +2383,3 @@ Loop: c.Response().Flush() return nil } - -func ChatCodeHandler(c echo.Context) error { - messageUUID := c.Param("messageUUID") - idx, err := strconv.Atoi(c.Param("idx")) - if err != nil { - return c.Redirect(http.StatusFound, "/") - } - - authUser := c.Get("authUser").(*database.User) - db := c.Get("database").(*database.DkfDB) - msg, err := db.GetChatMessageByUUID(messageUUID) - if err != nil { - return c.Redirect(http.StatusFound, "/") - } - - if !verifyMsgAuth(db, authUser, &msg) { - return c.Redirect(http.StatusFound, "/") - } - - doc, err := goquery.NewDocumentFromReader(strings.NewReader(msg.Message)) - if err != nil { - return c.Redirect(http.StatusFound, "/") - } - n := doc.Find("pre").Eq(idx) - if n == nil { - return c.Redirect(http.StatusFound, "/") - } - - var data chatCodepData - data.Code, err = n.Html() - if err != nil { - return c.Redirect(http.StatusFound, "/") - } - return c.Render(http.StatusOK, "chat-code", data) -}