繰り返し追加機能の追加
This commit is contained in:
@@ -187,7 +187,6 @@ func (r *AssignmentRepository) CountOverdueByUserID(userID uint) (int64, error)
|
||||
return count, err
|
||||
}
|
||||
|
||||
// StatisticsFilter holds filter parameters for statistics queries
|
||||
type StatisticsFilter struct {
|
||||
Subject string
|
||||
From *time.Time
|
||||
@@ -195,7 +194,6 @@ type StatisticsFilter struct {
|
||||
IncludeArchived bool
|
||||
}
|
||||
|
||||
// AssignmentStatistics holds statistics data
|
||||
type AssignmentStatistics struct {
|
||||
Total int64
|
||||
Completed int64
|
||||
@@ -205,7 +203,6 @@ type AssignmentStatistics struct {
|
||||
OnTimeCompletionRate float64
|
||||
}
|
||||
|
||||
// SubjectStatistics holds statistics for a specific subject
|
||||
type SubjectStatistics struct {
|
||||
Subject string
|
||||
Total int64
|
||||
@@ -216,64 +213,48 @@ type SubjectStatistics struct {
|
||||
OnTimeCompletionRate float64
|
||||
}
|
||||
|
||||
// GetStatistics returns statistics for a user with optional filters
|
||||
func (r *AssignmentRepository) GetStatistics(userID uint, filter StatisticsFilter) (*AssignmentStatistics, error) {
|
||||
now := time.Now()
|
||||
stats := &AssignmentStatistics{}
|
||||
|
||||
// Base query
|
||||
baseQuery := r.db.Model(&models.Assignment{}).Where("user_id = ?", userID)
|
||||
|
||||
// Apply subject filter
|
||||
if filter.Subject != "" {
|
||||
baseQuery = baseQuery.Where("subject = ?", filter.Subject)
|
||||
}
|
||||
|
||||
// Apply date range filter (by created_at)
|
||||
if filter.From != nil {
|
||||
baseQuery = baseQuery.Where("created_at >= ?", *filter.From)
|
||||
}
|
||||
if filter.To != nil {
|
||||
// Add 1 day to include the entire "to" date
|
||||
toEnd := filter.To.AddDate(0, 0, 1)
|
||||
baseQuery = baseQuery.Where("created_at < ?", toEnd)
|
||||
}
|
||||
|
||||
// Apply archived filter
|
||||
if !filter.IncludeArchived {
|
||||
baseQuery = baseQuery.Where("is_archived = ?", false)
|
||||
}
|
||||
|
||||
// Total count
|
||||
if err := baseQuery.Count(&stats.Total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Completed count
|
||||
completedQuery := baseQuery.Session(&gorm.Session{})
|
||||
if err := completedQuery.Where("is_completed = ?", true).Count(&stats.Completed).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Pending count
|
||||
pendingQuery := baseQuery.Session(&gorm.Session{})
|
||||
if err := pendingQuery.Where("is_completed = ?", false).Count(&stats.Pending).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Overdue count
|
||||
overdueQuery := baseQuery.Session(&gorm.Session{})
|
||||
if err := overdueQuery.Where("is_completed = ? AND due_date < ?", false, now).Count(&stats.Overdue).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Completed on time count (completed_at <= due_date)
|
||||
onTimeQuery := baseQuery.Session(&gorm.Session{})
|
||||
if err := onTimeQuery.Where("is_completed = ? AND completed_at <= due_date", true).Count(&stats.CompletedOnTime).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Calculate on-time completion rate
|
||||
if stats.Completed > 0 {
|
||||
stats.OnTimeCompletionRate = float64(stats.CompletedOnTime) / float64(stats.Completed) * 100
|
||||
}
|
||||
@@ -281,7 +262,6 @@ func (r *AssignmentRepository) GetStatistics(userID uint, filter StatisticsFilte
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// GetStatisticsBySubjects returns statistics grouped by subject
|
||||
func (r *AssignmentRepository) GetStatisticsBySubjects(userID uint, filter StatisticsFilter) ([]SubjectStatistics, error) {
|
||||
now := time.Now()
|
||||
subjects, err := r.GetSubjectsByUserID(userID)
|
||||
@@ -301,7 +281,6 @@ func (r *AssignmentRepository) GetStatisticsBySubjects(userID uint, filter Stati
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Count overdue for this subject
|
||||
overdueQuery := r.db.Model(&models.Assignment{}).
|
||||
Where("user_id = ? AND subject = ? AND is_completed = ? AND due_date < ?", userID, subject, false, now)
|
||||
if filter.From != nil {
|
||||
@@ -328,21 +307,18 @@ func (r *AssignmentRepository) GetStatisticsBySubjects(userID uint, filter Stati
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// ArchiveBySubject archives all assignments for a subject
|
||||
func (r *AssignmentRepository) ArchiveBySubject(userID uint, subject string) error {
|
||||
return r.db.Model(&models.Assignment{}).
|
||||
Where("user_id = ? AND subject = ?", userID, subject).
|
||||
Update("is_archived", true).Error
|
||||
}
|
||||
|
||||
// UnarchiveBySubject unarchives all assignments for a subject
|
||||
func (r *AssignmentRepository) UnarchiveBySubject(userID uint, subject string) error {
|
||||
return r.db.Model(&models.Assignment{}).
|
||||
Where("user_id = ? AND subject = ?", userID, subject).
|
||||
Update("is_archived", false).Error
|
||||
}
|
||||
|
||||
// GetArchivedSubjects returns a list of archived subjects for a user
|
||||
func (r *AssignmentRepository) GetArchivedSubjects(userID uint) ([]string, error) {
|
||||
var subjects []string
|
||||
err := r.db.Model(&models.Assignment{}).
|
||||
@@ -352,7 +328,6 @@ func (r *AssignmentRepository) GetArchivedSubjects(userID uint) ([]string, error
|
||||
return subjects, err
|
||||
}
|
||||
|
||||
// GetSubjectsByUserIDWithArchived returns subjects optionally including archived
|
||||
func (r *AssignmentRepository) GetSubjectsByUserIDWithArchived(userID uint, includeArchived bool) ([]string, error) {
|
||||
var subjects []string
|
||||
query := r.db.Model(&models.Assignment{}).
|
||||
|
||||
123
internal/repository/recurring_assignment_repository.go
Normal file
123
internal/repository/recurring_assignment_repository.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"homework-manager/internal/database"
|
||||
"homework-manager/internal/models"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type RecurringAssignmentRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewRecurringAssignmentRepository() *RecurringAssignmentRepository {
|
||||
return &RecurringAssignmentRepository{db: database.GetDB()}
|
||||
}
|
||||
|
||||
func (r *RecurringAssignmentRepository) Create(recurring *models.RecurringAssignment) error {
|
||||
return r.db.Create(recurring).Error
|
||||
}
|
||||
|
||||
func (r *RecurringAssignmentRepository) FindByID(id uint) (*models.RecurringAssignment, error) {
|
||||
var recurring models.RecurringAssignment
|
||||
err := r.db.First(&recurring, id).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &recurring, nil
|
||||
}
|
||||
|
||||
func (r *RecurringAssignmentRepository) FindByUserID(userID uint) ([]models.RecurringAssignment, error) {
|
||||
var recurrings []models.RecurringAssignment
|
||||
err := r.db.Where("user_id = ?", userID).Order("created_at DESC").Find(&recurrings).Error
|
||||
return recurrings, err
|
||||
}
|
||||
|
||||
func (r *RecurringAssignmentRepository) FindActiveByUserID(userID uint) ([]models.RecurringAssignment, error) {
|
||||
var recurrings []models.RecurringAssignment
|
||||
err := r.db.Where("user_id = ? AND is_active = ?", userID, true).Order("created_at DESC").Find(&recurrings).Error
|
||||
return recurrings, err
|
||||
}
|
||||
|
||||
func (r *RecurringAssignmentRepository) Update(recurring *models.RecurringAssignment) error {
|
||||
return r.db.Save(recurring).Error
|
||||
}
|
||||
|
||||
func (r *RecurringAssignmentRepository) Delete(id uint) error {
|
||||
return r.db.Delete(&models.RecurringAssignment{}, id).Error
|
||||
}
|
||||
|
||||
func (r *RecurringAssignmentRepository) FindDueForGeneration() ([]models.RecurringAssignment, error) {
|
||||
var recurrings []models.RecurringAssignment
|
||||
|
||||
err := r.db.Where("is_active = ? AND recurrence_type != ?", true, models.RecurrenceNone).
|
||||
Find(&recurrings).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []models.RecurringAssignment
|
||||
now := time.Now()
|
||||
for _, rec := range recurrings {
|
||||
shouldGenerate := true
|
||||
|
||||
switch rec.EndType {
|
||||
case models.EndTypeCount:
|
||||
if rec.EndCount != nil && rec.GeneratedCount >= *rec.EndCount {
|
||||
shouldGenerate = false
|
||||
}
|
||||
case models.EndTypeDate:
|
||||
if rec.EndDate != nil && now.After(*rec.EndDate) {
|
||||
shouldGenerate = false
|
||||
}
|
||||
}
|
||||
|
||||
if shouldGenerate {
|
||||
result = append(result, rec)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *RecurringAssignmentRepository) GetLatestAssignmentByRecurringID(recurringID uint) (*models.Assignment, error) {
|
||||
var assignment models.Assignment
|
||||
err := r.db.Where("recurring_assignment_id = ?", recurringID).
|
||||
Order("due_date DESC").
|
||||
First(&assignment).Error
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &assignment, nil
|
||||
}
|
||||
|
||||
func (r *RecurringAssignmentRepository) GetAssignmentsByRecurringID(recurringID uint) ([]models.Assignment, error) {
|
||||
var assignments []models.Assignment
|
||||
err := r.db.Where("recurring_assignment_id = ?", recurringID).
|
||||
Order("due_date ASC").
|
||||
Find(&assignments).Error
|
||||
return assignments, err
|
||||
}
|
||||
|
||||
func (r *RecurringAssignmentRepository) GetFutureAssignmentsByRecurringID(recurringID uint, fromDate time.Time) ([]models.Assignment, error) {
|
||||
var assignments []models.Assignment
|
||||
err := r.db.Where("recurring_assignment_id = ? AND due_date >= ?", recurringID, fromDate).
|
||||
Order("due_date ASC").
|
||||
Find(&assignments).Error
|
||||
return assignments, err
|
||||
}
|
||||
|
||||
func (r *RecurringAssignmentRepository) CountPendingByRecurringID(recurringID uint) (int64, error) {
|
||||
var count int64
|
||||
err := r.db.Model(&models.Assignment{}).
|
||||
Where("recurring_assignment_id = ? AND is_completed = ?", recurringID, false).
|
||||
Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
Reference in New Issue
Block a user