♻️ Better notification system

This commit is contained in:
LittleSheep 2024-06-07 20:05:56 +08:00
parent b925d54000
commit 332557778d
9 changed files with 120 additions and 106 deletions

View File

@ -5,15 +5,15 @@
</component>
<component name="ChangeListManager">
<list default="true" id="3fefb2c4-b6f9-466b-a523-53352e8d6f95" name="更改" comment=":sparkles: Apple push notification services">
<change afterPath="$PROJECT_DIR$/pkg/services/external_apns.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/go.mod" beforeDir="false" afterPath="$PROJECT_DIR$/go.mod" afterDir="false" />
<change beforePath="$PROJECT_DIR$/go.sum" beforeDir="false" afterPath="$PROJECT_DIR$/go.sum" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pkg/cmd/main.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/cmd/main.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pkg/grpc/notify.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/grpc/notify.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pkg/grpc/proto/notify.pb.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/grpc/proto/notify.pb.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pkg/grpc/proto/notify.proto" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/grpc/proto/notify.proto" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pkg/grpc/proto/notify_grpc.pb.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/grpc/proto/notify_grpc.pb.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pkg/models/notifications.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/models/notifications.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pkg/services/external_firebase.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/services/external_firebase.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pkg/server/notifications_api.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/server/notifications_api.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pkg/server/notify_api.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/server/notify_api.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/pkg/services/notifications.go" beforeDir="false" afterPath="$PROJECT_DIR$/pkg/services/notifications.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/settings.toml" beforeDir="false" afterPath="$PROJECT_DIR$/settings.toml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -48,33 +48,33 @@
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"DefaultGoTemplateProperty": "Go File",
"Go Build.Backend.executor": "Run",
"Go 构建.Backend.executor": "Run",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.go.formatter.settings.were.checked": "true",
"RunOnceActivity.go.migrated.go.modules.settings": "true",
"RunOnceActivity.go.modules.automatic.dependencies.download": "true",
"RunOnceActivity.go.modules.go.list.on.any.changes.was.set": "true",
"git-widget-placeholder": "master",
"go.import.settings.migrated": "true",
"go.sdk.automatically.set": "true",
"last_opened_file_path": "/Users/littlesheep/Documents/Projects/Hydrogen/Passport/pkg/services",
"node.js.detected.package.eslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"run.code.analysis.last.selected.profile": "pProject Default",
"settings.editor.selected.configurable": "preferences.pluginManager",
"vue.rearranger.settings.migration": "true"
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;DefaultGoTemplateProperty&quot;: &quot;Go File&quot;,
&quot;Go Build.Backend.executor&quot;: &quot;Run&quot;,
&quot;Go 构建.Backend.executor&quot;: &quot;Run&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.go.formatter.settings.were.checked&quot;: &quot;true&quot;,
&quot;RunOnceActivity.go.migrated.go.modules.settings&quot;: &quot;true&quot;,
&quot;RunOnceActivity.go.modules.automatic.dependencies.download&quot;: &quot;true&quot;,
&quot;RunOnceActivity.go.modules.go.list.on.any.changes.was.set&quot;: &quot;true&quot;,
&quot;git-widget-placeholder&quot;: &quot;master&quot;,
&quot;go.import.settings.migrated&quot;: &quot;true&quot;,
&quot;go.sdk.automatically.set&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;/Users/littlesheep/Documents/Projects/Hydrogen/Passport/pkg/services&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;run.code.analysis.last.selected.profile&quot;: &quot;pProject Default&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
},
"keyToStringList": {
"DatabaseDriversLRU": [
"postgresql"
&quot;keyToStringList&quot;: {
&quot;DatabaseDriversLRU&quot;: [
&quot;postgresql&quot;
]
}
}]]></component>
}</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/pkg/services" />

View File

@ -2,6 +2,7 @@ package grpc
import (
"context"
jsoniter "github.com/json-iterator/go"
"git.solsynth.dev/hydrogen/passport/pkg/grpc/proto"
"git.solsynth.dev/hydrogen/passport/pkg/models"
@ -20,6 +21,9 @@ func (v *Server) NotifyUser(_ context.Context, in *proto.NotifyRequest) (*proto.
return nil, err
}
var metadata map[string]any
_ = jsoniter.Unmarshal(in.GetMetadata(), &metadata)
links := lo.Map(in.GetLinks(), func(item *proto.NotifyLink, index int) models.NotificationLink {
return models.NotificationLink{
Label: item.Label,
@ -28,12 +32,13 @@ func (v *Server) NotifyUser(_ context.Context, in *proto.NotifyRequest) (*proto.
})
notification := models.Notification{
Type: in.GetType(),
Subject: in.GetSubject(),
Content: in.GetContent(),
Metadata: metadata,
Links: links,
IsImportant: in.GetIsImportant(),
IsRealtime: in.GetIsRealtime(),
ReadAt: nil,
IsForcePush: in.GetIsForcePush(),
RecipientID: user.ID,
SenderID: &client.ID,
}

View File

@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.33.0
// protoc v4.25.3
// protoc v5.26.1
// source: notify.proto
package proto
@ -80,14 +80,16 @@ type NotifyRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Subject string `protobuf:"bytes,1,opt,name=subject,proto3" json:"subject,omitempty"`
Content string `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"`
Links []*NotifyLink `protobuf:"bytes,3,rep,name=links,proto3" json:"links,omitempty"`
IsImportant bool `protobuf:"varint,4,opt,name=is_important,json=isImportant,proto3" json:"is_important,omitempty"`
RecipientId uint64 `protobuf:"varint,5,opt,name=recipient_id,json=recipientId,proto3" json:"recipient_id,omitempty"`
ClientId string `protobuf:"bytes,6,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
ClientSecret string `protobuf:"bytes,7,opt,name=client_secret,json=clientSecret,proto3" json:"client_secret,omitempty"`
IsRealtime bool `protobuf:"varint,8,opt,name=is_realtime,json=isRealtime,proto3" json:"is_realtime,omitempty"`
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
Subject string `protobuf:"bytes,2,opt,name=subject,proto3" json:"subject,omitempty"`
Content string `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"`
Metadata []byte `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"`
Links []*NotifyLink `protobuf:"bytes,5,rep,name=links,proto3" json:"links,omitempty"`
RecipientId uint64 `protobuf:"varint,6,opt,name=recipient_id,json=recipientId,proto3" json:"recipient_id,omitempty"`
ClientId string `protobuf:"bytes,7,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"`
ClientSecret string `protobuf:"bytes,8,opt,name=client_secret,json=clientSecret,proto3" json:"client_secret,omitempty"`
IsRealtime bool `protobuf:"varint,9,opt,name=is_realtime,json=isRealtime,proto3" json:"is_realtime,omitempty"`
IsForcePush bool `protobuf:"varint,10,opt,name=is_force_push,json=isForcePush,proto3" json:"is_force_push,omitempty"`
}
func (x *NotifyRequest) Reset() {
@ -122,6 +124,13 @@ func (*NotifyRequest) Descriptor() ([]byte, []int) {
return file_notify_proto_rawDescGZIP(), []int{1}
}
func (x *NotifyRequest) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *NotifyRequest) GetSubject() string {
if x != nil {
return x.Subject
@ -136,6 +145,13 @@ func (x *NotifyRequest) GetContent() string {
return ""
}
func (x *NotifyRequest) GetMetadata() []byte {
if x != nil {
return x.Metadata
}
return nil
}
func (x *NotifyRequest) GetLinks() []*NotifyLink {
if x != nil {
return x.Links
@ -143,13 +159,6 @@ func (x *NotifyRequest) GetLinks() []*NotifyLink {
return nil
}
func (x *NotifyRequest) GetIsImportant() bool {
if x != nil {
return x.IsImportant
}
return false
}
func (x *NotifyRequest) GetRecipientId() uint64 {
if x != nil {
return x.RecipientId
@ -178,6 +187,13 @@ func (x *NotifyRequest) GetIsRealtime() bool {
return false
}
func (x *NotifyRequest) GetIsForcePush() bool {
if x != nil {
return x.IsForcePush
}
return false
}
type NotifyReply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -232,33 +248,36 @@ var file_notify_proto_rawDesc = []byte{
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x34, 0x0a, 0x0a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4c,
0x69, 0x6e, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x95, 0x02, 0x0a, 0x0d,
0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a,
0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65,
0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
0x74, 0x12, 0x27, 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0xc6, 0x02, 0x0a, 0x0d,
0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a,
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,
0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63,
0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f,
0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x12, 0x27, 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4c,
0x69, 0x6e, 0x6b, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73,
0x5f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,
0x52, 0x0b, 0x69, 0x73, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x61, 0x6e, 0x74, 0x12, 0x21, 0x0a,
0x0c, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20,
0x01, 0x28, 0x04, 0x52, 0x0b, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64,
0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x23, 0x0a,
0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x07,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72,
0x65, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x72, 0x65, 0x61, 0x6c, 0x74, 0x69, 0x6d,
0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x52, 0x65, 0x61, 0x6c, 0x74,
0x69, 0x6d, 0x65, 0x22, 0x26, 0x0a, 0x0b, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x70,
0x6c, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20,
0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x53, 0x65, 0x6e, 0x74, 0x32, 0x42, 0x0a, 0x06, 0x4e,
0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x38, 0x0a, 0x0a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x55,
0x73, 0x65, 0x72, 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x69,
0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42,
0x09, 0x5a, 0x07, 0x2e, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
0x69, 0x6e, 0x6b, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65,
0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04,
0x52, 0x0b, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a,
0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c,
0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12,
0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x72, 0x65, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09,
0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x52, 0x65, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x65,
0x12, 0x22, 0x0a, 0x0d, 0x69, 0x73, 0x5f, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x75, 0x73,
0x68, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x46, 0x6f, 0x72, 0x63, 0x65,
0x50, 0x75, 0x73, 0x68, 0x22, 0x26, 0x0a, 0x0b, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65,
0x70, 0x6c, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x01,
0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x53, 0x65, 0x6e, 0x74, 0x32, 0x42, 0x0a, 0x06,
0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x12, 0x38, 0x0a, 0x0a, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79,
0x55, 0x73, 0x65, 0x72, 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74,
0x69, 0x66, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00,
0x42, 0x09, 0x5a, 0x07, 0x2e, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
}
var (

View File

@ -14,14 +14,16 @@ message NotifyLink {
}
message NotifyRequest {
string subject = 1;
string content = 2;
repeated NotifyLink links = 3;
bool is_important = 4;
uint64 recipient_id = 5;
string client_id = 6;
string client_secret = 7;
bool is_realtime = 8;
string type = 1;
string subject = 2;
string content = 3;
bytes metadata = 4;
repeated NotifyLink links = 5;
uint64 recipient_id = 6;
string client_id = 7;
string client_secret = 8;
bool is_realtime = 9;
bool is_force_push = 10;
}
message NotifyReply {

View File

@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc v4.25.3
// - protoc v5.26.1
// source: notify.proto
package proto

View File

@ -1,8 +1,6 @@
package models
import (
"time"
"gorm.io/datatypes"
)
@ -14,9 +12,8 @@ type Notification struct {
Content string `json:"content"`
Metadata datatypes.JSONMap `json:"metadata"`
Links datatypes.JSONSlice[NotificationLink] `json:"links"`
IsImportant bool `json:"is_important"`
IsRealtime bool `json:"is_realtime" gorm:"-"`
ReadAt *time.Time `json:"read_at"`
IsForcePush bool `json:"is_force_push" gorm:"-"`
SenderID *uint `json:"sender_id"`
RecipientID uint `json:"recipient_id"`
}

View File

@ -1,14 +1,11 @@
package server
import (
"git.solsynth.dev/hydrogen/passport/pkg/utils"
"time"
"git.solsynth.dev/hydrogen/passport/pkg/database"
"git.solsynth.dev/hydrogen/passport/pkg/models"
"git.solsynth.dev/hydrogen/passport/pkg/services"
"git.solsynth.dev/hydrogen/passport/pkg/utils"
"github.com/gofiber/fiber/v2"
"github.com/samber/lo"
)
func getNotifications(c *fiber.Ctx) error {
@ -16,12 +13,7 @@ func getNotifications(c *fiber.Ctx) error {
take := c.QueryInt("take", 0)
offset := c.QueryInt("offset", 0)
only_unread := !c.QueryBool("past", false)
tx := database.C.Where(&models.Notification{RecipientID: user.ID}).Model(&models.Notification{})
if only_unread {
tx = tx.Where("read_at IS NULL")
}
var count int64
var notifications []models.Notification
@ -33,7 +25,6 @@ func getNotifications(c *fiber.Ctx) error {
if err := tx.
Limit(take).
Offset(offset).
Order("read_at desc").
Find(&notifications).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
@ -56,9 +47,7 @@ func markNotificationRead(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusNotFound, err.Error())
}
notify.ReadAt = lo.ToPtr(time.Now())
if err := database.C.Save(&notify).Error; err != nil {
if err := database.C.Delete(&notify).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
} else {
return c.SendStatus(fiber.StatusOK)
@ -78,7 +67,7 @@ func markNotificationReadBatch(c *fiber.Ctx) error {
if err := database.C.Model(&models.Notification{}).
Where("recipient_id = ? AND id IN ?", user.ID, data.MessageIDs).
Updates(&models.Notification{ReadAt: lo.ToPtr(time.Now())}).Error; err != nil {
Delete(&models.Notification{}).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
} else {
return c.SendStatus(fiber.StatusOK)

View File

@ -11,10 +11,12 @@ func notifyUser(c *fiber.Ctx) error {
var data struct {
ClientID string `json:"client_id" validate:"required"`
ClientSecret string `json:"client_secret" validate:"required"`
Type string `json:"type" validate:"required"`
Subject string `json:"subject" validate:"required,max=1024"`
Content string `json:"content" validate:"required,max=3072"`
Content string `json:"content" validate:"required,max=4096"`
Metadata map[string]any `json:"metadata"`
Links []models.NotificationLink `json:"links"`
IsImportant bool `json:"is_important"`
IsForcePush bool `json:"is_force_push"`
IsRealtime bool `json:"is_realtime"`
UserID uint `json:"user_id" validate:"required"`
}
@ -34,12 +36,12 @@ func notifyUser(c *fiber.Ctx) error {
}
notification := models.Notification{
Type: data.Type,
Subject: data.Subject,
Content: data.Content,
Links: data.Links,
IsImportant: data.IsImportant,
IsRealtime: data.IsRealtime,
ReadAt: nil,
IsForcePush: data.IsForcePush,
RecipientID: user.ID,
SenderID: &client.ID,
}

View File

@ -67,7 +67,7 @@ func PushNotification(notification models.Notification) error {
}
// Skip push notification when frontend notify is available
if frontendAvailable {
if frontendAvailable && !notification.IsForcePush {
return nil
}