func makeMutation(mmap map[string][]*cassandra.Mutation, cf, name string,
	value []byte, now time.Time) {
	var m *cassandra.Mutation = cassandra.NewMutation()
	var col *cassandra.Column = cassandra.NewColumn()

	col.Name = []byte(name)
	col.Value = value
	col.Timestamp = proto.Int64(now.UnixNano())

	m.ColumnOrSupercolumn = cassandra.NewColumnOrSuperColumn()
	m.ColumnOrSupercolumn.Column = col
	mmap[cf] = append(mmap[cf], m)
}
Beispiel #2
0
// Create a new mutation with the given name, value and time stamp.
func newCassandraMutationBytes(name string, value []byte, now *time.Time, ttl int32) *cassandra.Mutation {
	var ret = cassandra.NewMutation()
	var col = cassandra.NewColumn()
	var now_long = int64(now.UnixNano())

	col.Timestamp = &now_long
	col.Name = []byte(name)
	col.Value = value

	if ttl > 0 {
		col.TTL = &ttl
	}

	ret.ColumnOrSupercolumn = cassandra.NewColumnOrSuperColumn()
	ret.ColumnOrSupercolumn.Column = col

	return ret
}
func (self *ProductEditAPI) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var buf *bytes.Buffer = new(bytes.Buffer)
	var specid string = req.PostFormValue("id")
	var uuid UUID
	var codes *Barcodes = new(Barcodes)
	var mmap map[string]map[string][]*cassandra.Mutation
	var tsprefix []byte
	var prod Product
	var mutations []*cassandra.Mutation
	var mutation *cassandra.Mutation
	var col *cassandra.Column
	var ire *cassandra.InvalidRequestException
	var ue *cassandra.UnavailableException
	var te *cassandra.TimedOutException
	var barcode string
	var now time.Time = time.Now()
	var err error
	var match bool

	numRequests.Add(1)
	numAPIRequests.Add(1)

	// Check the user is in the reqeuested scope.
	if !self.authenticator.IsAuthenticatedScope(req, self.scope) {
		numDisallowedScope.Add(1)
		http.Error(w,
			"You are not in the right group to access this resource",
			http.StatusForbidden)
		return
	}

	// Check if the product name has been specified.
	prod.Name = req.PostFormValue("prodname")
	if len(prod.Name) <= 0 {
		log.Print("Parsing product name: ", err)
		http.Error(w, "Product name empty", http.StatusNotAcceptable)
		return
	}

	prod.Price, err = strconv.ParseFloat(req.PostFormValue("price"), 64)
	if err != nil {
		log.Print("Parsing price: ", err)
		http.Error(w, "price: "+err.Error(), http.StatusNotAcceptable)
		return
	}

	prod.Stock, err = strconv.ParseUint(req.PostFormValue("stock"), 10, 64)
	if err != nil {
		log.Print("Parsing stock: ", err)
		http.Error(w, "stock: "+err.Error(), http.StatusNotAcceptable)
		return
	}

	// Check if the barcode has been given. If it was, it needs to be
	// numeric (EAN-13). If we find different types of barcodes we can
	// always revise this.
	for _, barcode = range req.PostForm["barcode"] {
		barcode = strings.Replace(barcode, " ", "", -1)
		if len(barcode) > 0 {
			match, err = regexp.MatchString("^[0-9]+$", barcode)
			if err != nil {
				productEditErrors.Add(err.Error(), 1)
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			if match {
				codes.Barcode = append(codes.Barcode, barcode)
			} else {
				productEditErrors.Add("barcode-format-error", 1)
				http.Error(w, "Barcode should only contain numbers",
					http.StatusNotAcceptable)
				return
			}
		}
	}

	// Create column data for the product row.
	col = cassandra.NewColumn()
	col.Name = []byte("name")
	col.Value = []byte(prod.Name)
	col.Timestamp = now.Unix()
	mutation = cassandra.NewMutation()
	mutation.ColumnOrSupercolumn = cassandra.NewColumnOrSuperColumn()
	mutation.ColumnOrSupercolumn.Column = col
	mutations = append(mutations, mutation)

	err = binary.Write(buf, binary.BigEndian, prod.Price)
	if err != nil {
		productEditErrors.Add(err.Error(), 1)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	col = cassandra.NewColumn()
	col.Name = []byte("price")
	col.Value = buf.Bytes()
	col.Timestamp = now.Unix()
	mutation = cassandra.NewMutation()
	mutation.ColumnOrSupercolumn = cassandra.NewColumnOrSuperColumn()
	mutation.ColumnOrSupercolumn.Column = col
	mutations = append(mutations, mutation)

	buf = new(bytes.Buffer)
	err = binary.Write(buf, binary.BigEndian, prod.Stock)
	if err != nil {
		productEditErrors.Add(err.Error(), 1)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	col = cassandra.NewColumn()
	col.Name = []byte("stock")
	col.Value = buf.Bytes()
	col.Timestamp = now.Unix()
	mutation = cassandra.NewMutation()
	mutation.ColumnOrSupercolumn = cassandra.NewColumnOrSuperColumn()
	mutation.ColumnOrSupercolumn.Column = col
	mutations = append(mutations, mutation)

	col = cassandra.NewColumn()
	col.Name = []byte("barcodes")
	col.Value, err = proto.Marshal(codes)
	if err != nil {
		productEditErrors.Add(err.Error(), 1)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	col.Timestamp = now.Unix()
	mutation = cassandra.NewMutation()
	mutation.ColumnOrSupercolumn = cassandra.NewColumnOrSuperColumn()
	mutation.ColumnOrSupercolumn.Column = col
	mutations = append(mutations, mutation)

	// If we're editing an existing product, re-use that UUID. Otherwise,
	// generate one.
	if len(specid) > 0 {
		uuid, err = ParseUUID(specid)
	} else {
		uuid, err = GenTimeUUID(&now)
	}
	if err != nil {
		productEditErrors.Add(err.Error(), 1)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	mmap = make(map[string]map[string][]*cassandra.Mutation)
	mmap[string(uuid)] = make(map[string][]*cassandra.Mutation)
	mmap[string(uuid)]["products"] = mutations

	// Create the entry in the products_byname index.
	mutations = make([]*cassandra.Mutation, 0)
	col = cassandra.NewColumn()
	col.Name = []byte("product")
	col.Value = uuid
	col.Timestamp = now.Unix()
	mutation = cassandra.NewMutation()
	mutation.ColumnOrSupercolumn = cassandra.NewColumnOrSuperColumn()
	mutation.ColumnOrSupercolumn.Column = col
	mutations = append(mutations, mutation)
	mmap[prod.Name] = make(map[string][]*cassandra.Mutation)
	mmap[prod.Name]["products_byname"] = mutations

	// If a barcode has been given, specify it in the products_bybarcode
	// column.
	if len(barcode) > 0 {
		mmap[barcode] = make(map[string][]*cassandra.Mutation)
		mmap[barcode]["products_bybarcode"] = mutations
	}

	// Log a timeseries entry stating that the product has been present
	// at the time.
	mutations = make([]*cassandra.Mutation, 0)
	col = cassandra.NewColumn()
	col.Name = []byte("product-count")
	col.Value = buf.Bytes() // still the product count from above.
	col.Timestamp = now.Unix()
	mutation = cassandra.NewMutation()
	mutation.ColumnOrSupercolumn = cassandra.NewColumnOrSuperColumn()
	mutation.ColumnOrSupercolumn.Column = col
	mutations = append(mutations, mutation)

	// Create the TS prefix: first the UUID, then the timestamp.
	buf = new(bytes.Buffer)
	err = binary.Write(buf, binary.BigEndian, now.UnixNano())
	if err != nil {
		productEditErrors.Add(err.Error(), 1)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	tsprefix = make([]byte, len(uuid)+buf.Len()+1)
	copy(tsprefix, uuid)
	tsprefix[len(uuid)] = ':'
	for i, v := range buf.Bytes() {
		tsprefix[len(uuid)+i+1] = v
	}
	mmap[string(tsprefix)] = make(map[string][]*cassandra.Mutation)
	mmap[string(tsprefix)]["product_tsdata"] = mutations

	// Now, write the mutations to the database.
	ire, ue, te, err = self.client.AtomicBatchMutate(mmap,
		cassandra.ConsistencyLevel_QUORUM)
	if ire != nil {
		log.Println("Invalid request: ", ire.Why)
		productEditErrors.Add(ire.Why, 1)
		return
	}
	if ue != nil {
		log.Println("Unavailable")
		productEditErrors.Add("unavailable", 1)
		return
	}
	if te != nil {
		log.Println("Request to database backend timed out")
		productEditErrors.Add("timeout", 1)
		return
	}
	if err != nil {
		log.Println("Generic error: ", err)
		productEditErrors.Add(err.Error(), 1)
		return
	}
}
Beispiel #4
0
// Move a member record to the queue for getting their user account removed
// (e.g. when they leave us). Set the retention to 2 years instead of just
// 6 months, since they have been a member.
func (m *MembershipDB) MoveMemberToTrash(id, initiator, reason string) error {
	var now time.Time = time.Now()
	var now_long uint64 = uint64(now.Unix())
	var uuid cassandra.UUID
	var mmap map[string]map[string][]*cassandra.Mutation
	var member *MembershipAgreement

	var cp *cassandra.ColumnPath = cassandra.NewColumnPath()
	var cos *cassandra.ColumnOrSuperColumn
	var del *cassandra.Deletion = cassandra.NewDeletion()
	var mu *cassandra.Mutation
	var ts int64

	var err error

	cp.ColumnFamily = "members"
	cp.Column = []byte("pb_data")

	uuid, err = cassandra.GenTimeUUID(&now)
	if err != nil {
		return err
	}

	cos, err = m.conn.Get(
		[]byte(memberPrefix+id), cp, cassandra.ConsistencyLevel_QUORUM)
	if err != nil {
		return err
	}

	member = new(MembershipAgreement)
	err = proto.Unmarshal(cos.Column.Value, member)
	if err != nil {
		return err
	}

	del.Predicate = cassandra.NewSlicePredicate()
	del.Predicate.ColumnNames = allColumns
	del.Timestamp = cos.Column.Timestamp

	mu = cassandra.NewMutation()
	mu.Deletion = del

	mmap = make(map[string]map[string][]*cassandra.Mutation)
	mmap[memberPrefix+id] = make(map[string][]*cassandra.Mutation)
	mmap[memberPrefix+id]["members"] = []*cassandra.Mutation{mu}

	member.Metadata.GoodbyeInitiator = &initiator
	member.Metadata.GoodbyeTimestamp = &now_long
	member.Metadata.GoodbyeReason = &reason

	ts = now.UnixNano()
	cos.Column = cassandra.NewColumn()
	cos.Column.Name = []byte("pb_data")
	cos.Column.Timestamp = &ts
	cos.Column.Value, err = proto.Marshal(member)
	if err != nil {
		return err
	}

	mu = cassandra.NewMutation()
	mu.ColumnOrSupercolumn = cos

	mmap[dequeuePrefix+id] = make(map[string][]*cassandra.Mutation)
	mmap[dequeuePrefix+string([]byte(uuid))] =
		make(map[string][]*cassandra.Mutation)
	mmap[dequeuePrefix+string([]byte(uuid))]["membership_dequeue"] =
		[]*cassandra.Mutation{mu}

	err = m.conn.AtomicBatchMutate(
		mmap, cassandra.ConsistencyLevel_QUORUM)
	return err
}