dkforest

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

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 }