ghost-listmonk-connector/services/son_storage.go
troneras ff5b39241a first commit
fixed cache

Refactoring from app router to page router

Refactoring from app router to page router

Add authentication with JWT

base ui done

protect the dashboard

added transitions

styling

type trick added

cleanup

Add enable-disable logic

add transactional emails

Improvements on delay and frontend

added description on select

implement auth with magic link

migrate to mariadb

webhook signature working

Adding async processing with queues

Implemented webhook reply functionality

Add son execution logs

update status logic

Add recent activity monitoring to sons

show son performance in dashboard

add readme

implement listmonk connector

listmonk-connector-v1

Create CODE_OF_CONDUCT.md

Create LICENSE
2024-08-21 02:09:24 +02:00

176 lines
4.9 KiB
Go

package services
import (
"database/sql"
"encoding/json"
"errors"
"fmt"
"github.com/troneras/ghost-listmonk-connector/database"
"github.com/troneras/ghost-listmonk-connector/models"
"github.com/troneras/ghost-listmonk-connector/utils"
)
var (
ErrSonAlreadyExists = errors.New("son with this ID already exists")
ErrSonNotFound = errors.New("son not found")
)
type SonStorage struct {
db *sql.DB
recentActivityService *RecentActivityService
}
// Update the NewSonStorage function
func NewSonStorage(recentActivityService *RecentActivityService) *SonStorage {
return &SonStorage{
db: database.GetDB(),
recentActivityService: recentActivityService,
}
}
func (s *SonStorage) Create(son *models.Son) error {
actionsJSON, err := json.Marshal(son.Actions)
if err != nil {
utils.ErrorLogger.Errorf("Failed to marshal actions: %v", err)
return err
}
_, err = s.db.Exec(
"INSERT INTO sons (id, user_id, name, trigger_event, delay, actions, enabled, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())",
son.ID, son.UserID, son.Name, son.Trigger, son.Delay, actionsJSON, son.Enabled,
)
if err != nil {
utils.ErrorLogger.Errorf("Failed to create Son: %v", err)
return err
}
if err := s.recentActivityService.LogActivity(son.UserID, "son_created", fmt.Sprintf("Created Son: %s", son.Name)); err != nil {
utils.ErrorLogger.Printf("Failed to log activity: %v", err)
}
utils.InfoLogger.Infof("Created new Son with ID: %s", son.ID)
return nil
}
func (s *SonStorage) Get(id string) (models.Son, error) {
var son models.Son
var actionsJSON []byte
err := s.db.QueryRow(
"SELECT id, user_id, name, trigger_event, delay, actions, enabled, created_at, updated_at FROM sons WHERE id = ?",
id,
).Scan(&son.ID, &son.UserID, &son.Name, &son.Trigger, &son.Delay, &actionsJSON, &son.Enabled, &son.CreatedAt, &son.UpdatedAt)
if err != nil {
if err == sql.ErrNoRows {
utils.ErrorLogger.Errorf("Failed to get Son: %v", ErrSonNotFound)
return models.Son{}, ErrSonNotFound
}
utils.ErrorLogger.Errorf("Failed to get Son: %v", err)
return models.Son{}, err
}
err = json.Unmarshal(actionsJSON, &son.Actions)
if err != nil {
utils.ErrorLogger.Errorf("Failed to unmarshal actions: %v", err)
return models.Son{}, err
}
utils.InfoLogger.Infof("Retrieved Son with ID: %s", id)
return son, nil
}
func (s *SonStorage) Update(son models.Son) error {
actionsJSON, err := json.Marshal(son.Actions)
if err != nil {
return err
}
result, err := s.db.Exec(
"UPDATE sons SET name = ?, trigger_event = ?, delay = ?, actions = ?, enabled = ?, updated_at = NOW() WHERE id = ? AND user_id = ?",
son.Name, son.Trigger, son.Delay, actionsJSON, son.Enabled, son.ID, son.UserID,
)
if err != nil {
utils.ErrorLogger.Errorf("Failed to update Son: %v", err)
return err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return err
}
if rowsAffected == 0 {
utils.ErrorLogger.Errorf("Failed to update Son: %v", ErrSonNotFound)
return ErrSonNotFound
}
if err := s.recentActivityService.LogActivity(son.UserID, "son_updated", fmt.Sprintf("Updated Son: %s", son.Name)); err != nil {
utils.ErrorLogger.Printf("Failed to log activity: %v", err)
}
utils.InfoLogger.Infof("Updated Son with ID: %s", son.ID)
return nil
}
func (s *SonStorage) Delete(id string, userID string) error {
result, err := s.db.Exec("DELETE FROM sons WHERE id = ? AND user_id = ?", id, userID)
if err != nil {
utils.ErrorLogger.Errorf("Failed to delete Son: %v", err)
return err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return err
}
if rowsAffected == 0 {
utils.ErrorLogger.Errorf("Failed to delete Son: %v", ErrSonNotFound)
return ErrSonNotFound
}
if err := s.recentActivityService.LogActivity(userID, "son_deleted", fmt.Sprintf("Deleted Son: %s", id)); err != nil {
utils.ErrorLogger.Printf("Failed to log activity: %v", err)
}
utils.InfoLogger.Infof("Deleted Son with ID: %s", id)
return nil
}
func (s *SonStorage) List(userID string) ([]models.Son, error) {
rows, err := s.db.Query("SELECT id, user_id, name, trigger_event, delay, actions, enabled, created_at, updated_at FROM sons WHERE user_id = ?", userID)
if err != nil {
utils.ErrorLogger.Errorf("Failed to list Sons: %v", err)
return nil, err
}
defer rows.Close()
var sons []models.Son
for rows.Next() {
var son models.Son
var actionsJSON []byte
err := rows.Scan(&son.ID, &son.UserID, &son.Name, &son.Trigger, &son.Delay, &actionsJSON, &son.Enabled, &son.CreatedAt, &son.UpdatedAt)
if err != nil {
utils.ErrorLogger.Errorf("Failed to scan Son: %v", err)
continue
}
err = json.Unmarshal(actionsJSON, &son.Actions)
if err != nil {
utils.ErrorLogger.Errorf("Failed to unmarshal actions: %v", err)
continue
}
sons = append(sons, son)
}
if sons == nil {
sons = []models.Son{}
}
utils.InfoLogger.Infof("Retrieved list of %d Sons for user %s", len(sons), userID)
return sons, nil
}