Add PDF reports, file uploads, admin auth, and comprehensive tests
Features: - PDF service for generating task reports with ReportLab-style formatting - Storage service for file uploads (local and S3-compatible) - Admin authentication middleware with JWT support - Admin user model and repository Infrastructure: - Updated Docker configuration for admin panel builds - Email service enhancements for task notifications - Updated router with admin and file upload routes - Environment configuration updates Tests: - Unit tests for handlers (auth, residence, task) - Unit tests for models (user, residence, task) - Unit tests for repositories (user, residence, task) - Unit tests for services (residence, task) - Integration test setup - Test utilities for mocking database and services Database: - Admin user seed data - Updated test data seeds 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
107
internal/repositories/admin_repo.go
Normal file
107
internal/repositories/admin_repo.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/treytartt/mycrib-api/internal/models"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrAdminNotFound = errors.New("admin user not found")
|
||||
ErrAdminExists = errors.New("admin user already exists")
|
||||
)
|
||||
|
||||
// AdminRepository handles admin user database operations
|
||||
type AdminRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewAdminRepository creates a new admin repository
|
||||
func NewAdminRepository(db *gorm.DB) *AdminRepository {
|
||||
return &AdminRepository{db: db}
|
||||
}
|
||||
|
||||
// FindByID finds an admin user by ID
|
||||
func (r *AdminRepository) FindByID(id uint) (*models.AdminUser, error) {
|
||||
var admin models.AdminUser
|
||||
if err := r.db.First(&admin, id).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrAdminNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &admin, nil
|
||||
}
|
||||
|
||||
// FindByEmail finds an admin user by email (case-insensitive)
|
||||
func (r *AdminRepository) FindByEmail(email string) (*models.AdminUser, error) {
|
||||
var admin models.AdminUser
|
||||
if err := r.db.Where("LOWER(email) = LOWER(?)", email).First(&admin).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrAdminNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &admin, nil
|
||||
}
|
||||
|
||||
// Create creates a new admin user
|
||||
func (r *AdminRepository) Create(admin *models.AdminUser) error {
|
||||
// Check if email already exists
|
||||
var count int64
|
||||
if err := r.db.Model(&models.AdminUser{}).Where("LOWER(email) = LOWER(?)", admin.Email).Count(&count).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return ErrAdminExists
|
||||
}
|
||||
|
||||
return r.db.Create(admin).Error
|
||||
}
|
||||
|
||||
// Update updates an admin user
|
||||
func (r *AdminRepository) Update(admin *models.AdminUser) error {
|
||||
return r.db.Save(admin).Error
|
||||
}
|
||||
|
||||
// Delete deletes an admin user
|
||||
func (r *AdminRepository) Delete(id uint) error {
|
||||
return r.db.Delete(&models.AdminUser{}, id).Error
|
||||
}
|
||||
|
||||
// UpdateLastLogin updates the last login timestamp
|
||||
func (r *AdminRepository) UpdateLastLogin(id uint) error {
|
||||
now := time.Now()
|
||||
return r.db.Model(&models.AdminUser{}).Where("id = ?", id).Update("last_login", now).Error
|
||||
}
|
||||
|
||||
// List returns all admin users with pagination
|
||||
func (r *AdminRepository) List(page, pageSize int) ([]models.AdminUser, int64, error) {
|
||||
var admins []models.AdminUser
|
||||
var total int64
|
||||
|
||||
// Get total count
|
||||
if err := r.db.Model(&models.AdminUser{}).Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Get paginated results
|
||||
offset := (page - 1) * pageSize
|
||||
if err := r.db.Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&admins).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return admins, total, nil
|
||||
}
|
||||
|
||||
// ExistsByEmail checks if an admin user with the given email exists
|
||||
func (r *AdminRepository) ExistsByEmail(email string) (bool, error) {
|
||||
var count int64
|
||||
if err := r.db.Model(&models.AdminUser{}).Where("LOWER(email) = LOWER(?)", email).Count(&count).Error; err != nil {
|
||||
return false, err
|
||||
}
|
||||
return count > 0, nil
|
||||
}
|
||||
Reference in New Issue
Block a user