func (i IsNumericChecker) IsFormat(data string) bool {
	return govalidator.IsNumeric(data)
}
Example #2
0
// list object
// supports
// - pagination using 'page' query. Use per_page to set the number of results per page. max is 100
// - filters: filter_type, filter_service, filter_open, filter_open_method, filter_gte_date_created
//   filter_lte_date_created
// - sorting: sort_balance, sort_date_created
func (c *WalletController) List(params martini.Params, res http.ResponseWriter, req services.AuxRequestContext, db *services.DB) {

	// TODO: get from access token
	// authorizing wallet id
	authWalletID := "55c679145fe09c74ed000001"

	dbCon := db.GetPostgresHandle()

	// get wallet
	wallet, found, err := models.FindWalletByObjectID(dbCon, params["id"])
	if !found {
		services.Res(res).Error(404, "not_found", "wallet not found")
		return
	} else if err != nil {
		c.log.Error(err.Error())
		services.Res(res).Error(500, "", "server error")
		return
	}

	// ensure wallet matches authorizing wallet
	if wallet.ObjectID != authWalletID {
		services.Res(res).Error(401, "unauthorized", "client does not have permission to access wallet")
		return
	}

	query := req.URL.Query()
	qPage := query.Get("page")
	if c.validate.IsEmpty(qPage) {
		qPage = "0"
	} else if !validator.IsNumeric(qPage) {
		services.Res(res).Error(400, "invalid_parameter", "page query value must be numeric")
		return
	}

	q := make(map[string]interface{})
	q["wallet_id"] = wallet.ID
	order := "id asc"
	limitPerPage := int64(2)
	offset := int64(0)
	currentPage, err := strconv.ParseInt(qPage, 0, 64)
	if err != nil {
		c.log.Error(err.Error())
		services.Res(res).Error(500, "", "server error")
		return
	}

	// set limit per page if provided in query
	qPerPage := query.Get("per_page")
	if !c.validate.IsEmpty(qPerPage) {
		if validator.IsNumeric(qPerPage) {
			qPerPage, _ := strconv.ParseInt(qPerPage, 0, 64)
			if qPerPage > 100 {
				qPerPage = 100
			} else if qPerPage <= 0 {
				qPerPage = limitPerPage
			}
			limitPerPage = qPerPage
		}
	}

	// set current page default and calculate offset
	if currentPage <= 1 {
		currentPage = 1
		offset = 0
	} else {
		offset = (int64(limitPerPage) * currentPage) - int64(limitPerPage)
	}

	// apply type filter if included in query
	filterType := query.Get("filter_type")
	if !c.validate.IsEmpty(filterType) && services.StringInStringSlice([]string{"obj_value", "obj_valueless"}, filterType) {
		q["type"] = filterType
	}

	// apply service filter if included in query
	filterService := query.Get("filter_service")
	if !c.validate.IsEmpty(filterService) {

		// find service
		service, found, err := models.FindServiceByObjectID(db.GetPostgresHandle(), filterService)
		if err != nil {
			c.log.Error(err.Error())
			services.Res(res).Error(500, "", "server error")
			return
		}

		if found {
			q["service_id"] = service.ID
		}
	}

	// apply open filter if included in query
	filterOpen := query.Get("filter_open")
	if !c.validate.IsEmpty(filterOpen) && services.StringInStringSlice([]string{"true", "false"}, filterOpen) {
		q["open"] = filterOpen
	}

	// apply open_method filter if included in query
	filterOpenMethod := query.Get("filter_open_method")
	if !c.validate.IsEmpty(filterOpenMethod) && services.StringInStringSlice([]string{"open", "open_timed", "open_pin"}, filterOpenMethod) {
		q["open_method"] = filterOpenMethod
	}

	// apply filter_gte_date_created filter if included in query
	filterGTEDateCreated := query.Get("filter_gte_date_created")
	if !c.validate.IsEmpty(filterGTEDateCreated) {
		if validator.IsNumeric(filterGTEDateCreated) {
			ts, _ := strconv.ParseInt(filterGTEDateCreated, 0, 64)
			dbCon = dbCon.Where("created_at >= ?", services.UnixToTime(ts).UTC().Format(time.RFC3339Nano))
		}
	}

	// apply filter_lte_date_created filter if included in query
	filterLTEDateCreated := query.Get("filter_lte_date_created")
	if !c.validate.IsEmpty(filterLTEDateCreated) {
		if validator.IsNumeric(filterLTEDateCreated) {
			ts, _ := strconv.ParseInt(filterLTEDateCreated, 0, 64)
			dbCon = dbCon.Where("created_at <= ?", services.UnixToTime(ts).UTC().Format(time.RFC3339Nano))
		}
	}

	// the below connection is used for sorting/ordering
	var dbConSort = dbCon

	// apply sort_balance sort if included
	sortBalance := query.Get("sort_balance")
	if !c.validate.IsEmpty(sortBalance) {
		orderVal := "asc"
		if sortBalance == "-1" {
			orderVal = "desc"
		}
		dbConSort = dbCon.Order("objects.balance " + orderVal)
	}

	// apply ort_date_created sort if included
	sortDateCreated := query.Get("sort_date_created")
	if !c.validate.IsEmpty(sortDateCreated) {
		orderVal := "asc"
		if sortDateCreated == "-1" {
			orderVal = "desc"
		}
		dbConSort = dbConSort.Order("objects.created_at " + orderVal)
	}

	// find objects associated with wallet
	objects := []models.Object{}
	var objectsCount int64

	// count number of objects. I didnt use dbConSort as count will throw an error
	dbCon.Model(models.Object{}).Where(q).Count(&objectsCount)

	// set the original db connection to the sort connection
	dbCon = dbConSort

	// calculate number of pages
	numPages := services.Round(float64(objectsCount) / float64(limitPerPage))

	// fetch the objects
	dbCon.Where(q).Preload("Service.Identity").Preload("Wallet.Identity").Limit(limitPerPage).Offset(offset).Order(order).Find(&objects)

	// prepare response
	respObj, _ := services.StructToJsonToSlice(objects)
	if len(respObj) == 0 {
		respObj = []map[string]interface{}{}
	}

	services.Res(res).Json(map[string]interface{}{
		"results": respObj,
		"_metadata": map[string]interface{}{
			"total_count": objectsCount,
			"per_page":    limitPerPage,
			"page_count":  numPages,
			"page":        currentPage,
		},
	})
}
func (s *service) IsNumeric(str string) bool                 { return gov.IsNumeric(str) }
Example #4
0
// open an object for charge/consumption. An object opened in this method
// will be consumable without restriction
func (c *ObjectController) Open(params martini.Params, res http.ResponseWriter, req services.AuxRequestContext, log *config.CustomLog, db *services.DB) {

	// TODO: get from access token
	// authorizing wallet id
	authWalletID := "55c679145fe09c74ed000001"

	// parse body
	var body objectOpenBody
	if err := c.ParseJsonBody(req, &body); err != nil {
		services.Res(res).Error(400, "invalid_body", "request body is invalid or malformed. Expects valid json body")
		return
	}

	// ensure open method is provided
	if c.validate.IsEmpty(body.OpenMethod) {
		services.Res(res).Error(400, "invalid_parameter", "open_method: open method is required")
		return
	}

	// ensure a known open method is provided
	if body.OpenMethod != "open" && body.OpenMethod != "open_timed" && body.OpenMethod != "open_pin" {
		services.Res(res).Error(400, "invalid_parameter", "unknown open type method")
		return
	}

	dbTx, err := db.GetPostgresHandleWithRepeatableReadTrans()
	if err != nil {
		c.log.Error(err.Error())
		services.Res(res).Error(500, "", "server error")
		return
	}

	// get the object
	object, found, err := models.FindObjectByObjectID(dbTx, params["id"])
	if !found {
		dbTx.Rollback()
		services.Res(res).Error(404, "not_found", "object was not found")
		return
	} else if err != nil {
		dbTx.Rollback()
		c.log.Error(err.Error())
		services.Res(res).Error(500, "", "server error")
		return
	}

	// ensure object belongs to authorizing wallet
	if object.Wallet.ObjectID != authWalletID {
		dbTx.Rollback()
		services.Res(res).Error(401, "unauthorized", "objects: object does not belong to authorizing wallet")
		return
	}

	// set object's open property to true and open_method to `open`
	clearOpen(&object)
	object.Open = true
	object.OpenMethod = models.ObjectOpenDefault

	// for open_timed,
	// set 'open_time' field to indicate object open window
	if body.OpenMethod == "open_timed" {

		// ensure time field is provided
		if body.Time == 0 {
			dbTx.Rollback()
			services.Res(res).Error(400, "invalid_parameter", "time: open window time is required. use unix time")
			return
		}

		// time must be in the future
		now := time.Now().UTC()
		if !now.Before(services.UnixToTime(body.Time).UTC()) {
			dbTx.Rollback()
			services.Res(res).Error(400, "invalid_parameter", "time: use a unix time pointing to a period in the future")
			return
		}

		object.OpenMethod = models.ObjectOpenTimed
		object.OpenTime = body.Time
	}

	// for open_pin
	// open pin sets a pin for used by charge API
	if body.OpenMethod == "open_pin" {

		// ensure pin is provided
		if c.validate.IsEmpty(body.Pin) {
			dbTx.Rollback()
			services.Res(res).Error(400, "invalid_parameter", "pin: pin is required")
			return
		}

		// pin must be numeric
		if !validator.IsNumeric(body.Pin) {
			dbTx.Rollback()
			services.Res(res).Error(400, "invalid_parameter", "pin: pin must contain only numeric characters. e.g 4345")
			return
		}

		// pin length must be between 4 - 12 characters
		if len(body.Pin) < 4 || len(body.Pin) > 12 {
			dbTx.Rollback()
			services.Res(res).Error(400, "invalid_parameter", "pin: pin must have a minimum character length of 4 and maximum of 12")
			return
		}

		// hash pin using bcrypt
		pinHash, err := services.Bcrypt(body.Pin, 10)
		if err != nil {
			c.log.Error("unable to hash password. reason: " + err.Error())
			services.Res(res).Error(500, "", "server error")
			return
		}

		object.OpenMethod = models.ObjectOpenPin
		object.OpenPin = pinHash
	}

	dbTx.Save(&object).Commit()
	services.Res(res).Json(object)
}