✨ Support firebase FCM as a notify subscriber
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"code.smartsheep.studio/hydrogen/passport/pkg/external"
|
||||
"code.smartsheep.studio/hydrogen/passport/pkg/server"
|
||||
"os"
|
||||
"os/signal"
|
||||
@ -37,6 +38,12 @@ func main() {
|
||||
log.Fatal().Err(err).Msg("An error occurred when running database auto migration.")
|
||||
}
|
||||
|
||||
// External
|
||||
// All the things are optional so when error occurred the server won't crash
|
||||
if err := external.SetupFirebase(viper.GetString("external.firebase.credentials")); err != nil {
|
||||
log.Error().Err(err).Msg("An error occurred when starting firebase communicating...")
|
||||
}
|
||||
|
||||
// Server
|
||||
server.NewServer()
|
||||
go server.Listen()
|
||||
|
21
pkg/external/firebase.go
vendored
Normal file
21
pkg/external/firebase.go
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
package external
|
||||
|
||||
import (
|
||||
"context"
|
||||
firebase "firebase.google.com/go"
|
||||
"google.golang.org/api/option"
|
||||
)
|
||||
|
||||
var Fire *firebase.App
|
||||
|
||||
func SetupFirebase(credentials string) error {
|
||||
opt := option.WithCredentialsFile(credentials)
|
||||
app, err := firebase.NewApp(context.Background(), nil, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
Fire = app
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,16 +1,26 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"gorm.io/datatypes"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Notification struct {
|
||||
BaseModel
|
||||
|
||||
Subject string `json:"subject"`
|
||||
Content string `json:"content"`
|
||||
IsImportant bool `json:"is_important"`
|
||||
ReadAt *time.Time `json:"read_at"`
|
||||
SenderID *uint `json:"sender_id"`
|
||||
RecipientID uint `json:"recipient_id"`
|
||||
Subject string `json:"subject"`
|
||||
Content string `json:"content"`
|
||||
Links datatypes.JSONSlice[NotificationLink] `json:"links"`
|
||||
IsImportant bool `json:"is_important"`
|
||||
ReadAt *time.Time `json:"read_at"`
|
||||
SenderID *uint `json:"sender_id"`
|
||||
RecipientID uint `json:"recipient_id"`
|
||||
}
|
||||
|
||||
// NotificationLink Used to embed into notify and render actions
|
||||
type NotificationLink struct {
|
||||
Label string `json:"label"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -8,12 +8,13 @@ import (
|
||||
|
||||
func notifyUser(c *fiber.Ctx) error {
|
||||
var data struct {
|
||||
ClientID string `json:"client_id" validate:"required"`
|
||||
ClientSecret string `json:"client_secret" validate:"required"`
|
||||
Subject string `json:"subject" validate:"required,max=1024"`
|
||||
Content string `json:"content" validate:"required,max=3072"`
|
||||
IsImportant bool `json:"is_important"`
|
||||
UserID uint `json:"user_id" validate:"required"`
|
||||
ClientID string `json:"client_id" validate:"required"`
|
||||
ClientSecret string `json:"client_secret" validate:"required"`
|
||||
Subject string `json:"subject" validate:"required,max=1024"`
|
||||
Content string `json:"content" validate:"required,max=3072"`
|
||||
Links []models.NotificationLink `json:"links"`
|
||||
IsImportant bool `json:"is_important"`
|
||||
UserID uint `json:"user_id" validate:"required"`
|
||||
}
|
||||
|
||||
if err := BindAndValidate(c, &data); err != nil {
|
||||
@ -30,7 +31,7 @@ func notifyUser(c *fiber.Ctx) error {
|
||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||
}
|
||||
|
||||
if err := services.NewNotification(client, user, data.Subject, data.Content, data.IsImportant); err != nil {
|
||||
if err := services.NewNotification(client, user, data.Subject, data.Content, data.Links, data.IsImportant); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
|
@ -2,14 +2,18 @@ package services
|
||||
|
||||
import (
|
||||
"code.smartsheep.studio/hydrogen/passport/pkg/database"
|
||||
"code.smartsheep.studio/hydrogen/passport/pkg/external"
|
||||
"code.smartsheep.studio/hydrogen/passport/pkg/models"
|
||||
"context"
|
||||
"firebase.google.com/go/messaging"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func AddNotifySubscriber(user models.Account, provider, device, ua string) (models.NotificationSubscriber, error) {
|
||||
subscriber := models.NotificationSubscriber{
|
||||
UserAgent: ua,
|
||||
Provider: provider,
|
||||
DeviceID: ua,
|
||||
DeviceID: device,
|
||||
AccountID: user.ID,
|
||||
}
|
||||
|
||||
@ -18,10 +22,17 @@ func AddNotifySubscriber(user models.Account, provider, device, ua string) (mode
|
||||
return subscriber, err
|
||||
}
|
||||
|
||||
func NewNotification(user models.ThirdClient, target models.Account, subject, content string, important bool) error {
|
||||
func NewNotification(
|
||||
user models.ThirdClient,
|
||||
target models.Account,
|
||||
subject, content string,
|
||||
links []models.NotificationLink,
|
||||
important bool,
|
||||
) error {
|
||||
notification := models.Notification{
|
||||
Subject: subject,
|
||||
Content: content,
|
||||
Links: links,
|
||||
IsImportant: important,
|
||||
ReadAt: nil,
|
||||
SenderID: &user.ID,
|
||||
@ -32,7 +43,43 @@ func NewNotification(user models.ThirdClient, target models.Account, subject, co
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO Notify all the listeners
|
||||
var subscribers []models.NotificationSubscriber
|
||||
if err := database.C.Where(&models.NotificationSubscriber{
|
||||
AccountID: user.ID,
|
||||
}).Find(&subscribers).Error; err != nil {
|
||||
// I don't know why cannot get subscribers list, but whatever, the notifications has created
|
||||
log.Error().Err(err).Msg("Unexpected error occurred during the notification.")
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, subscriber := range subscribers {
|
||||
switch subscriber.Provider {
|
||||
case models.NotifySubscriberFirebase:
|
||||
if external.Fire == nil {
|
||||
// Didn't configure for firebase support
|
||||
break
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
client, err := external.Fire.Messaging(ctx)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("An error occurred when getting firebase FCM client...")
|
||||
break
|
||||
}
|
||||
|
||||
message := &messaging.Message{
|
||||
Notification: &messaging.Notification{
|
||||
Title: notification.Subject,
|
||||
Body: notification.Content,
|
||||
},
|
||||
Token: subscriber.DeviceID,
|
||||
}
|
||||
|
||||
if _, err = client.Send(ctx, message); err != nil {
|
||||
log.Warn().Err(err).Msg("An error occurred when notify subscriber though firebase FCM...")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user