package models import ( "errors" "fmt" "time" "gorm.io/gorm" ) // CertificationPhoto table. type CertificationPhoto struct { ID uint64 `gorm:"primaryKey"` UserID uint64 `gorm:"uniqueIndex"` Filename string Filesize int64 Status CertificationPhotoStatus AdminComment string SecondaryNeeded bool // a secondary form of ID has been requested SecondaryFilename string // photo ID upload SecondaryVerified bool // mark true when ID checked so original can be deleted IPAddress string // the IP they uploaded the photo from CreatedAt time.Time UpdatedAt time.Time } type CertificationPhotoStatus string const ( CertificationPhotoNeeded CertificationPhotoStatus = "needed" CertificationPhotoPending CertificationPhotoStatus = "pending" CertificationPhotoApproved CertificationPhotoStatus = "approved" CertificationPhotoRejected CertificationPhotoStatus = "rejected" // If a photo is pending approval but the admin wants to engage the // secondary check (prompt user for a photo ID upload) CertificationPhotoSecondary CertificationPhotoStatus = "secondary" ) // GetCertificationPhoto retrieves the user's record from the DB or upserts their initial record. func GetCertificationPhoto(userID uint64) (*CertificationPhoto, error) { p := &CertificationPhoto{} result := DB.Where("user_id = ?", userID).First(&p) if result.Error == gorm.ErrRecordNotFound { p = &CertificationPhoto{ UserID: userID, Status: CertificationPhotoNeeded, } result = DB.Create(p) return p, result.Error } return p, result.Error } // CertifiedSince retrieve's the last updated date of the user's certification photo, if approved. // // This incurs a DB query for their cert photo. func (u *User) CertifiedSince() (time.Time, error) { if !u.Certified { return time.Time{}, errors.New("user is not certified") } cert, err := GetCertificationPhoto(u.ID) if err != nil { return time.Time{}, err } if cert.Status != CertificationPhotoApproved { return time.Time{}, fmt.Errorf("cert photo status is: %s (expected 'approved')", cert.Status) } return cert.UpdatedAt, nil } // CertificationPhotosNeedingApproval returns a pager of the pictures that require admin approval. func CertificationPhotosNeedingApproval(status CertificationPhotoStatus, pager *Pagination) ([]*CertificationPhoto, error) { var p = []*CertificationPhoto{} query := DB.Where( "status = ?", status, ).Order( pager.Sort, ) // Get the total count. query.Model(&CertificationPhoto{}).Count(&pager.Total) result := query.Offset( pager.GetOffset(), ).Limit(pager.PerPage).Find(&p) return p, result.Error } // CountCertificationPhotosNeedingApproval gets the count of pending photos for admin alert. func CountCertificationPhotosNeedingApproval() int64 { var count int64 DB.Where("status = ?", CertificationPhotoPending).Model(&CertificationPhoto{}).Count(&count) return count } // Save photo. func (p *CertificationPhoto) Save() error { result := DB.Save(p) return result.Error } // Delete the DB entry. func (p *CertificationPhoto) Delete() error { return DB.Delete(p).Error }