discord.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. package util
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strings"
  6. "github.com/rigormorrtiss/discordgo"
  7. "github.com/rivo/tview"
  8. )
  9. // WriteMessage parses, renders, and writes a message to the given TextView.
  10. func WriteMessage(v *tview.TextView, m *discordgo.Message, clientID string) {
  11. var b strings.Builder
  12. switch m.Type {
  13. case discordgo.MessageTypeDefault, discordgo.MessageTypeReply:
  14. // Define a new region and assign message ID as the region ID.
  15. // Learn more: https://pkg.go.dev/github.com/rivo/tview#hdr-Regions_and_Highlights
  16. b.WriteString("[\"")
  17. b.WriteString(m.ID)
  18. b.WriteString("\"]")
  19. // Render the message associated with crosspost, channel follow add, pin, or a reply.
  20. if rm := m.ReferencedMessage; rm != nil {
  21. b.WriteString(" ╭ ")
  22. b.WriteString("[::d]")
  23. parseAuthor(&b, rm.Author, clientID)
  24. if rm.Content != "" {
  25. rm.Content = parseMessageMentions(rm.Content, rm.Mentions, clientID)
  26. b.WriteString(rm.Content)
  27. }
  28. b.WriteString("[::-]\n")
  29. }
  30. // Render the author of the message.
  31. parseAuthor(&b, m.Author, clientID)
  32. // If the message content is not empty, parse the message mentions (users mentioned in the message) and render the message content.
  33. if m.Content != "" {
  34. m.Content = parseMessageMentions(m.Content, m.Mentions, clientID)
  35. b.WriteString(m.Content)
  36. }
  37. // If the edited timestamp of the message is not empty; it implies that the message has been edited, hence render the message with edited label for distinction
  38. if m.EditedTimestamp != "" {
  39. b.WriteString(" [::d](edited)[::-]")
  40. }
  41. // TODO: render message embeds
  42. for range m.Embeds {
  43. b.WriteString("\n<EMBED>")
  44. }
  45. // Render the message attachments (attached files to the message).
  46. for _, a := range m.Attachments {
  47. b.WriteString("\n[")
  48. b.WriteString(a.Filename)
  49. b.WriteString("]: ")
  50. b.WriteString(a.URL)
  51. }
  52. fmt.Fprintln(v, b.String())
  53. case discordgo.MessageTypeGuildMemberJoin:
  54. b.WriteString("[#5865F2]")
  55. b.WriteString(m.Author.Username)
  56. b.WriteString("[-]")
  57. b.WriteString(" joined the server")
  58. fmt.Fprintln(v, b.String())
  59. }
  60. }
  61. func parseMessageMentions(content string, mentions []*discordgo.User, clientID string) string {
  62. for _, mUser := range mentions {
  63. var color string
  64. if mUser.ID == clientID {
  65. color = "[:#5865F2]"
  66. } else {
  67. color = "[#EB459E]"
  68. }
  69. content = strings.NewReplacer(
  70. // <@USER_ID>
  71. "<@"+mUser.ID+">",
  72. color+"@"+mUser.Username+"[-:-]",
  73. // <@!USER_ID>
  74. "<@!"+mUser.ID+">",
  75. color+"@"+mUser.Username+"[-:-]",
  76. ).Replace(content)
  77. }
  78. return content
  79. }
  80. func parseAuthor(b *strings.Builder, u *discordgo.User, clientID string) {
  81. // If the message author is the client, modify the text color for distinction.
  82. if u.ID == clientID {
  83. b.WriteString("[#57F287]")
  84. } else {
  85. b.WriteString("[#ED4245]")
  86. }
  87. b.WriteString(u.Username)
  88. b.WriteString("[-] ")
  89. // If the message author is a bot account, render the message with bot label for distinction.
  90. if u.Bot {
  91. b.WriteString("[#EB459E]BOT[-] ")
  92. }
  93. }
  94. type loginResponse struct {
  95. MFA bool `json:"mfa"`
  96. SMS bool `json:"sms"`
  97. Ticket string `json:"ticket"`
  98. Token string `json:"token"`
  99. }
  100. // Login creates a new request to the `/login` endpoint for essential login information.
  101. func Login(s *discordgo.Session, email, password string) (*loginResponse, error) {
  102. data := struct {
  103. Email string `json:"email"`
  104. Password string `json:"password"`
  105. }{email, password}
  106. resp, err := s.RequestWithBucketID("POST", discordgo.EndpointLogin, data, discordgo.EndpointLogin)
  107. if err != nil {
  108. return nil, err
  109. }
  110. var lr loginResponse
  111. err = json.Unmarshal(resp, &lr)
  112. if err != nil {
  113. return nil, err
  114. }
  115. return &lr, nil
  116. }
  117. // TOTP creates a new request to `/mfa/totp` endpoint for time-based one-time
  118. // passcode for essential login information
  119. func TOTP(s *discordgo.Session, code, ticket string) (*loginResponse, error) {
  120. data := struct {
  121. Code string `json:"code"`
  122. Ticket string `json:"ticket"`
  123. }{code, ticket}
  124. e := discordgo.EndpointAuth + "mfa/totp"
  125. resp, err := s.RequestWithBucketID("POST", e, data, e)
  126. if err != nil {
  127. return nil, err
  128. }
  129. var lr loginResponse
  130. err = json.Unmarshal(resp, &lr)
  131. if err != nil {
  132. return nil, err
  133. }
  134. return &lr, nil
  135. }
  136. // HasPermission returns a boolean representing whether the provided user has given permissions or not.
  137. func HasPermission(s *discordgo.State, uID string, cID string, perm int64) bool {
  138. p, err := s.UserChannelPermissions(uID, cID)
  139. if err != nil {
  140. return false
  141. }
  142. return p&perm == perm
  143. }