website/pkg/models/certification.go

114 lines
3.2 KiB
Go
Raw Permalink Normal View History

package models
import (
"errors"
"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 {
// The edge case can come up if a user was manually certified but didn't have an approved picture.
// Return their CreatedAt instead.
return u.CreatedAt, nil
}
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
}