initial commit from original sev version
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
RoleReader = "Reader"
|
||||
RoleAdmin = "Admin"
|
||||
)
|
||||
|
||||
var AbuseCategories = []string{
|
||||
"physical",
|
||||
"psychological",
|
||||
"sexual",
|
||||
"economic",
|
||||
"material",
|
||||
"digital",
|
||||
"stalking",
|
||||
"threats",
|
||||
"honor_related",
|
||||
}
|
||||
|
||||
var Genders = []string{"female", "male", "non_binary", "unknown"}
|
||||
var Statuses = []string{"new", "open", "referred", "closed"}
|
||||
|
||||
// FaroeLocations is the fixed set of accepted location values for this POC.
|
||||
var FaroeLocations = []string{
|
||||
"Akrar", "Argir", "Ánirnar", "Árnafjørður", "Bøur", "Dalur", "Depil", "Eiði",
|
||||
"Elduvík", "Fámjin", "Froðba", "Fuglafjørður", "Funningsfjørður", "Funningur",
|
||||
"Gásadalur", "Gjógv", "Glyvrar", "Gøtugjógv", "Haldórsvík", "Haraldssund",
|
||||
"Hattarvík", "Hellurnar", "Hestur", "Hov", "Hoyvík", "Hósvík", "Húsar",
|
||||
"Húsavík", "Hvalba", "Hvalvík", "Hvannasund", "Hvítanes", "Innan Glyvur",
|
||||
"Kaldbak", "Kaldbaksbotnur", "Kirkja", "Kirkjubøur", "Klaksvík", "Kolbeinagjógv",
|
||||
"Kollafjørður", "Koltur", "Kunoy", "Kvívík", "Lamba", "Lambareiði", "Langasandur",
|
||||
"Leirvík", "Leynar", "Ljósá", "Lopra", "Miðvágur", "Mikladalur", "Mjørkadalur",
|
||||
"Morskranes", "Múli", "Mykines", "Nes", "Nesvík", "Nólsoy", "Norðdepil",
|
||||
"Norðoyri", "Norðradalur", "Norðragøta", "Norðskáli", "Norðtoftir", "Oyndarfjørður",
|
||||
"Oyrarbakki", "Oyrareingir", "Oyri", "Porkeri", "Rituvík", "Runavík", "Saksun",
|
||||
"Saltangará", "Saltnes", "Sandavágur", "Sandur", "Sandvík", "Selatrað", "Signabøur",
|
||||
"Skarvanes", "Skála", "Skálafjørður/Skálabotnur", "Skálafjørður (Eysturkommuna)",
|
||||
"Skálavík", "Skipanes", "Skopun", "Skúgvoy", "Skælingur", "Stóra Dímun",
|
||||
"Strendur", "Streymnes", "Stykkið", "Sumba", "Sund", "Svínáir", "Svínoy",
|
||||
"Syðradalur (Kalsoy)", "Syðradalur (Streymoy)", "Syðrugøta", "Søldarfjørður",
|
||||
"Sørvágur", "Tjørnuvík", "Toftir", "Tórshavn", "Trongisvágur", "Trøllanes",
|
||||
"Tvøroyri", "Undir Gøtueiði", "Vatnsoyrar", "Vágur", "Válur", "Velbastaður",
|
||||
"Vestmanna", "Viðareiði", "Víkarbyrgi", "Æðuvík", "Ørðavík/Øravík", "Øravíkarlíð",
|
||||
}
|
||||
|
||||
type Registration struct {
|
||||
ID string `json:"id"`
|
||||
RegisteredAt string `json:"registered_at"`
|
||||
Gender string `json:"gender"`
|
||||
Location string `json:"location"`
|
||||
AbuseType string `json:"abuse_type"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type RegistrationFilter struct {
|
||||
Location string
|
||||
AbuseType string
|
||||
Gender string
|
||||
Status string
|
||||
Search string
|
||||
From time.Time
|
||||
To time.Time
|
||||
HasFrom bool
|
||||
HasTo bool
|
||||
Limit int
|
||||
Offset int
|
||||
}
|
||||
|
||||
func NormalizeRegistration(input *Registration) error {
|
||||
registeredAt := strings.TrimSpace(input.RegisteredAt)
|
||||
if registeredAt == "" {
|
||||
input.RegisteredAt = time.Now().UTC().Format(time.RFC3339)
|
||||
} else {
|
||||
parsed, err := ParseInputTime(registeredAt)
|
||||
if err != nil {
|
||||
return errors.New("registered_at must be RFC3339 or YYYY-MM-DD")
|
||||
}
|
||||
input.RegisteredAt = parsed.UTC().Format(time.RFC3339)
|
||||
}
|
||||
|
||||
gender := strings.ToLower(strings.TrimSpace(input.Gender))
|
||||
if gender == "" {
|
||||
gender = "unknown"
|
||||
}
|
||||
if !ContainsFold(Genders, gender) {
|
||||
return errors.New("gender must be one of: female, male, non_binary, unknown")
|
||||
}
|
||||
input.Gender = gender
|
||||
|
||||
location, ok := CanonicalLocation(input.Location)
|
||||
if !ok {
|
||||
return errors.New("location must be one of the allowed Faroese towns/villages")
|
||||
}
|
||||
input.Location = location
|
||||
|
||||
abuseType := strings.ToLower(strings.TrimSpace(input.AbuseType))
|
||||
if !ContainsFold(AbuseCategories, abuseType) {
|
||||
return errors.New("abuse_type must be one of the allowed categories")
|
||||
}
|
||||
input.AbuseType = abuseType
|
||||
|
||||
status := strings.ToLower(strings.TrimSpace(input.Status))
|
||||
if status == "" {
|
||||
status = "new"
|
||||
}
|
||||
if !ContainsFold(Statuses, status) {
|
||||
return errors.New("status must be one of: new, open, referred, closed")
|
||||
}
|
||||
input.Status = status
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseInputTime(value string) (time.Time, error) {
|
||||
value = strings.TrimSpace(value)
|
||||
if parsed, err := time.Parse(time.RFC3339, value); err == nil {
|
||||
return parsed, nil
|
||||
}
|
||||
if parsed, err := time.Parse("2006-01-02", value); err == nil {
|
||||
return parsed, nil
|
||||
}
|
||||
return time.Time{}, errors.New("invalid time")
|
||||
}
|
||||
|
||||
func CanonicalLocation(value string) (string, bool) {
|
||||
needle := strings.ToLower(strings.TrimSpace(value))
|
||||
for _, location := range FaroeLocations {
|
||||
if strings.ToLower(location) == needle {
|
||||
return location, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func ContainsFold(values []string, needle string) bool {
|
||||
needle = strings.ToLower(strings.TrimSpace(needle))
|
||||
for _, value := range values {
|
||||
if strings.ToLower(strings.TrimSpace(value)) == needle {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user