message.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. package controller
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "github.com/gin-gonic/gin"
  7. "message-pusher/channel"
  8. "message-pusher/common"
  9. "message-pusher/model"
  10. "net/http"
  11. "strconv"
  12. "time"
  13. )
  14. func keepCompatible(message *model.Message) {
  15. // Keep compatible with ServerChan: https://sct.ftqq.com/sendkey
  16. if message.Description == "" {
  17. message.Description = message.Short
  18. }
  19. if message.Content == "" {
  20. message.Content = message.Desp
  21. }
  22. if message.To == "" {
  23. message.To = message.OpenId
  24. }
  25. }
  26. func GetPushMessage(c *gin.Context) {
  27. message := model.Message{
  28. Title: c.Query("title"),
  29. Description: c.Query("description"),
  30. Content: c.Query("content"),
  31. URL: c.Query("url"),
  32. Channel: c.Query("channel"),
  33. Token: c.Query("token"),
  34. To: c.Query("to"),
  35. Desp: c.Query("desp"),
  36. Short: c.Query("short"),
  37. OpenId: c.Query("openid"),
  38. }
  39. keepCompatible(&message)
  40. pushMessageHelper(c, &message)
  41. }
  42. func PostPushMessage(c *gin.Context) {
  43. message := model.Message{
  44. Title: c.PostForm("title"),
  45. Description: c.PostForm("description"),
  46. Content: c.PostForm("content"),
  47. URL: c.PostForm("url"),
  48. Channel: c.PostForm("channel"),
  49. Token: c.PostForm("token"),
  50. To: c.PostForm("to"),
  51. Desp: c.PostForm("desp"),
  52. Short: c.PostForm("short"),
  53. OpenId: c.PostForm("openid"),
  54. }
  55. if message == (model.Message{}) {
  56. // Looks like the user is using JSON
  57. err := json.NewDecoder(c.Request.Body).Decode(&message)
  58. if err != nil {
  59. c.JSON(http.StatusOK, gin.H{
  60. "success": false,
  61. "message": "无法解析请求体,请检查其是否为合法 JSON",
  62. })
  63. return
  64. }
  65. }
  66. keepCompatible(&message)
  67. pushMessageHelper(c, &message)
  68. }
  69. func pushMessageHelper(c *gin.Context, message *model.Message) {
  70. user := model.User{Username: c.Param("username")}
  71. err := user.FillUserByUsername()
  72. if err != nil {
  73. c.JSON(http.StatusOK, gin.H{
  74. "success": false,
  75. "message": err.Error(),
  76. })
  77. return
  78. }
  79. if user.Status == common.UserStatusNonExisted {
  80. c.JSON(http.StatusOK, gin.H{
  81. "success": false,
  82. "message": "用户不存在",
  83. })
  84. return
  85. }
  86. if user.Status == common.UserStatusDisabled {
  87. c.JSON(http.StatusOK, gin.H{
  88. "success": false,
  89. "message": "用户已被封禁",
  90. })
  91. return
  92. }
  93. if user.Token != "" && user.Token != " " {
  94. if message.Token == "" {
  95. message.Token = c.Request.Header.Get("Authorization")
  96. if message.Token == "" {
  97. c.JSON(http.StatusOK, gin.H{
  98. "success": false,
  99. "message": "token 为空",
  100. })
  101. return
  102. }
  103. }
  104. if user.Token != message.Token {
  105. c.JSON(http.StatusOK, gin.H{
  106. "success": false,
  107. "message": "无效的 token",
  108. })
  109. return
  110. }
  111. }
  112. if message.Title == "" {
  113. message.Title = common.SystemName
  114. }
  115. if message.Channel == "" {
  116. message.Channel = user.Channel
  117. if message.Channel == "" {
  118. message.Channel = model.TypeEmail
  119. }
  120. }
  121. channel_, err := model.GetChannelByName(message.Channel, user.Id)
  122. if err != nil {
  123. c.JSON(http.StatusOK, gin.H{
  124. "success": false,
  125. "message": "无效的渠道名称:" + message.Channel,
  126. })
  127. return
  128. }
  129. err = saveAndSendMessage(&user, message, channel_)
  130. if err != nil {
  131. c.JSON(http.StatusOK, gin.H{
  132. "success": false,
  133. "message": err.Error(),
  134. })
  135. return
  136. }
  137. c.JSON(http.StatusOK, gin.H{
  138. "success": true,
  139. "message": "",
  140. })
  141. }
  142. func saveAndSendMessage(user *model.User, message *model.Message, channel_ *model.Channel) error {
  143. if channel_.Status != common.ChannelStatusEnabled {
  144. return errors.New("该渠道已被禁用")
  145. }
  146. message.Link = common.GetUUID()
  147. if message.URL == "" {
  148. message.URL = fmt.Sprintf("%s/message/%s", common.ServerAddress, message.Link)
  149. }
  150. success := false
  151. if common.MessagePersistenceEnabled || user.SaveMessageToDatabase == common.SaveMessageToDatabaseAllowed {
  152. defer func() {
  153. // Update the status of the message
  154. status := common.MessageSendStatusFailed
  155. if success {
  156. status = common.MessageSendStatusSent
  157. }
  158. err := message.UpdateStatus(status)
  159. if err != nil {
  160. common.SysError("failed to update the status of the message: " + err.Error())
  161. }
  162. }()
  163. err := message.UpdateAndInsert(user.Id)
  164. if err != nil {
  165. return err
  166. }
  167. } else {
  168. message.Link = "unsaved" // This is for user to identify whether the message is saved
  169. }
  170. err := channel.SendMessage(message, user, channel_)
  171. common.MessageCount += 1 // We don't need to use atomic here because it's not a critical value
  172. if err != nil {
  173. return err
  174. }
  175. success = true
  176. return nil // After this line, the message status will be updated
  177. }
  178. func GetStaticFile(c *gin.Context) {
  179. path := c.Param("file")
  180. c.FileFromFS("public/static/"+path, http.FS(common.FS))
  181. }
  182. func RenderMessage(c *gin.Context) {
  183. if !common.MessageRenderEnabled {
  184. c.HTML(http.StatusOK, "message.html", gin.H{
  185. "title": "无法渲染",
  186. "time": time.Now().Format("2006-01-02 15:04:05"),
  187. "description": "超级管理员禁用了消息渲染",
  188. "content": "很抱歉,您所使用的消息推送服务的管理员禁用了消息渲染功能,因此您的消息无法渲染。",
  189. })
  190. return
  191. }
  192. link := c.Param("link")
  193. if link == "unsaved" {
  194. c.HTML(http.StatusOK, "message.html", gin.H{
  195. "title": "无法渲染",
  196. "time": time.Now().Format("2006-01-02 15:04:05"),
  197. "description": "超级管理员禁用了消息持久化",
  198. "content": "很抱歉,您所使用的消息推送服务的管理员禁用了消息持久化功能,您的消息并没有存储到数据库中,因此无法渲染。",
  199. })
  200. return
  201. }
  202. message, err := model.GetMessageByLink(link)
  203. if err != nil {
  204. c.Status(http.StatusNotFound)
  205. return
  206. }
  207. if message.Description != "" {
  208. message.Description, err = common.Markdown2HTML(message.Description)
  209. if err != nil {
  210. common.SysLog(err.Error())
  211. }
  212. }
  213. if message.Content != "" {
  214. message.HTMLContent, err = common.Markdown2HTML(message.Content)
  215. if err != nil {
  216. common.SysLog(err.Error())
  217. }
  218. }
  219. c.HTML(http.StatusOK, "message.html", gin.H{
  220. "title": message.Title,
  221. "time": time.Unix(message.Timestamp, 0).Format("2006-01-02 15:04:05"),
  222. "description": message.Description,
  223. "content": message.HTMLContent,
  224. })
  225. return
  226. }
  227. func GetUserMessages(c *gin.Context) {
  228. userId := c.GetInt("id")
  229. p, _ := strconv.Atoi(c.Query("p"))
  230. if p < 0 {
  231. p = 0
  232. }
  233. messages, err := model.GetMessagesByUserId(userId, p*common.ItemsPerPage, common.ItemsPerPage)
  234. if err != nil {
  235. c.JSON(http.StatusOK, gin.H{
  236. "success": false,
  237. "message": err.Error(),
  238. })
  239. return
  240. }
  241. c.JSON(http.StatusOK, gin.H{
  242. "success": true,
  243. "message": "",
  244. "data": messages,
  245. })
  246. return
  247. }
  248. func GetMessage(c *gin.Context) {
  249. messageId, _ := strconv.Atoi(c.Param("id"))
  250. userId := c.GetInt("id")
  251. message, err := model.GetMessageById(messageId, userId)
  252. if err != nil {
  253. c.JSON(http.StatusOK, gin.H{
  254. "success": false,
  255. "message": err.Error(),
  256. })
  257. return
  258. }
  259. c.JSON(http.StatusOK, gin.H{
  260. "success": true,
  261. "message": "",
  262. "data": message,
  263. })
  264. return
  265. }
  266. func SearchMessages(c *gin.Context) {
  267. keyword := c.Query("keyword")
  268. messages, err := model.SearchMessages(keyword)
  269. if err != nil {
  270. c.JSON(http.StatusOK, gin.H{
  271. "success": false,
  272. "message": err.Error(),
  273. })
  274. return
  275. }
  276. c.JSON(http.StatusOK, gin.H{
  277. "success": true,
  278. "message": "",
  279. "data": messages,
  280. })
  281. return
  282. }
  283. func ResendMessage(c *gin.Context) {
  284. messageId, _ := strconv.Atoi(c.Param("id"))
  285. userId := c.GetInt("id")
  286. helper := func() error {
  287. message, err := model.GetMessageById(messageId, userId)
  288. message.Id = 0
  289. if err != nil {
  290. return err
  291. }
  292. user, err := model.GetUserById(userId, true)
  293. if err != nil {
  294. return err
  295. }
  296. channel_, err := model.GetChannelByName(message.Channel, user.Id)
  297. if err != nil {
  298. return err
  299. }
  300. err = saveAndSendMessage(user, message, channel_)
  301. if err != nil {
  302. return err
  303. }
  304. return nil
  305. }
  306. err := helper()
  307. if err != nil {
  308. c.JSON(http.StatusOK, gin.H{
  309. "success": false,
  310. "message": err.Error(),
  311. })
  312. return
  313. }
  314. c.JSON(http.StatusOK, gin.H{
  315. "success": true,
  316. "message": "",
  317. })
  318. return
  319. }
  320. func DeleteMessage(c *gin.Context) {
  321. messageId, _ := strconv.Atoi(c.Param("id"))
  322. userId := c.GetInt("id")
  323. err := model.DeleteMessageById(messageId, userId)
  324. if err != nil {
  325. c.JSON(http.StatusOK, gin.H{
  326. "success": false,
  327. "message": err.Error(),
  328. })
  329. return
  330. }
  331. c.JSON(http.StatusOK, gin.H{
  332. "success": true,
  333. "message": "",
  334. })
  335. return
  336. }
  337. func DeleteAllMessages(c *gin.Context) {
  338. err := model.DeleteAllMessages()
  339. if err != nil {
  340. c.JSON(http.StatusOK, gin.H{
  341. "success": false,
  342. "message": err.Error(),
  343. })
  344. return
  345. }
  346. c.JSON(http.StatusOK, gin.H{
  347. "success": true,
  348. "message": "",
  349. })
  350. return
  351. }