message.go 9.4 KB

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