package main import ( "errors" "log" "net/http" "os" "os/signal" "golang.org/x/crypto/bcrypt" "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson" ) func DBConnect(address string) *mgo.Session { session, err := mgo.Dial(address) if err != nil { panic(err) } // Optional. Switch the session to a monotonic behavior. session.SetMode(mgo.Monotonic, true) c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) go func() { for sig := range c { log.Println("%v captured - Closing database connection", sig) session.Close() os.Exit(1) } }() return session } func DBEnsureIndices(s *mgo.Session) error { i := mgo.Index{ Key: []string{"email"}, Unique: true, Background: true, Name: "email", } return s.DB(DBNAME).C("users").EnsureIndex(i) } type User struct { ID bson.ObjectId `bson:"_id" json:"-"` Email string `bson:"email" json:"email"` Password string `bson:"password,omitempty" json:"-"` DisplayName string `bson:"displayName,omitempty" json:"displayName,omitempty"` Picture string `bson:"picture,omitempty" json:"picture,omitempty"` Facebook string `bson:"facebook,omitempty" json:"facebook,omitempty"` Foursquare string `bson:"foursquare,omitempty" json:"foursquare,omitempty"` Google string `bson:"google,omitempty" json:"google,omitempty"` Github string `bson:"github,omitempty" json:"github,omitempty"` Linkedin string `bson:"linkedin,omitempty" json:"linkedin,omitempty"` Live string `bson:"live,omitempty" json:"live,omitempty"` Yahoo string `bson:"yahoo,omitempty" json:"yahoo,omitempty"` Twitter string `bson:"twitter,omitempty" json:"twitter,omitempty"` } func (u *User) Save(db *mgo.Database) error { uC := db.C("users") _, err := uC.UpsertId(u.ID, bson.M{"$set": u}) return err } func NewUser() (u *User) { u = &User{} u.ID = bson.NewObjectId() return } func CreateUser(db *mgo.Database, u *User) *Error { uC := db.C("users") pwHash, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost) if err != nil { return &Error{Reason: errors.New("Couldn't hash password"), Internal: true} } u.Password = string(pwHash) u.ID = bson.NewObjectId() err = uC.Insert(u) if mgo.IsDup(err) { return &Error{Reason: errors.New("User already exists"), Internal: false} } return nil } func AuthUser(db *mgo.Database, email, password string) (*User, *Error) { uC := db.C("users") user := &User{} err := uC.Find(bson.M{"email": email}).One(user) if err != nil { if err == mgo.ErrNotFound { return nil, &Error{Reason: errors.New("User wasn't found on our servers"), Internal: false} } return nil, &Error{Reason: err, Internal: true} } if user.ID == "" { return nil, &Error{Reason: errors.New("No user found"), Internal: false} } err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) if err != nil { return nil, &Error{Reason: errors.New("Incorrect password"), Internal: false, Code: http.StatusUnauthorized} } return user, nil } func FindUserByQuery(db *mgo.Database, query bson.M) (*User, *Error) { uC := db.C("users") user := &User{} err := uC.Find(query).One(user) if err != nil { return nil, &Error{Reason: err, Internal: true} } else if user.ID == "" { return nil, &Error{Reason: errors.New("No user found"), Internal: false} } return user, nil } func FindUserById(db *mgo.Database, id bson.ObjectId) (*User, *Error) { uC := db.C("users") user := &User{} err := uC.FindId(id).One(user) if err != nil { return nil, &Error{Reason: err, Internal: true} } else if user.ID == "" { return nil, &Error{Reason: errors.New("No user found"), Internal: false} } return user, nil } func FindUserByProvider(db *mgo.Database, provider, sub string) (*User, *Error) { return FindUserByQuery(db, bson.M{provider: sub}) } func UpdateUserById(db *mgo.Database, id bson.ObjectId, email, displayName string) *Error { uC := db.C("users") user, errM := FindUserById(db, id) if errM != nil { return errM } if displayName == "" { displayName = user.DisplayName } if email == "" { email = user.Email } err := uC.Update(bson.M{"_id": id}, bson.M{"$set": bson.M{"email": email, "displayName": displayName}}) if err != nil { return &Error{Reason: errors.New("No user found"), Internal: false} } return nil }