This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

WIP: continue

+171 -50
+18
churros.go
··· 1 1 package notella 2 2 3 3 import ( 4 + "context" 4 5 "fmt" 5 6 "strings" 6 7 ··· 44 45 45 46 return nil 46 47 } 48 + 49 + func CreateInDatabaseNotification(notification Message, endpoint string) error { 50 + _, err := prisma.Notification.CreateOne( 51 + db.Notification.Subscription.Link( 52 + db.NotificationSubscription.Endpoint.Equals(endpoint), 53 + ), 54 + db.Notification.Title.Set(notification.Title), 55 + db.Notification.Body.Set(notification.Body), 56 + db.Notification.ID.Set(notification.Id), 57 + ).Exec(context.Background()) 58 + 59 + return err 60 + } 61 + 62 + func ConnectToDababase() error { 63 + return prisma.Connect() 64 + }
+13 -2
receiver.go
··· 1 1 package notella 2 2 3 3 import ( 4 + "encoding/json" 5 + "fmt" 6 + 4 7 ll "github.com/ewen-lbh/label-logger-go" 5 8 "github.com/nats-io/nats.go" 6 9 ) ··· 8 11 const StreamName = "notella:stream" 9 12 const SubjectName = "notella:notification" 10 13 11 - func NatsReceiver(m *nats.Msg) { 12 - ll.Log("Received", "cyan", "message: %s", string(m.Data)) 14 + func NatsReceiver(m *nats.Msg) error { 15 + var message Message 16 + err := json.Unmarshal(m.Data, &message) 17 + if err != nil { 18 + return fmt.Errorf("while unmarshaling received message: %w", err) 19 + } 20 + 21 + ll.Log("Received", "cyan", "%-10s | %s", message.Id, message.ChurrosObjectId) 22 + CreateInDatabaseNotification(message, "feur") 23 + return nil 13 24 }
-1
scheduler.go
··· 5 5 cmap "github.com/orcaman/concurrent-map/v2" 6 6 ) 7 7 8 - 9 8 var schedules = cmap.New[ScheduledJob]() 10 9 11 10 func (job ScheduledJob) Unschedule() {
+1 -1
scripts/typing.go
··· 84 84 os.WriteFile("types.d.ts", output, 0644) 85 85 86 86 // Also save useful constants 87 - os.WriteFile("constants.ts", []byte(fmt.Sprintf("export const STREAM_NAME = %q; export const SUBJECT_NAME = %q;", notella.StreamName, notella.SubjectName)), 0644) 87 + os.WriteFile("constants.ts", []byte(fmt.Sprintf("export const STREAM_NAME = '%s';\nexport const SUBJECT_NAME = '%s';\n", notella.StreamName, notella.SubjectName)), 0644) 88 88 }
+10 -1
server/main.go
··· 58 58 ll.Info("starting scheduler") 59 59 go notella.StartScheduler() 60 60 61 + ll.Log("Connecting", "cyan", "to Churros database at [bold]%s[reset]", config.ChurrosDatabaseURL) 62 + err = notella.ConnectToDababase() 63 + if err != nil { 64 + ll.ErrorDisplay("could not connect to database", err) 65 + } 66 + 61 67 ll.Log("Connecting", "cyan", "to NATS server at [bold]%s[reset]", nats.DefaultURL) 62 68 nc, err := nats.Connect(nats.DefaultURL) 63 69 if err != nil { ··· 131 137 132 138 // Process each message 133 139 for _, msg := range msgs { 134 - notella.NatsReceiver(msg) 140 + err = notella.NatsReceiver(msg) 141 + if err != nil { 142 + ll.ErrorDisplay("Could not process message", err) 143 + } 135 144 msg.Ack() // Acknowledge the message 136 145 } 137 146 }
+45 -45
types.d.ts
··· 1 1 export interface Message { 2 - /** 3 - * URL to go to when the action button is clicked 4 - */ 5 - action: string; 6 - /** 7 - * Additional action buttons 8 - */ 9 - actions: Action[]; 10 - /** 11 - * Notification body 12 - */ 13 - body: string; 14 - /** 15 - * Type of event that triggered the notification 16 - */ 17 - event: Event; 18 - /** 19 - * Unique ID for the notification scheduling request. 20 - */ 21 - id: string; 22 - /** 23 - * URL to an image to display in the notification 24 - */ 25 - image: string; 26 - /** 27 - * Churros ID of the ressource (the ticket, the post, the comment, etc) 28 - * Used to determine to whom the notification should be sent 29 - * For godchild_request, this is not a user id, but a godparent request id. 30 - */ 31 - object_id: string; 32 - /** 33 - * When to push the notification 34 - */ 35 - send_at: Date; 36 - /** 37 - * Notification title 38 - */ 39 - title: string; 2 + /** 3 + * URL to go to when the action button is clicked 4 + */ 5 + action: string; 6 + /** 7 + * Additional action buttons 8 + */ 9 + actions: Action[]; 10 + /** 11 + * Notification body 12 + */ 13 + body: string; 14 + /** 15 + * Type of event that triggered the notification 16 + */ 17 + event: Event; 18 + /** 19 + * Unique ID for the notification scheduling request. 20 + */ 21 + id: string; 22 + /** 23 + * URL to an image to display in the notification 24 + */ 25 + image: string; 26 + /** 27 + * Churros ID of the ressource (the ticket, the post, the comment, etc) 28 + * Used to determine to whom the notification should be sent 29 + * For godchild_request, this is not a user id, but a godparent request id. 30 + */ 31 + object_id: string; 32 + /** 33 + * When to push the notification 34 + */ 35 + send_at: Date; 36 + /** 37 + * Notification title 38 + */ 39 + title: string; 40 40 } 41 41 42 42 export interface Action { 43 - action: string; 44 - label: string; 43 + action: string; 44 + label: string; 45 45 } 46 46 47 47 /** 48 48 * Type of event that triggered the notification 49 49 */ 50 50 export enum Event { 51 - CommentReply = 'comment_reply', 52 - GodchildRequest = 'godchild_request', 53 - NewComment = 'new_comment', 54 - NewPost = 'new_post', 55 - NewTicket = 'new_ticket', 51 + CommentReply = "comment_reply", 52 + GodchildRequest = "godchild_request", 53 + NewComment = "new_comment", 54 + NewPost = "new_post", 55 + NewTicket = "new_ticket", 56 56 }
+84
users.go
··· 1 + package notella 2 + 3 + import ( 4 + "context" 5 + "fmt" 6 + 7 + "git.inpt.fr/churros/notella/db" 8 + ) 9 + 10 + // AllUsers returns all the users in the database that have at least one notification subscription 11 + func AllUsers() ([]string, error) { 12 + users, err := prisma.User.FindMany( 13 + db.User.NotificationSubscriptions.Some(), 14 + ).Select( 15 + db.User.ID.Field(), 16 + ).Exec(context.Background()) 17 + 18 + if err != nil { 19 + return []string{}, fmt.Errorf("while getting all users: %w", err) 20 + } 21 + 22 + ids := make([]string, len(users)) 23 + for i, user := range users { 24 + ids[i] = user.ID 25 + } 26 + 27 + return ids, nil 28 + } 29 + 30 + // Receivers determines which users to send the notification to 31 + func Receivers(message Message) ([]string, error) { 32 + switch message.Event { 33 + case EventNewPost: 34 + return receiversForPost(message) 35 + } 36 + 37 + return []string{}, nil 38 + } 39 + 40 + func receiversForPost(message Message) (userIds []string, err error) { 41 + post, err := prisma.Article.FindUnique( 42 + db.Article.ID.Equals(message.ChurrosObjectId), 43 + ).With( 44 + db.Article.Group.Fetch().With( 45 + db.Group.Members.Fetch().Select( 46 + db.GroupMember.MemberID.Field(), 47 + ), 48 + db.Group.StudentAssociation.Fetch().With( 49 + db.StudentAssociation.School.Fetch().With( 50 + db.School.Majors.Fetch().With( 51 + db.Major.Students.Fetch().Select( 52 + db.User.ID.Field(), 53 + ), 54 + ), 55 + ), 56 + ), 57 + ), 58 + ).Exec(context.Background()) 59 + 60 + if err != nil { 61 + return []string{}, fmt.Errorf("while getting the post %q: %w", message.Id, err) 62 + } 63 + 64 + switch post.Visibility { 65 + case db.VisibilityPrivate: 66 + case db.VisibilityUnlisted: 67 + return []string{}, nil 68 + case db.VisibilityPublic: 69 + return AllUsers() 70 + case db.VisibilitySchoolRestricted: 71 + for _, major := range post.Group().StudentAssociation().School().Majors() { 72 + for _, student := range major.Students() { 73 + userIds = append(userIds, student.ID) 74 + } 75 + } 76 + return 77 + case db.VisibilityGroupRestricted: 78 + for _, member := range post.Group().Members() { 79 + userIds = append(userIds, member.MemberID) 80 + } 81 + } 82 + 83 + return userIds, fmt.Errorf("unknown post visibility %q", post.Visibility) 84 + }