notifications.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package utils
  2. import (
  3. "net/http"
  4. "encoding/json"
  5. "time"
  6. "fmt"
  7. "strings"
  8. "go.mongodb.org/mongo-driver/mongo/options"
  9. "go.mongodb.org/mongo-driver/bson/primitive"
  10. "go.mongodb.org/mongo-driver/bson"
  11. )
  12. type NotificationActions struct {
  13. Text string
  14. Link string
  15. }
  16. type Notification struct {
  17. ID primitive.ObjectID `bson:"_id,omitempty"`
  18. Title string
  19. Message string
  20. Icon string
  21. Link string
  22. Date time.Time
  23. Level string
  24. Read bool
  25. Recipient string
  26. Actions []NotificationActions
  27. }
  28. func NotifGet(w http.ResponseWriter, req *http.Request) {
  29. _from := req.URL.Query().Get("from")
  30. from, _ := primitive.ObjectIDFromHex(_from)
  31. if LoggedInOnly(w, req) != nil {
  32. return
  33. }
  34. nickname := req.Header.Get("x-cosmos-user")
  35. if(req.Method == "GET") {
  36. c, errCo := GetCollection(GetRootAppId(), "notifications")
  37. if errCo != nil {
  38. Error("Database Connect", errCo)
  39. HTTPError(w, "Database", http.StatusInternalServerError, "DB001")
  40. return
  41. }
  42. Debug("Notifications: Get notif for " + nickname)
  43. notifications := []Notification{}
  44. reqdb := map[string]interface{}{
  45. "Recipient": nickname,
  46. }
  47. if from != primitive.NilObjectID {
  48. reqdb = map[string]interface{}{
  49. // nickname or role
  50. "Recipient": nickname,
  51. // get notif before from
  52. "_id": map[string]interface{}{
  53. "$lt": from,
  54. },
  55. }
  56. }
  57. limit := int64(20)
  58. cursor, err := c.Find(nil, reqdb, &options.FindOptions{
  59. Sort: map[string]interface{}{
  60. "Date": -1,
  61. },
  62. Limit: &limit,
  63. })
  64. if err != nil {
  65. Error("Notifications: Error while getting notifications", err)
  66. HTTPError(w, "notifications Get Error", http.StatusInternalServerError, "UD001")
  67. return
  68. }
  69. defer cursor.Close(nil)
  70. if err = cursor.All(nil, &notifications); err != nil {
  71. Error("Notifications: Error while decoding notifications", err)
  72. HTTPError(w, "notifications Get Error", http.StatusInternalServerError, "UD002")
  73. return
  74. }
  75. json.NewEncoder(w).Encode(map[string]interface{}{
  76. "status": "OK",
  77. "data": notifications,
  78. })
  79. } else {
  80. Error("Notifications: Method not allowed" + req.Method, nil)
  81. HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
  82. return
  83. }
  84. }
  85. func MarkAsRead(w http.ResponseWriter, req *http.Request) {
  86. if(req.Method == "GET") {
  87. if LoggedInOnly(w, req) != nil {
  88. return
  89. }
  90. notificationIDs := []primitive.ObjectID{}
  91. nickname := req.Header.Get("x-cosmos-user")
  92. notificationIDsRawRunes := req.URL.Query().Get("ids")
  93. notificationIDsRaw := strings.Split(notificationIDsRawRunes, ",")
  94. Debug(fmt.Sprintf("Marking %v notifications as read",notificationIDsRaw))
  95. for _, notificationIDRaw := range notificationIDsRaw {
  96. notificationID, err := primitive.ObjectIDFromHex(notificationIDRaw)
  97. if err != nil {
  98. HTTPError(w, "Invalid notification ID " + notificationIDRaw, http.StatusBadRequest, "InvalidID")
  99. return
  100. }
  101. notificationIDs = append(notificationIDs, notificationID)
  102. }
  103. c, errCo := GetCollection(GetRootAppId(), "notifications")
  104. if errCo != nil {
  105. Error("Database Connect", errCo)
  106. HTTPError(w, "Database connection error", http.StatusInternalServerError, "DB001")
  107. return
  108. }
  109. filter := bson.M{"_id": bson.M{"$in": notificationIDs}, "Recipient": nickname}
  110. update := bson.M{"$set": bson.M{"Read": true}}
  111. result, err := c.UpdateMany(nil, filter, update)
  112. if err != nil {
  113. Error("Notifications: Error while marking notification as read", err)
  114. HTTPError(w, "Error updating notification", http.StatusInternalServerError, "UpdateError")
  115. return
  116. }
  117. if result.MatchedCount == 0 {
  118. HTTPError(w, "No matching notification found", http.StatusNotFound, "NotFound")
  119. return
  120. }
  121. json.NewEncoder(w).Encode(map[string]interface{}{
  122. "status": "OK",
  123. "message": "Notification marked as read",
  124. })
  125. } else {
  126. Error("Notifications: Method not allowed" + req.Method, nil)
  127. HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
  128. return
  129. }
  130. }
  131. func WriteNotification(notification Notification) {
  132. notification.Date = time.Now()
  133. notification.Read = false
  134. if notification.Recipient == "all" || notification.Recipient == "admin" || notification.Recipient == "user" {
  135. // list all users
  136. users := ListAllUsers(notification.Recipient)
  137. Debug("Notifications: Sending notification to " + string(len(users)) + " users")
  138. for _, user := range users {
  139. BufferedDBWrite("notifications", map[string]interface{}{
  140. "Title": notification.Title,
  141. "Message": notification.Message,
  142. "Icon": notification.Icon,
  143. "Link": notification.Link,
  144. "Date": notification.Date,
  145. "Level": notification.Level,
  146. "Read": notification.Read,
  147. "Recipient": user.Nickname,
  148. "Actions": notification.Actions,
  149. })
  150. }
  151. } else {
  152. BufferedDBWrite("notifications", map[string]interface{}{
  153. "Title": notification.Title,
  154. "Message": notification.Message,
  155. "Icon": notification.Icon,
  156. "Link": notification.Link,
  157. "Date": notification.Date,
  158. "Level": notification.Level,
  159. "Read": notification.Read,
  160. "Recipient": notification.Recipient,
  161. "Actions": notification.Actions,
  162. })
  163. }
  164. }