command.go (6410B)
1 package command 2 3 import ( 4 "dkforest/pkg/database" 5 dutils "dkforest/pkg/database/utils" 6 "errors" 7 "fmt" 8 "github.com/labstack/echo" 9 "net/url" 10 ) 11 12 var ErrRedirect = errors.New("redirect") 13 var ErrStop = errors.New("stop") 14 15 type ErrSuccess struct { 16 msg string 17 } 18 19 func NewErrSuccess(msg string) *ErrSuccess { 20 return &ErrSuccess{msg: msg} 21 } 22 23 func (e ErrSuccess) Error() string { 24 return e.msg 25 } 26 27 const ( 28 RedirectPmQP = "pm" 29 RedirectEditQP = "e" 30 RedirectGroupQP = "g" 31 RedirectModQP = "m" 32 RedirectHbmQP = "hbm" 33 RedirectTagQP = "tag" 34 RedirectHTagQP = "htag" 35 RedirectMTagQP = "mtag" 36 RedirectQuoteQP = "quote" 37 RedirectMultilineQP = "ml" 38 RedirectPmUsernameQP = "pmusername" 39 ) 40 41 type Command struct { 42 Err error 43 44 // Data that can be mutated 45 Raw bool // If true, will send raw message 46 RedirectQP url.Values // RedirectURL Query Parameters 47 OrigMessage string // This is the original text that the user input (can be changed by /e) 48 DataMessage string // This is what the user will have in his input box 49 Message string // Un-sanitized message received from the user 50 Room database.ChatRoom // Room the user is in 51 RoomKey string // Room password (if any) 52 AuthUser *database.User // Authenticated user (sender of the message) 53 DB *database.DkfDB // Database instance 54 ToUser *database.User // If not nil, will be a PM 55 Upload *database.Upload // If the message contains an uploaded file 56 EditMsg *database.ChatMessage // If we're editing a message 57 GroupID *database.GroupID // If the message is for a subgroup 58 HellbanMsg bool // Is the message will be marked HB 59 SystemMsg bool // Is the message system 60 ModMsg bool // Is the message part of the "moderators" group 61 C echo.Context 62 SkipInboxes bool 63 64 zeroUser *database.User // Cache the zero (@0) user 65 } 66 67 func NewCommand(c echo.Context, origMessage string, room database.ChatRoom, roomKey string) *Command { 68 authUser := c.Get("authUser").(*database.User) 69 db := c.Get("database").(*database.DkfDB) 70 return &Command{ 71 C: c, 72 AuthUser: authUser, 73 DB: db, 74 HellbanMsg: authUser.IsHellbanned, 75 RedirectQP: url.Values{}, 76 OrigMessage: origMessage, 77 Message: origMessage, 78 Room: room, 79 RoomKey: roomKey, 80 } 81 } 82 83 func (c *Command) RedirectURL() string { 84 return fmt.Sprintf("/api/v1/chat/top-bar/%s?%s", c.Room.Name, c.RedirectQP.Encode()) 85 } 86 87 func (c *Command) RawMessage(raw string) { 88 c.Raw = true 89 c.OrigMessage = "<raw message>" 90 c.Message = raw 91 } 92 93 func (c *Command) SetToUser(username database.Username) (err error) { 94 user, err := c.DB.GetUserByUsername(username) 95 if err != nil { 96 c.Err = errors.New("invalid username") 97 return c.Err 98 } 99 100 c.SkipInboxes, c.Err = dutils.CanUserPmOther(c.DB, *c.AuthUser, user, c.Room.IsOwned()) 101 if c.Err != nil { 102 return c.Err 103 } 104 c.ToUser = &user 105 return nil 106 } 107 108 // GetZeroUser lazy loading and cache of the zero user 109 func (c *Command) GetZeroUser() database.User { 110 if c.zeroUser == nil { 111 zeroUser := dutils.GetZeroUser(c.DB) 112 c.zeroUser = &zeroUser 113 } 114 return *c.zeroUser 115 } 116 117 // ZeroProcMsg have the "zero user" send a processed message to the authUser 118 func (c *Command) ZeroProcMsg(rawMsg string) { 119 c.zeroProcMsgRoom(rawMsg, c.RoomKey, c.Room.ID) 120 } 121 122 // ZeroPublicProcMsgRoom have the "zero user" send a processed message in the specified room 123 func (c *Command) ZeroPublicProcMsgRoom(rawMsg, roomKey string, roomID database.RoomID) { 124 c.zeroProcMsgRoomToUser(rawMsg, roomKey, roomID, nil) 125 } 126 127 // Have the "zero user" send a processed message to the authUser in the specified room 128 func (c *Command) zeroProcMsgRoom(rawMsg, roomKey string, roomID database.RoomID) { 129 c.zeroProcMsgRoomToUser(rawMsg, roomKey, roomID, c.AuthUser) 130 } 131 132 // Have the "zero user" send a "processed message" PM to a user in a specific room. 133 func (c *Command) zeroProcMsgRoomToUser(rawMsg, roomKey string, roomID database.RoomID, toUser *database.User) { 134 procMsg, _, _ := dutils.ProcessRawMessage(c.DB, rawMsg, roomKey, c.AuthUser.ID, roomID, nil, c.AuthUser.IsModerator(), true, false) 135 c.zeroRawMsg(toUser, rawMsg, procMsg) 136 } 137 138 // ZeroMsg have the "zero user" send an unprocessed private message to the authUser 139 func (c *Command) ZeroMsg(msg string) { 140 c.zeroRawMsg(c.AuthUser, msg, msg) 141 } 142 143 // ZeroMsgToUser have the "zero user" send an unprocessed private message to toUser 144 func (c *Command) ZeroMsgToUser(toUser database.User, msg string) { 145 c.zeroRawMsg(&toUser, msg, msg) 146 } 147 148 func (c *Command) ZeroSysMsgTo(user2 *database.User, msg string) { 149 c.zeroSysRawMsg(user2, msg, msg, false) 150 } 151 152 func (c *Command) ZeroSysMsgToSkipNotify(user2 *database.User, msg string) { 153 c.zeroSysRawMsg(user2, msg, msg, true) 154 } 155 156 // ZeroPublicMsg have the "zero user" send an unprocessed message in the current room 157 func (c *Command) ZeroPublicMsg(raw, msg string) { 158 c.zeroRawMsg(nil, raw, msg) 159 } 160 161 func (c *Command) zeroRawMsg(user2 *database.User, raw, msg string) { 162 c.rawMsg(c.GetZeroUser(), user2, raw, msg) 163 } 164 165 func (c *Command) zeroSysRawMsg(user2 *database.User, raw, msg string, skipNotify bool) { 166 c.rawSysMsg(c.GetZeroUser(), user2, raw, msg, skipNotify) 167 } 168 169 func (c *Command) rawMsg(user1 database.User, user2 *database.User, raw, msg string) { 170 if c.Room.ReadOnly { 171 return 172 } 173 rawMsgRoom(c.DB, user1, user2, raw, msg, c.RoomKey, c.Room.ID, c.HellbanMsg) 174 } 175 176 func (c *Command) rawSysMsg(user1 database.User, user2 *database.User, raw, msg string, skipNotify bool) { 177 if c.Room.ReadOnly { 178 return 179 } 180 rawSysMsgRoom(c.DB, user1, user2, raw, msg, c.RoomKey, c.Room.ID, skipNotify) 181 } 182 183 func rawMsgRoom(db *database.DkfDB, user1 database.User, user2 *database.User, raw, msg, roomKey string, roomID database.RoomID, hellbanMsg bool) { 184 var toUserID *database.UserID 185 if user2 != nil { 186 toUserID = &user2.ID 187 } 188 _, _ = db.CreateMsg(raw, msg, roomKey, roomID, user1.ID, toUserID, hellbanMsg) 189 } 190 191 func rawSysMsgRoom(db *database.DkfDB, user1 database.User, user2 *database.User, raw, msg, roomKey string, roomID database.RoomID, skipNotify bool) { 192 var toUserID *database.UserID 193 if user2 != nil { 194 toUserID = &user2.ID 195 } 196 _ = db.CreateSysMsgPM(raw, msg, roomKey, roomID, user1.ID, toUserID, skipNotify) 197 }