Example #1
0
func (c *Customer) validateEmail() error {
	if c.Email == "" {
		return fmt.Errorf("error: %s", "invalid email address")
	}

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return err
	}
	defer sess.Close()

	col := sess.DB("CurtCart").C("customer")

	var tmp Customer
	err = col.Find(bson.M{"email": c.Email}).One(&tmp)
	if err != nil && err != mgo.ErrNotFound {
		return err
	}

	if tmp.Id.Hex() != "" {
		return fmt.Errorf("error: %s", "email already exists")
	}

	return nil
}
Example #2
0
func (o *Order) Update() error {
	if o.Id.Hex() == "" {
		return fmt.Errorf("error: %s", "invalid order identifier")
	}

	o.UpdatedAt = time.Now()

	if err := o.validate(); err != nil {
		return err
	}

	o.bindCustomer()

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return err
	}
	defer sess.Close()

	updateDoc, err := o.mapUpdate()
	if err != nil {
		return err
	}

	var change = mgo.Change{
		ReturnNew: true,
		Update: bson.M{
			"$set": updateDoc,
		},
	}

	_, err = sess.DB("CurtCart").C("order").Find(bson.M{"_id": o.Id, "shop_id": o.ShopId}).Apply(change, o)

	return err
}
Example #3
0
func (o *Order) Create() error {
	o.Token = bson.NewObjectId()
	o.CreatedAt = time.Now()
	o.ProcessedAt = time.Now()
	o.UpdatedAt = time.Now()

	if err := o.validate(); err != nil {
		return err
	}

	count, err := getOrderCount(o.ShopId)
	if err != nil {
		return err
	}
	o.OrderNumber = count + 1

	o.bindCustomer()

	if o.Id.Hex() == "" {
		o.Id = bson.NewObjectId()
	}

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return err
	}
	defer sess.Close()

	col := sess.DB("CurtCart").C("order")
	_, err = col.UpsertId(o.Id, o)

	return err
}
Example #4
0
// Add new customer.
func (c *Customer) Insert(ref string) error {
	if err := c.validateEmail(); err != nil {
		c.Password = ""
		return err
	}
	if c.Password == "" {
		return fmt.Errorf("error: %s", "invalid password")
	}
	if c.FirstName == "" {
		c.Password = ""
		return fmt.Errorf("error: %s", "invalid first name")
	}
	if c.LastName == "" {
		c.Password = ""
		return fmt.Errorf("error: %s", "invalid last name")
	}
	if c.Id.Hex() == "" {
		c.Id = bson.NewObjectId()
	}
	if c.CreatedAt.IsZero() {
		c.CreatedAt = time.Now()
	}
	c.UpdatedAt = time.Now()

	cryptic, err := bcrypt.GenerateFromPassword([]byte(c.Password), bcrypt.DefaultCost)
	if err != nil {
		c.Password = ""
		return fmt.Errorf("error: %s", err.Error())
	}
	pass := string(cryptic)
	c.generateToken(ref)
	c.Password = pass

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		c.Password = ""
		return err
	}
	defer sess.Close()

	col := sess.DB("CurtCart").C("customer")

	_, err = col.UpsertId(c.Id, c)
	if err != nil {
		c.Password = ""
		return err
	}

	// index the document
	idx := mgo.Index{
		Key:        []string{"email", "first_name", "last_name", "meta_fields", "note", "state"},
		Background: true,
		Sparse:     false,
		DropDups:   true,
	}
	col.EnsureIndex(idx)
	c.Password = ""

	return nil
}
Example #5
0
func AuthenticateAccount(token string) (Customer, error) {

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return Customer{}, err
	}
	defer sess.Close()

	var cust Customer
	qs := bson.M{
		"token": token,
		"$or": []bson.M{
			bson.M{"customer.addresses.deleted": false},
			bson.M{"customer.addresses.deleted": bson.M{
				"$exists": false,
			}},
		},
	}
	err = sess.DB("CurtCart").C("customer").Find(qs).One(&cust)
	if err != nil || !cust.Id.Valid() {
		return Customer{}, fmt.Errorf("error: %s", "failed to authenticate using JWT")
	}

	return cust, nil
}
Example #6
0
func (c *Customer) AddAddress(addr CustomerAddress) error {
	if c.Id.Hex() == "" {
		return fmt.Errorf("error: %s", "cannot update a customer that doesn't exist")
	}
	if addr.Id == nil || !addr.Id.Valid() {
		addrId := bson.NewObjectId()
		addr.Id = &addrId
	}

	if err := addr.Validate(); err != nil {
		return err
	}

	addr.UpdatedAt = time.Now()
	addr.CreatedAt = time.Now()

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return err
	}
	defer sess.Close()

	var change = mgo.Change{
		ReturnNew: true,
		Update: bson.M{
			"$addToSet": bson.M{
				"addresses": addr,
			},
		},
	}

	_, err = sess.DB("CurtCart").C("customer").Find(bson.M{"_id": c.Id, "shop_id": c.ShopId}).Apply(change, c)

	return err
}
Example #7
0
// Get a customer by email.
func (c *Customer) GetByEmail() error {
	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return err
	}
	defer sess.Close()

	col := sess.DB("CurtCart").C("customer")

	qs := bson.M{
		"email":   c.Email,
		"shop_id": c.ShopId,
		"$or": []bson.M{
			bson.M{"customer.addresses.deleted": false},
			bson.M{"customer.addresses.deleted": bson.M{
				"$exists": false,
			}},
		},
	}
	err = col.Find(qs).One(&c)
	if err != nil {
		return err
	}
	c.Password = ""

	return nil
}
Example #8
0
func (c *Customer) SaveAddress(addr CustomerAddress) error {
	if c.Id.Hex() == "" {
		return fmt.Errorf("error: %s", "cannot update a customer that doesn't exist")
	}

	if err := addr.Validate(); err != nil {
		return err
	}

	addr.UpdatedAt = time.Now()

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return err
	}
	defer sess.Close()

	qry := bson.M{
		"addresses._id": addr.Id,
	}
	change := bson.M{
		"$set": bson.M{
			"customer.$.address": addr,
		},
	}
	return sess.DB("CurtCart").C("customer").Update(qry, change)
}
Example #9
0
func getOrderCount(shopId bson.ObjectId) (int, error) {
	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return 0, err
	}
	defer sess.Close()

	return sess.DB("CurtCart").C("order").Find(bson.M{"shop_id": shopId}).Count()
}
Example #10
0
// Get all customers since a defined Id.
func CustomersSinceId(shopId bson.ObjectId, since_id bson.ObjectId, page, limit int, created_at_min, created_at_max, updated_at_min, updated_at_max *time.Time) ([]Customer, error) {
	custs := []Customer{}
	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return custs, err
	}
	defer sess.Close()

	c := sess.DB("CurtCart").C("customer")
	qs := bson.M{
		"shop_id": shopId.String(),
		"_id": bson.M{
			"$gt": since_id.String(),
		},
		"$or": []bson.M{
			bson.M{"customer.addresses.deleted": false},
			bson.M{"customer.addresses.deleted": bson.M{
				"$exists": false,
			}},
		},
	}
	if created_at_min != nil || created_at_max != nil {
		createdQs := bson.M{}
		if created_at_min != nil {
			createdQs["&qt"] = created_at_min.String()
		}
		if created_at_max != nil {
			createdQs["&lt"] = created_at_max.String()
		}
		qs["created_at"] = createdQs
	}
	if updated_at_min != nil || updated_at_max != nil {
		updatedQs := bson.M{}
		if updated_at_min != nil {
			updatedQs["&qt"] = updated_at_min.String()
		}
		if updated_at_max != nil {
			updatedQs["&lt"] = updated_at_max.String()
		}
		qs["updated_at"] = updatedQs
	}

	if page == 1 {
		page = 0
	}
	err = c.Find(qs).Skip(page * limit).Limit(limit).All(&custs)
	if err != nil {
		return []Customer{}, err
	}

	for i, _ := range custs {
		custs[i].Password = ""
	}

	return custs, err
}
Example #11
0
func clearMongo() {
	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return
	}
	defer sess.Close()
	sess.DB("CurtCart").C("customer").RemoveAll(bson.M{})
	sess.DB("CurtCart").C("order").RemoveAll(bson.M{})
	sess.DB("CurtCart").C("shop").RemoveAll(bson.M{})
}
Example #12
0
// Update a customer.
// Updates updated_at, accepts_marketing, addresses, default_address,
// email, first_name, last_name, meta_fields, note, state, tags.
func (c *Customer) Update() error {
	if c.Id.Hex() == "" {
		c.Password = ""
		return fmt.Errorf("error: %s", "cannot update a customer that doesn't exist")
	}
	if c.FirstName == "" {
		c.Password = ""
		return fmt.Errorf("error: %s", "invalid first anem")
	}
	if c.LastName == "" {
		c.Password = ""
		return fmt.Errorf("error: %s", "invalid last name")
	}

	c.UpdatedAt = time.Now()

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return err
	}
	defer sess.Close()

	var change = mgo.Change{
		ReturnNew: true,
		Update: bson.M{
			"$set": bson.M{
				"accepts_marketing": c.AcceptsMarketing,
				"addresses":         c.Addresses,
				"default_address":   c.DefaultAddress,
				"first_name":        c.FirstName,
				"last_name":         c.LastName,
				"meta_fields":       c.MetaFields,
				"note":              c.Note,
				"state":             c.State,
				"tags":              c.Tags,
			},
		},
	}

	qs := bson.M{
		"_id":     c.Id,
		"shop_id": c.ShopId,
		"$or": []bson.M{
			bson.M{"customer.addresses.deleted": false},
			bson.M{"customer.addresses.deleted": bson.M{
				"$exists": false,
			}},
		},
	}
	_, err = sess.DB("CurtCart").C("customer").Find(qs).Apply(change, c)

	c.Password = ""
	return err
}
Example #13
0
// This method is used explicitly for generating test data
// DO NOT EXPOSE
func InsertTestData() *bson.ObjectId {
	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return nil
	}

	sh := Shop{}
	sh.Id = bson.NewObjectId()
	sh.Name = "Test Shop"
	sh.Address1 = "1119 Sunset Lane"
	sh.City = "Altoona"
	sh.Province = "Wisconsin"
	sh.ProvinceCode = "WI"
	sh.Country = "US"
	sh.CountryCode = "US"
	sh.CountryName = "United States"
	sh.Zip = "54720"
	sh.CreatedAt = time.Now()
	sh.Currency = "USD"
	sh.Domain, _ = url.Parse("http://store.ninneman.org")
	sh.Email = "*****@*****.**"
	sh.MoneyFormat = "$"
	sh.MoneyWithCurrencyFormat = "$ USD"
	sh.PasswordEnabled = true
	sh.Phone = "7153082604"
	sh.Public = false
	sh.ShopOwner = "Alex Ninneman"
	sh.TaxShipping = true
	sh.TaxesIncluded = false
	sh.CountyTaxes = false
	sh.Timezone = "US/Central"
	sh.HasStorefront = false

	l := geocoding.Lookup{
		Address: fmt.Sprintf("%s, %s, %s %s", sh.Address1, sh.City, sh.ProvinceCode, sh.Zip),
	}
	resp, err := l.Search()
	if err == nil && len(resp.Results) > 0 {
		sh.Longitude = resp.Results[0].Geometry.Location.Longitude
		sh.Latitude = resp.Results[0].Geometry.Location.Latitude
	}

	if err := sess.DB("CurtCart").C("shop").Insert(sh); err != nil {
		return nil
	}

	return &sh.Id
}
Example #14
0
func (sh *Shop) Get() error {

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return err
	}
	defer sess.Close()

	c := sess.DB("CurtCart").C("shop")
	err = c.Find(bson.M{"_id": sh.Id}).One(&sh)
	if err != nil {
		return err
	}

	return nil
}
Example #15
0
// Delete a customer.
// A customer can't be deleted if they have existing orders
func (c *Customer) Delete() error {
	if c.Id.Hex() == "" {
		return fmt.Errorf("error: %s", "invalid customer reference")
	}

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return err
	}
	defer sess.Close()

	if err := c.Get(); err != nil {
		return err
	}

	if c.Orders != nil && len(c.Orders) > 0 {
		return fmt.Errorf("error: %s", "can't remove a customer that has order information")
	}

	return sess.DB("CurtCart").C("customer").RemoveId(c.Id)
}
Example #16
0
func CustomerCount(shopId bson.ObjectId) (int, error) {
	if shopId.Hex() == "" {
		return 0, fmt.Errorf("error: %s", "invalid shop reference")
	}

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return 0, err
	}
	defer sess.Close()

	qs := bson.M{
		"shop_id": shopId,
		"$or": []bson.M{
			bson.M{"customer.addresses.deleted": false},
			bson.M{"customer.addresses.deleted": bson.M{
				"$exists": false,
			}},
		},
	}
	return sess.DB("CurtCart").C("customer").Find(qs).Count()
}
Example #17
0
func (c *Customer) DeleteAddress(addr CustomerAddress) error {
	if c.Id.Hex() == "" {
		return fmt.Errorf("error: %s", "cannot update a customer that doesn't exist")
	}

	if err := addr.Validate(); err != nil {
		return err
	}

	addr.UpdatedAt = time.Now()

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return err
	}
	defer sess.Close()

	qry := bson.M{
		"addresses._id": addr.Id,
	}
	change := bson.M{
		"$set": bson.M{
			"customer.$.address.deleted": true,
		},
	}

	err = sess.DB("CurtCart").C("customer").Update(qry, change)
	if err != nil {
		return err
	}

	for k, a := range c.Addresses {
		if a.Id == addr.Id {
			c.Addresses = append(c.Addresses[:k], c.Addresses[k+1:]...)
		}
	}

	return nil
}
Example #18
0
func (c *Customer) generateToken(referer string) error {
	c.Password = ""
	var err error

	// create token
	token := jwt.New(jwt.SigningMethodHS256)

	// assign claims
	token.Claims["iss"] = "carter.curtmfg.com"
	token.Claims["sub"] = referer
	token.Claims["exp"] = time.Now().Add(time.Hour * 1).Unix()
	token.Claims["iat"] = time.Now().Unix()

	c.Token, err = token.SignedString([]byte(jwtSigningKey))
	if err != nil {
		return err
	}

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return err
	}
	defer sess.Close()

	var change = mgo.Change{
		ReturnNew: true,
		Update: bson.M{
			"$set": bson.M{
				"token": c.Token,
			},
		},
	}

	_, err = sess.DB("CurtCart").C("customer").Find(bson.M{"_id": c.Id, "shop_id": c.ShopId}).Apply(change, c)

	c.Password = ""
	return err
}
Example #19
0
func SearchCustomers(query string, shopId bson.ObjectId) ([]Customer, error) {
	var custs []Customer
	if query == "" {
		return custs, fmt.Errorf("error: %s", "invalid query")
	}

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return custs, err
	}
	defer sess.Close()

	qs := bson.M{
		"$text": bson.M{
			"$search": query,
		},
		"shop_id":  shopId,
		"password": 0,
		"$or": []bson.M{
			bson.M{"customer.addresses.deleted": false},
			bson.M{"customer.addresses.deleted": bson.M{
				"$exists": false,
			}},
		},
	}

	err = sess.DB("CurtCart").C("customer").Find(qs).All(&custs)
	if err != nil {
		return []Customer{}, err
	}

	for i, _ := range custs {
		custs[i].Password = ""
	}

	return custs, err
}
Example #20
0
func IdentifierFromToken(t string) (bson.ObjectId, error) {
	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return "", err
	}
	defer sess.Close()

	var cust Customer
	qs := bson.M{
		"token": t,
		"$or": []bson.M{
			bson.M{"customer.addresses.deleted": false},
			bson.M{"customer.addresses.deleted": bson.M{
				"$exists": false,
			}},
		},
	}
	err = sess.DB("CurtCart").C("customer").Find(qs).One(&cust)
	if err != nil || !cust.Id.Valid() {
		return "", fmt.Errorf("error: %s", "failed to identify using JWT")
	}

	return cust.Id, nil
}
Example #21
0
// Login a customer.
func (c *Customer) Login(ref string) error {
	pass := c.Password
	c.Password = ""

	sess, err := mgo.DialWithInfo(database.MongoConnectionString())
	if err != nil {
		return err
	}
	defer sess.Close()

	col := sess.DB("CurtCart").C("customer")

	var custs []Customer
	qs := bson.M{
		"email":   c.Email,
		"shop_id": c.ShopId,
		"$or": []bson.M{
			bson.M{"customer.addresses.deleted": false},
			bson.M{"customer.addresses.deleted": bson.M{
				"$exists": false,
			}},
		},
	}
	err = col.Find(qs).All(&custs)
	if err != nil {
		return err
	}

	if custs == nil || len(custs) == 0 {
		return fmt.Errorf("error: %s", "no account for this email address")
	}

	for _, cust := range custs {
		if err := bcrypt.CompareHashAndPassword([]byte(cust.Password), []byte(pass)); err != nil {
			continue
		}

		c.Id = cust.Id
		c.ShopId = cust.ShopId
		c.AcceptsMarketing = cust.AcceptsMarketing
		c.Addresses = cust.Addresses
		c.DefaultAddress = cust.DefaultAddress
		c.CreatedAt = cust.CreatedAt
		c.Email = cust.Email
		c.FirstName = cust.FirstName
		c.LastName = cust.LastName
		c.MetaFields = cust.MetaFields
		c.LastOrderId = cust.LastOrderId
		c.LastOrderName = cust.LastOrderName
		c.OrdersCount = cust.OrdersCount
		c.Note = cust.Note
		c.State = cust.State
		c.Tags = cust.Tags
		c.UpdatedAt = cust.UpdatedAt
		c.VerifiedEmail = cust.VerifiedEmail
		c.Orders = cust.Orders
		c.generateToken(ref)

		return nil
	}

	return fmt.Errorf("error: %s", "credentials do not match")
}