- Backend: Email producer (LavinMQ), EmailService interface - Backend: CRUD API for email_templates and email_settings - Backend: avatar_url field in users table + UpdateMyProfile support - Backend: StorageService for pre-signed URLs - NestJS: Email consumer with Nodemailer and Handlebars - Frontend: Email Templates admin pages (list/edit) - Frontend: Updated profileApi.uploadAvatar with pre-signed URL flow - Frontend: New /post-job public page (company registration + job creation wizard) - Migrations: 027_create_email_system.sql, 028_add_avatar_url_to_users.sql
90 lines
2.3 KiB
Go
90 lines
2.3 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/appwrite/sdk-for-go/client"
|
|
"github.com/appwrite/sdk-for-go/databases"
|
|
)
|
|
|
|
type AppwriteConfig struct {
|
|
Endpoint string `json:"endpoint"`
|
|
ProjectID string `json:"projectId"`
|
|
APIKey string `json:"apiKey"`
|
|
DatabaseID string `json:"databaseId"`
|
|
CollectionID string `json:"collectionId"`
|
|
}
|
|
|
|
type AppwriteService struct {
|
|
credentialsService *CredentialsService
|
|
}
|
|
|
|
func NewAppwriteService(creds *CredentialsService) *AppwriteService {
|
|
return &AppwriteService{
|
|
credentialsService: creds,
|
|
}
|
|
}
|
|
|
|
// PushMessage pushes a message to Appwrite Database for Realtime sync
|
|
func (s *AppwriteService) PushMessage(ctx context.Context, msgID, convoID, senderID, content string) error {
|
|
config, err := s.getConfig(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("appwrite config error: %w", err)
|
|
}
|
|
|
|
if config.Endpoint == "" || config.ProjectID == "" {
|
|
return fmt.Errorf("appwrite not configured")
|
|
}
|
|
|
|
// Initialize Client
|
|
// sdk-for-go v0.16.x uses direct field assignment or AddHeader for config
|
|
cl := client.New()
|
|
cl.Endpoint = config.Endpoint
|
|
cl.AddHeader("X-Appwrite-Project", config.ProjectID)
|
|
cl.AddHeader("X-Appwrite-Key", config.APIKey)
|
|
|
|
db := databases.New(cl)
|
|
|
|
// Create Document
|
|
_, err = db.CreateDocument(
|
|
config.DatabaseID,
|
|
config.CollectionID,
|
|
msgID,
|
|
map[string]interface{}{
|
|
"conversation_id": convoID,
|
|
"sender_id": senderID,
|
|
"content": content,
|
|
"timestamp": time.Now().Format(time.RFC3339),
|
|
},
|
|
db.WithCreateDocumentPermissions([]string{}), // Optional permissions
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to push to appwrite: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *AppwriteService) getConfig(ctx context.Context) (*AppwriteConfig, error) {
|
|
// Try DB first
|
|
payload, err := s.credentialsService.GetDecryptedKey(ctx, "appwrite")
|
|
if err == nil && payload != "" {
|
|
var cfg AppwriteConfig
|
|
if err := json.Unmarshal([]byte(payload), &cfg); err == nil {
|
|
return &cfg, nil
|
|
}
|
|
}
|
|
|
|
// Fallback to Env
|
|
return &AppwriteConfig{
|
|
Endpoint: os.Getenv("APPWRITE_ENDPOINT"),
|
|
ProjectID: os.Getenv("APPWRITE_PROJECT_ID"),
|
|
APIKey: os.Getenv("APPWRITE_API_KEY"),
|
|
DatabaseID: os.Getenv("APPWRITE_DATABASE_ID"),
|
|
CollectionID: "messages", // Default if not set
|
|
}, nil
|
|
}
|