280 lines
6.8 KiB
Go
280 lines
6.8 KiB
Go
package processor
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/url"
|
|
|
|
"eslogad-be/internal/config"
|
|
"eslogad-be/internal/contract"
|
|
"eslogad-be/internal/entities"
|
|
|
|
novu "github.com/novuhq/go-novu/lib"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type NovuProcessor interface {
|
|
CreateSubscriber(ctx context.Context, user *entities.User) error
|
|
UpdateSubscriber(ctx context.Context, user *entities.User) error
|
|
DeleteSubscriber(ctx context.Context, userID uuid.UUID) error
|
|
CreateSubscriberFromContract(ctx context.Context, user *contract.UserResponse) error
|
|
BulkCreateSubscribers(ctx context.Context, users []*entities.User) error
|
|
SendLetterNotification(ctx context.Context, letterID uuid.UUID, recipientUserID uuid.UUID, subject string, body string) error
|
|
}
|
|
|
|
type NovuProcessorImpl struct {
|
|
client *novu.APIClient
|
|
config *config.NovuConfig
|
|
}
|
|
|
|
func NewNovuProcessor(cfg *config.NovuConfig) *NovuProcessorImpl {
|
|
if cfg.APIKey == "" {
|
|
return &NovuProcessorImpl{
|
|
client: nil,
|
|
config: cfg,
|
|
}
|
|
}
|
|
|
|
// Create Novu config with backend URL
|
|
novuConfig := &novu.Config{}
|
|
if cfg.BaseURL != "" {
|
|
backendURL, err := url.Parse(cfg.BaseURL)
|
|
if err == nil {
|
|
novuConfig.BackendURL = backendURL
|
|
}
|
|
}
|
|
|
|
client := novu.NewAPIClient(cfg.APIKey, novuConfig)
|
|
|
|
return &NovuProcessorImpl{
|
|
client: client,
|
|
config: cfg,
|
|
}
|
|
}
|
|
|
|
func (p *NovuProcessorImpl) CreateSubscriber(ctx context.Context, user *entities.User) error {
|
|
if p.client == nil {
|
|
return fmt.Errorf("novu client not initialized")
|
|
}
|
|
|
|
subscriberID := user.ID.String()
|
|
|
|
data := map[string]interface{}{
|
|
"userId": user.ID.String(),
|
|
"email": user.Email,
|
|
"isActive": user.IsActive,
|
|
"createdAt": user.CreatedAt,
|
|
}
|
|
|
|
if user.Departments != nil && len(user.Departments) > 0 {
|
|
depts := make([]map[string]interface{}, len(user.Departments))
|
|
for i, dept := range user.Departments {
|
|
depts[i] = map[string]interface{}{
|
|
"id": dept.ID.String(),
|
|
"name": dept.Name,
|
|
"code": dept.Code,
|
|
}
|
|
}
|
|
data["departments"] = depts
|
|
}
|
|
|
|
subscriber := novu.SubscriberPayload{
|
|
Email: user.Email,
|
|
FirstName: user.Name,
|
|
LastName: "",
|
|
Phone: "",
|
|
Avatar: "",
|
|
Data: data,
|
|
}
|
|
|
|
_, err := p.client.SubscriberApi.Identify(ctx, subscriberID, subscriber)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create subscriber: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *NovuProcessorImpl) UpdateSubscriber(ctx context.Context, user *entities.User) error {
|
|
if p.client == nil {
|
|
return fmt.Errorf("novu client not initialized")
|
|
}
|
|
|
|
subscriberID := user.ID.String()
|
|
|
|
data := map[string]interface{}{
|
|
"userId": user.ID.String(),
|
|
"email": user.Email,
|
|
"isActive": user.IsActive,
|
|
"updatedAt": user.UpdatedAt,
|
|
}
|
|
|
|
if user.Departments != nil && len(user.Departments) > 0 {
|
|
depts := make([]map[string]interface{}, len(user.Departments))
|
|
for i, dept := range user.Departments {
|
|
depts[i] = map[string]interface{}{
|
|
"id": dept.ID.String(),
|
|
"name": dept.Name,
|
|
"code": dept.Code,
|
|
}
|
|
}
|
|
data["departments"] = depts
|
|
}
|
|
|
|
updateData := novu.SubscriberPayload{
|
|
Email: user.Email,
|
|
FirstName: user.Name,
|
|
LastName: "",
|
|
Phone: "",
|
|
Avatar: "",
|
|
Data: data,
|
|
}
|
|
|
|
_, err := p.client.SubscriberApi.Update(ctx, subscriberID, updateData)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to update subscriber: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *NovuProcessorImpl) DeleteSubscriber(ctx context.Context, userID uuid.UUID) error {
|
|
if p.client == nil {
|
|
return fmt.Errorf("novu client not initialized")
|
|
}
|
|
|
|
subscriberID := userID.String()
|
|
|
|
_, err := p.client.SubscriberApi.Delete(ctx, subscriberID)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete subscriber: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *NovuProcessorImpl) CreateSubscriberFromContract(ctx context.Context, user *contract.UserResponse) error {
|
|
if p.client == nil {
|
|
return fmt.Errorf("novu client not initialized")
|
|
}
|
|
|
|
subscriberID := user.ID.String()
|
|
|
|
data := map[string]interface{}{
|
|
"userId": user.ID.String(),
|
|
"email": user.Email,
|
|
"isActive": user.IsActive,
|
|
"createdAt": user.CreatedAt,
|
|
}
|
|
|
|
if user.Roles != nil && len(user.Roles) > 0 {
|
|
roles := make([]map[string]interface{}, len(user.Roles))
|
|
for i, role := range user.Roles {
|
|
roles[i] = map[string]interface{}{
|
|
"id": role.ID.String(),
|
|
"name": role.Name,
|
|
"code": role.Code,
|
|
}
|
|
}
|
|
data["roles"] = roles
|
|
}
|
|
|
|
if user.DepartmentResponse != nil && len(user.DepartmentResponse) > 0 {
|
|
depts := make([]map[string]interface{}, len(user.DepartmentResponse))
|
|
for i, dept := range user.DepartmentResponse {
|
|
depts[i] = map[string]interface{}{
|
|
"id": dept.ID.String(),
|
|
"name": dept.Name,
|
|
"code": dept.Code,
|
|
}
|
|
}
|
|
data["departments"] = depts
|
|
}
|
|
|
|
subscriber := novu.SubscriberPayload{
|
|
Email: user.Email,
|
|
FirstName: user.Name,
|
|
LastName: "",
|
|
Phone: "",
|
|
Avatar: "",
|
|
Data: data,
|
|
}
|
|
|
|
_, err := p.client.SubscriberApi.Identify(ctx, subscriberID, subscriber)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create subscriber from contract: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *NovuProcessorImpl) BulkCreateSubscribers(ctx context.Context, users []*entities.User) error {
|
|
if p.client == nil {
|
|
return fmt.Errorf("novu client not initialized")
|
|
}
|
|
|
|
var lastErr error
|
|
successCount := 0
|
|
|
|
for _, user := range users {
|
|
err := p.CreateSubscriber(ctx, user)
|
|
if err != nil {
|
|
lastErr = err
|
|
continue
|
|
}
|
|
successCount++
|
|
}
|
|
|
|
if lastErr != nil && successCount == 0 {
|
|
return fmt.Errorf("failed to create any subscribers, last error: %w", lastErr)
|
|
}
|
|
|
|
if lastErr != nil {
|
|
return fmt.Errorf("created %d out of %d subscribers, last error: %w", successCount, len(users), lastErr)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *NovuProcessorImpl) SendLetterNotification(ctx context.Context, letterID uuid.UUID, recipientUserID uuid.UUID, subject string, body string) error {
|
|
if p.client == nil {
|
|
return fmt.Errorf("novu client not initialized")
|
|
}
|
|
|
|
subscriberID := recipientUserID.String()
|
|
|
|
// Check if subscriber exists, create if not
|
|
_, err := p.client.SubscriberApi.Get(ctx, subscriberID)
|
|
if err != nil {
|
|
// Subscriber doesn't exist, create a basic one
|
|
subscriber := novu.SubscriberPayload{
|
|
Email: fmt.Sprintf("%s@placeholder.com", subscriberID),
|
|
}
|
|
_, err = p.client.SubscriberApi.Identify(ctx, subscriberID, subscriber)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to ensure subscriber exists: %w", err)
|
|
}
|
|
}
|
|
|
|
// Prepare notification payload
|
|
url := fmt.Sprintf("en/apps/surat-menyurat/masuk-detail/%s", letterID.String())
|
|
|
|
payload := map[string]interface{}{
|
|
"subject": subject,
|
|
"body": body,
|
|
"url": url,
|
|
}
|
|
|
|
// Trigger the notification
|
|
triggerPayload := novu.ITriggerPayloadOptions{
|
|
To: subscriberID,
|
|
Payload: payload,
|
|
}
|
|
|
|
_, err = p.client.EventApi.Trigger(ctx, "notification-dashboard", triggerPayload)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to send letter notification: %w", err)
|
|
}
|
|
|
|
return nil
|
|
} |