message.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  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. if message.Title == "" {
  115. message.Title = common.SystemName
  116. }
  117. if message.Channel == "" {
  118. message.Channel = user.Channel
  119. if message.Channel == "" {
  120. message.Channel = model.TypeEmail
  121. }
  122. }
  123. channel_, err := model.GetChannelByName(message.Channel, user.Id)
  124. if err != nil {
  125. c.JSON(http.StatusOK, gin.H{
  126. "success": false,
  127. "message": "无效的渠道名称:" + message.Channel,
  128. })
  129. return
  130. }
  131. err = saveAndSendMessage(&user, message, channel_)
  132. if err != nil {
  133. c.JSON(http.StatusOK, gin.H{
  134. "success": false,
  135. "message": err.Error(),
  136. })
  137. return
  138. }
  139. c.JSON(http.StatusOK, gin.H{
  140. "success": true,
  141. "message": "",
  142. "uuid": message.Link,
  143. })
  144. }
  145. func saveAndSendMessage(user *model.User, message *model.Message, channel_ *model.Channel) error {
  146. if channel_.Status != common.ChannelStatusEnabled {
  147. return errors.New("该渠道已被禁用")
  148. }
  149. common.MessageCount += 1 // We don't need to use atomic here because it's not a critical value
  150. message.Link = common.GetUUID()
  151. if message.URL == "" {
  152. message.URL = fmt.Sprintf("%s/message/%s", common.ServerAddress, message.Link)
  153. }
  154. success := false
  155. if common.MessagePersistenceEnabled || user.SaveMessageToDatabase == common.SaveMessageToDatabaseAllowed {
  156. defer func() {
  157. // Update the status of the message
  158. status := common.MessageSendStatusFailed
  159. if message.Async {
  160. status = common.MessageSendStatusAsyncPending
  161. } else {
  162. if success {
  163. status = common.MessageSendStatusSent
  164. }
  165. }
  166. err := message.UpdateStatus(status)
  167. if err != nil {
  168. common.SysError("failed to update the status of the message: " + err.Error())
  169. }
  170. if message.Async {
  171. channel.AsyncMessageQueue <- message.Id
  172. }
  173. }()
  174. err := message.UpdateAndInsert(user.Id)
  175. if err != nil {
  176. return err
  177. }
  178. } else {
  179. if message.Async {
  180. return errors.New("异步发送消息需要用户具备消息持久化的权限")
  181. }
  182. message.Link = "unsaved" // This is for user to identify whether the message is saved
  183. }
  184. if !message.Async {
  185. err := channel.SendMessage(message, user, channel_)
  186. if err != nil {
  187. return err
  188. }
  189. }
  190. success = true
  191. return nil // After this line, the message status will be updated
  192. }
  193. func GetStaticFile(c *gin.Context) {
  194. path := c.Param("file")
  195. c.FileFromFS("public/static/"+path, http.FS(common.FS))
  196. }
  197. func RenderMessage(c *gin.Context) {
  198. if !common.MessageRenderEnabled {
  199. c.HTML(http.StatusOK, "message.html", gin.H{
  200. "title": "无法渲染",
  201. "time": time.Now().Format("2006-01-02 15:04:05"),
  202. "description": "超级管理员禁用了消息渲染",
  203. "content": "很抱歉,您所使用的消息推送服务的管理员禁用了消息渲染功能,因此您的消息无法渲染。",
  204. })
  205. return
  206. }
  207. link := c.Param("link")
  208. if link == "unsaved" {
  209. c.HTML(http.StatusOK, "message.html", gin.H{
  210. "title": "无法渲染",
  211. "time": time.Now().Format("2006-01-02 15:04:05"),
  212. "description": "超级管理员禁用了消息持久化",
  213. "content": "很抱歉,您所使用的消息推送服务的管理员禁用了消息持久化功能,您的消息并没有存储到数据库中,因此无法渲染。",
  214. })
  215. return
  216. }
  217. message, err := model.GetMessageByLink(link)
  218. if err != nil {
  219. c.Status(http.StatusNotFound)
  220. return
  221. }
  222. if message.Description != "" {
  223. message.Description, err = common.Markdown2HTML(message.Description)
  224. if err != nil {
  225. common.SysLog(err.Error())
  226. }
  227. }
  228. if message.Content != "" {
  229. message.HTMLContent, err = common.Markdown2HTML(message.Content)
  230. if err != nil {
  231. common.SysLog(err.Error())
  232. }
  233. }
  234. c.HTML(http.StatusOK, "message.html", gin.H{
  235. "title": message.Title,
  236. "time": time.Unix(message.Timestamp, 0).Format("2006-01-02 15:04:05"),
  237. "description": message.Description,
  238. "content": message.HTMLContent,
  239. })
  240. return
  241. }
  242. func GetUserMessages(c *gin.Context) {
  243. userId := c.GetInt("id")
  244. p, _ := strconv.Atoi(c.Query("p"))
  245. if p < 0 {
  246. p = 0
  247. }
  248. messages, err := model.GetMessagesByUserId(userId, p*common.ItemsPerPage, common.ItemsPerPage)
  249. if err != nil {
  250. c.JSON(http.StatusOK, gin.H{
  251. "success": false,
  252. "message": err.Error(),
  253. })
  254. return
  255. }
  256. c.JSON(http.StatusOK, gin.H{
  257. "success": true,
  258. "message": "",
  259. "data": messages,
  260. })
  261. return
  262. }
  263. func GetMessage(c *gin.Context) {
  264. messageId, _ := strconv.Atoi(c.Param("id"))
  265. userId := c.GetInt("id")
  266. message, err := model.GetMessageByIds(messageId, userId)
  267. if err != nil {
  268. c.JSON(http.StatusOK, gin.H{
  269. "success": false,
  270. "message": err.Error(),
  271. })
  272. return
  273. }
  274. c.JSON(http.StatusOK, gin.H{
  275. "success": true,
  276. "message": "",
  277. "data": message,
  278. })
  279. return
  280. }
  281. func GetMessageStatus(c *gin.Context) {
  282. link := c.Param("link")
  283. status, err := model.GetMessageStatusByLink(link)
  284. if err != nil {
  285. c.JSON(http.StatusOK, gin.H{
  286. "success": false,
  287. "message": err.Error(),
  288. })
  289. return
  290. }
  291. c.JSON(http.StatusOK, gin.H{
  292. "success": true,
  293. "message": "",
  294. "status": status,
  295. })
  296. return
  297. }
  298. func SearchMessages(c *gin.Context) {
  299. keyword := c.Query("keyword")
  300. messages, err := model.SearchMessages(keyword)
  301. if err != nil {
  302. c.JSON(http.StatusOK, gin.H{
  303. "success": false,
  304. "message": err.Error(),
  305. })
  306. return
  307. }
  308. c.JSON(http.StatusOK, gin.H{
  309. "success": true,
  310. "message": "",
  311. "data": messages,
  312. })
  313. return
  314. }
  315. func ResendMessage(c *gin.Context) {
  316. messageId, _ := strconv.Atoi(c.Param("id"))
  317. userId := c.GetInt("id")
  318. helper := func() error {
  319. message, err := model.GetMessageByIds(messageId, userId)
  320. message.Id = 0
  321. if err != nil {
  322. return err
  323. }
  324. user, err := model.GetUserById(userId, true)
  325. if err != nil {
  326. return err
  327. }
  328. channel_, err := model.GetChannelByName(message.Channel, user.Id)
  329. if err != nil {
  330. return err
  331. }
  332. err = saveAndSendMessage(user, message, channel_)
  333. if err != nil {
  334. return err
  335. }
  336. return nil
  337. }
  338. err := helper()
  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. }
  352. func DeleteMessage(c *gin.Context) {
  353. messageId, _ := strconv.Atoi(c.Param("id"))
  354. userId := c.GetInt("id")
  355. err := model.DeleteMessageById(messageId, userId)
  356. if err != nil {
  357. c.JSON(http.StatusOK, gin.H{
  358. "success": false,
  359. "message": err.Error(),
  360. })
  361. return
  362. }
  363. c.JSON(http.StatusOK, gin.H{
  364. "success": true,
  365. "message": "",
  366. })
  367. return
  368. }
  369. func DeleteAllMessages(c *gin.Context) {
  370. err := model.DeleteAllMessages()
  371. if err != nil {
  372. c.JSON(http.StatusOK, gin.H{
  373. "success": false,
  374. "message": err.Error(),
  375. })
  376. return
  377. }
  378. c.JSON(http.StatusOK, gin.H{
  379. "success": true,
  380. "message": "",
  381. })
  382. return
  383. }