2018-05-01 00:50:39 +00:00
|
|
|
package contacts
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2018-05-12 04:29:18 +00:00
|
|
|
"fmt"
|
2018-05-12 03:15:16 +00:00
|
|
|
"math/rand"
|
2018-05-01 00:50:39 +00:00
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2018-05-12 03:15:16 +00:00
|
|
|
"github.com/jinzhu/gorm"
|
2018-05-01 00:50:39 +00:00
|
|
|
"github.com/kirsle/golog"
|
|
|
|
)
|
|
|
|
|
2018-05-12 03:15:16 +00:00
|
|
|
// DB is a reference to the parent app's gorm DB.
|
|
|
|
var DB *gorm.DB
|
|
|
|
|
|
|
|
// UseDB registers the DB from the root app.
|
|
|
|
func UseDB(db *gorm.DB) {
|
|
|
|
DB = db
|
|
|
|
DB.AutoMigrate(&Contact{})
|
|
|
|
}
|
2018-05-01 00:50:39 +00:00
|
|
|
|
|
|
|
var log *golog.Logger
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
log = golog.GetLogger("blog")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Contact is an individual contact in the address book.
|
|
|
|
type Contact struct {
|
|
|
|
ID int `json:"id"`
|
2018-05-12 03:15:16 +00:00
|
|
|
Secret string `json:"secret" gorm:"unique"` // their lazy insecure login token
|
2018-05-01 00:50:39 +00:00
|
|
|
FirstName string `json:"firstName"`
|
|
|
|
LastName string `json:"lastName"`
|
|
|
|
Email string `json:"email"`
|
|
|
|
SMS string `json:"sms"`
|
|
|
|
LastSeen time.Time `json:"lastSeen"`
|
|
|
|
Created time.Time `json:"created"`
|
|
|
|
Updated time.Time `json:"updated"`
|
|
|
|
}
|
|
|
|
|
2018-05-12 03:15:16 +00:00
|
|
|
// Contacts is the plurality of all contacts.
|
|
|
|
type Contacts []Contact
|
2018-05-01 00:50:39 +00:00
|
|
|
|
2018-05-12 03:15:16 +00:00
|
|
|
// NewContact initializes a new contact entry.
|
|
|
|
func NewContact() Contact {
|
|
|
|
return Contact{}
|
2018-05-01 00:50:39 +00:00
|
|
|
}
|
|
|
|
|
2018-05-12 03:15:16 +00:00
|
|
|
// pre-save checks.
|
|
|
|
func (c *Contact) presave() {
|
2018-05-01 00:50:39 +00:00
|
|
|
if c.Created.IsZero() {
|
|
|
|
c.Created = time.Now().UTC()
|
|
|
|
}
|
|
|
|
if c.Updated.IsZero() {
|
|
|
|
c.Updated = time.Now().UTC()
|
|
|
|
}
|
2018-05-12 03:15:16 +00:00
|
|
|
|
|
|
|
if c.Secret == "" {
|
|
|
|
// Make a random ID.
|
|
|
|
n := 8
|
|
|
|
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
|
|
|
secret := make([]rune, n)
|
|
|
|
for i := range secret {
|
|
|
|
secret[i] = letters[rand.Intn(len(letters))]
|
|
|
|
}
|
|
|
|
c.Secret = string(secret)
|
2018-05-12 04:29:18 +00:00
|
|
|
fmt.Printf("contact.presave: secret=%s", string(secret))
|
2018-05-12 03:15:16 +00:00
|
|
|
}
|
2018-05-01 00:50:39 +00:00
|
|
|
}
|
|
|
|
|
2018-05-12 03:15:16 +00:00
|
|
|
// Add a new contact.
|
|
|
|
func Add(c *Contact) error {
|
|
|
|
c.presave()
|
|
|
|
|
|
|
|
log.Error("contacts.Add: %+v", c)
|
|
|
|
|
|
|
|
return DB.Create(&c).Error
|
2018-05-01 00:50:39 +00:00
|
|
|
}
|
|
|
|
|
2018-05-12 03:15:16 +00:00
|
|
|
// All contacts from the database alphabetically sorted.
|
|
|
|
func All() (Contacts, error) {
|
|
|
|
result := Contacts{}
|
|
|
|
err := DB.Order("last_name").Find(&result).Error
|
|
|
|
return result, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get a contact by ID.
|
|
|
|
func Get(id int) (Contact, error) {
|
|
|
|
contact := Contact{}
|
|
|
|
err := DB.First(&contact, id).Error
|
|
|
|
return contact, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save the contact.
|
|
|
|
func (c Contact) Save() error {
|
|
|
|
c.presave()
|
|
|
|
return DB.Update(&c).Error
|
2018-05-01 00:50:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetEmail queries a contact by email address.
|
2018-05-12 03:15:16 +00:00
|
|
|
func GetEmail(email string) (Contact, error) {
|
|
|
|
contact := Contact{}
|
|
|
|
err := DB.Where("email = ?", email).First(&contact).Error
|
|
|
|
return contact, err
|
2018-05-01 00:50:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetSMS queries a contact by SMS number.
|
2018-05-12 03:15:16 +00:00
|
|
|
func GetSMS(number string) (Contact, error) {
|
|
|
|
contact := Contact{}
|
|
|
|
err := DB.Where("sms = ?", number).First(&contact).Error
|
|
|
|
return contact, err
|
2018-05-01 00:50:39 +00:00
|
|
|
}
|
|
|
|
|
2018-05-12 04:29:18 +00:00
|
|
|
// GetBySecret queries a contact by their secret.
|
|
|
|
func GetBySecret(secret string) (Contact, error) {
|
|
|
|
contact := Contact{}
|
|
|
|
err := DB.Where("secret = ?", secret).First(&contact).Error
|
|
|
|
return contact, err
|
|
|
|
}
|
|
|
|
|
2018-05-01 00:50:39 +00:00
|
|
|
// Name returns a friendly name for the contact.
|
2018-05-12 03:15:16 +00:00
|
|
|
func (c Contact) Name() string {
|
2018-05-01 00:50:39 +00:00
|
|
|
var parts []string
|
|
|
|
if c.FirstName != "" {
|
|
|
|
parts = append(parts, c.FirstName)
|
|
|
|
}
|
|
|
|
if c.LastName != "" {
|
|
|
|
parts = append(parts, c.LastName)
|
|
|
|
}
|
|
|
|
if len(parts) == 0 {
|
|
|
|
if c.Email != "" {
|
|
|
|
parts = append(parts, c.Email)
|
|
|
|
} else if c.SMS != "" {
|
|
|
|
parts = append(parts, c.SMS)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return strings.Join(parts, " ")
|
|
|
|
}
|
|
|
|
|
|
|
|
// ParseForm accepts form data for a contact.
|
|
|
|
func (c *Contact) ParseForm(r *http.Request) {
|
|
|
|
c.FirstName = r.FormValue("first_name")
|
|
|
|
c.LastName = r.FormValue("last_name")
|
|
|
|
c.Email = strings.ToLower(r.FormValue("email"))
|
|
|
|
c.SMS = r.FormValue("sms")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validate the contact form.
|
2018-05-12 03:15:16 +00:00
|
|
|
func (c Contact) Validate() error {
|
2018-05-01 00:50:39 +00:00
|
|
|
if c.Email == "" && c.SMS == "" {
|
|
|
|
return errors.New("email or sms number required")
|
|
|
|
}
|
|
|
|
if c.FirstName == "" && c.LastName == "" {
|
|
|
|
return errors.New("first or last name required")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for uniqueness of email and SMS.
|
|
|
|
if c.Email != "" {
|
2018-05-12 03:15:16 +00:00
|
|
|
if _, err := GetEmail(c.Email); err == nil {
|
2018-05-01 00:50:39 +00:00
|
|
|
return errors.New("email address already exists")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if c.SMS != "" {
|
2018-05-12 03:15:16 +00:00
|
|
|
if _, err := GetSMS(c.SMS); err == nil {
|
2018-05-01 00:50:39 +00:00
|
|
|
return errors.New("sms number already exists")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|