Example #1
0
func init() {
	gob.Register(time.Time{})
	gob.Register(datastore.ByteString{})
	gob.Register(&datastore.Key{})
	gob.Register(appengine.BlobKey(""))
	gob.Register(appengine.GeoPoint{})
}
func (tf *typeFilter) Save() ([]datastore.Property, error) {
	props := []datastore.Property{}
	for name, propList := range tf.pm {
		if len(name) != 0 && name[0] == '$' {
			continue
		}
		multiple := len(propList) > 1
		for _, prop := range propList {
			toAdd := datastore.Property{
				Name:     name,
				Multiple: multiple,
				NoIndex:  prop.IndexSetting() == ds.NoIndex,
			}
			switch prop.Type() {
			case ds.PTBytes:
				v := prop.Value().([]byte)
				if prop.IndexSetting() == ds.ShouldIndex {
					toAdd.Value = datastore.ByteString(v)
				} else {
					toAdd.Value = v
				}
			case ds.PTKey:
				toAdd.Value = dsF2R(prop.Value().(ds.Key))
			case ds.PTBlobKey:
				toAdd.Value = appengine.BlobKey(prop.Value().(bs.Key))
			case ds.PTGeoPoint:
				toAdd.Value = appengine.GeoPoint(prop.Value().(ds.GeoPoint))
			default:
				toAdd.Value = prop.Value()
			}
			props = append(props, toAdd)
		}
	}
	return props, nil
}
Example #3
0
// propValue returns a Go value that combines the raw PropertyValue with a
// meaning. For example, an Int64Value with GD_WHEN becomes a time.Time.
func propValue(v *pb.PropertyValue, m pb.Property_Meaning) (interface{}, error) {
	switch {
	case v.Int64Value != nil:
		if m == pb.Property_GD_WHEN {
			return fromUnixMicro(*v.Int64Value), nil
		} else {
			return *v.Int64Value, nil
		}
	case v.BooleanValue != nil:
		return *v.BooleanValue, nil
	case v.StringValue != nil:
		if m == pb.Property_BLOB {
			return []byte(*v.StringValue), nil
		} else if m == pb.Property_BLOBKEY {
			return appengine.BlobKey(*v.StringValue), nil
		} else if m == pb.Property_BYTESTRING {
			return ByteString(*v.StringValue), nil
		} else {
			return *v.StringValue, nil
		}
	case v.DoubleValue != nil:
		return *v.DoubleValue, nil
	case v.Referencevalue != nil:
		key, err := referenceValueToKey(v.Referencevalue)
		if err != nil {
			return nil, err
		}
		return key, nil
	case v.Pointvalue != nil:
		// NOTE: Strangely, latitude maps to X, longitude to Y.
		return appengine.GeoPoint{Lat: v.Pointvalue.GetX(), Lng: v.Pointvalue.GetY()}, nil
	}
	return nil, nil
}
Example #4
0
// propValue returns a Go value that combines the raw PropertyValue with a
// meaning. For example, an Int64Value with GD_WHEN becomes a time.Time.
func propValue(v *pb.PropertyValue, m pb.Property_Meaning) (interface{}, error) {
	switch {
	case v.Int64Value != nil:
		if m == pb.Property_GD_WHEN {
			return fromUnixMicro(*v.Int64Value), nil
		} else {
			return *v.Int64Value, nil
		}
	case v.BooleanValue != nil:
		return *v.BooleanValue, nil
	case v.StringValue != nil:
		if m == pb.Property_BLOB {
			return []byte(*v.StringValue), nil
		} else if m == pb.Property_BLOBKEY {
			return appengine.BlobKey(*v.StringValue), nil
		} else {
			return *v.StringValue, nil
		}
	case v.DoubleValue != nil:
		return *v.DoubleValue, nil
	case v.Referencevalue != nil:
		key, err := referenceValueToKey(v.Referencevalue)
		if err != nil {
			return nil, err
		}
		return key, nil
	}
	return nil, nil
}
Example #5
0
// BlobKeyForFile returns a BlobKey for a Google Storage file.
// The filename should be of the form "/gs/bucket_name/object_name".
func BlobKeyForFile(c context.Context, filename string) (appengine.BlobKey, error) {
	req := &blobpb.CreateEncodedGoogleStorageKeyRequest{
		Filename: &filename,
	}
	res := &blobpb.CreateEncodedGoogleStorageKeyResponse{}
	if err := internal.Call(c, "blobstore", "CreateEncodedGoogleStorageKey", req, res); err != nil {
		return "", err
	}
	return appengine.BlobKey(*res.BlobKey), nil
}
Example #6
0
func GetServingUrl(c *gin.Context) {
	r := c.Request
	ctx := appengine.NewContext(r)
	blobKey := appengine.BlobKey(c.Param("blobKey"))
	var err_msg string
	url, err := image.ServingURL(ctx, blobKey, nil)
	if err != nil {
		err_msg = "failed"
	}
	c.JSON(http.StatusOK, gin.H{"err": err_msg, "url": url, "blobKey": url.String()})
}
Example #7
0
func serveThumb(w http.ResponseWriter, r *http.Request, m map[string]interface{}) {

	c := appengine.NewContext(r)

	// c := appengine.NewContext(r)
	k := appengine.BlobKey(r.FormValue("blobkey"))

	var o image.ServingURLOptions = *new(image.ServingURLOptions)
	o.Size = 200
	o.Crop = true
	url, err := image.ServingURL(c, k, &o)

	loghttp.E(w, r, err, false)

	http.Redirect(w, r, url.String(), http.StatusFound)
}
Example #8
0
func handleFilesItem(w http.ResponseWriter, r *http.Request) {
	id := r.URL.Path
	if id == "" {
		w.WriteHeader(404)
		return
	}
	c := appengine.NewContext(r)
	key := datastore.NewKey(c, "File", id, 0, nil)
	switch r.Method {
	case "GET":
		var file File
		err := datastore.Get(c, key, &file)
		if err == datastore.ErrNoSuchEntity {
			http.NotFound(w, r)
			return
		}
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Errorf(c, "query file: %s", err.Error())
			return
		}
		w.Header().Set("Content-Type", "application/json")
		err = json.NewEncoder(w).Encode(&file)
		if err != nil {
			log.Errorf(c, "json encode: %s", err.Error())
		}
	case "DELETE":
		err := datastore.Delete(c, key)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Errorf(c, "delete file: %s", err.Error())
			return
		}
		err = blobstore.Delete(c, appengine.BlobKey(id))
		if err != nil {
			log.Warningf(c, "delete file '%s': %s", id, err.Error())
		}
		w.WriteHeader(204)
	default:
		http.Error(w, "Valid methods are GET and DELETE", http.StatusMethodNotAllowed)
		return
	}
}
Example #9
0
func handleBlobFile(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	key := datastore.NewKey(c, "File", r.URL.Path, 0, nil)

	var file File
	err := datastore.Get(c, key, &file)

	if err != nil {
		http.NotFound(w, r)
		return
	}

	w.Header().Set("Content-Type", mime.TypeByExtension(path.Ext(file.Name)))

	_, err = io.Copy(w, blobstore.NewReader(c, appengine.BlobKey(r.URL.Path)))
	if err != nil {
		log.Errorf(c, "stream blob: %s", err.Error())
	}
}
Example #10
0
func sampleHandler2(w http.ResponseWriter, r *http.Request) {
	// [START uploading_a_blob_3]
	ctx := appengine.NewContext(r)
	blobs, _, err := blobstore.ParseUpload(r)
	if err != nil {
		serveError(ctx, w, err)
		return
	}
	file := blobs["file"]
	if len(file) == 0 {
		log.Errorf(ctx, "no file uploaded")
		http.Redirect(w, r, "/", http.StatusFound)
		return
	}
	http.Redirect(w, r, "/serve/?blobKey="+string(file[0].BlobKey), http.StatusFound)
	// [END uploading_a_blob_3]

	// [START serving_a_blob]
	blobstore.Send(w, appengine.BlobKey(r.FormValue("blobKey")))
	// [END serving_a_blob]
}
Example #11
0
func TestReader(t *testing.T) {
	for _, rt := range readerTest {
		c := aetesting.FakeSingleContext(t, "blobstore", "FetchData", fakeFetchData)
		r := NewReader(c, appengine.BlobKey(rt.blobKey))
		for i, step := range rt.step {
			var (
				got    string
				gotErr error
				n      int
				offset int64
			)
			switch step.method {
			case "LargeReadAt":
				p := make([]byte, step.lenp)
				n, gotErr = r.ReadAt(p, step.offset)
				got = strconv.Itoa(n)
			case "Read":
				p := make([]byte, step.lenp)
				n, gotErr = r.Read(p)
				got = string(p[:n])
			case "ReadAt":
				p := make([]byte, step.lenp)
				n, gotErr = r.ReadAt(p, step.offset)
				got = string(p[:n])
			case "Seek":
				offset, gotErr = r.Seek(step.offset, step.whence)
				got = strconv.FormatInt(offset, 10)
			default:
				t.Fatalf("unknown method: %s", step.method)
			}
			if gotErr != step.wantErr {
				t.Fatalf("%s step %d: got error %v want %v", rt.blobKey, i, gotErr, step.wantErr)
			}
			if got != step.want {
				t.Fatalf("%s step %d: got %q want %q", rt.blobKey, i, got, step.want)
			}
		}
	}
}
func dsF2RProp(ctx context.Context, in ds.Property) (datastore.Property, error) {
	err := error(nil)
	ret := datastore.Property{
		NoIndex: in.IndexSetting() == ds.NoIndex,
	}
	switch in.Type() {
	case ds.PTBytes:
		v := in.Value().([]byte)
		if in.IndexSetting() == ds.ShouldIndex {
			ret.Value = datastore.ByteString(v)
		} else {
			ret.Value = v
		}
	case ds.PTKey:
		ret.Value, err = dsF2R(ctx, in.Value().(*ds.Key))
	case ds.PTBlobKey:
		ret.Value = appengine.BlobKey(in.Value().(bs.Key))
	case ds.PTGeoPoint:
		ret.Value = appengine.GeoPoint(in.Value().(ds.GeoPoint))
	default:
		ret.Value = in.Value()
	}
	return ret, err
}
Example #13
0
]`)

// icon is a sample white png file 16x16,
// dumped as a byte array.
var icon = []byte{
	137, 80, 78, 71, 13, 10, 26, 10,
	0, 0, 0, 13, 73, 72, 68, 82,
	0, 0, 0, 16, 0, 0, 0, 16,
	8, 2, 0, 0, 0, 144, 145, 104,
	54, 0, 0, 0, 9, 112, 72, 89,
	115, 0, 0, 11, 19, 0, 0, 11,
	19, 1, 0, 154, 156, 24, 0, 0,
	0, 7, 116, 73, 77, 69, 7, 222,
	5, 8, 21, 41, 53, 225, 172, 74,
	51, 0, 0, 0, 25, 116, 69, 88,
	116, 67, 111, 109, 109, 101, 110, 116,
	0, 67, 114, 101, 97, 116, 101, 100,
	32, 119, 105, 116, 104, 32, 71, 73,
	77, 80, 87, 129, 14, 23, 0, 0,
	0, 26, 73, 68, 65, 84, 40, 207,
	99, 252, 255, 255, 63, 3, 41, 128,
	137, 129, 68, 48, 170, 97, 84, 195,
	208, 209, 0, 0, 85, 109, 3, 29,
	159, 46, 21, 162, 0, 0, 0, 0,
	73, 69, 78, 68, 174, 66, 96, 130}

// blobKey is a sample appengine.BlobKey value.
var blobKey = appengine.BlobKey("AMIfv94Ly-gFmdjqsU9IwztyA6jjiChzE8cUSwkP8EE" +
	"fo4paIuXmHiwFkoccnayuqcTmkyXfDo8SS9uetO-6h7AhqlKQFYsY1tyGjrhjqmxOYT19CC" +
	"tH5tZEL2pxtCBLe6MFProzW1fw1du_vMwPsypKMHnnpZau6F_qJNoc6yoqnYIKGDvroNk")
Example #14
0
func handleServe(w http.ResponseWriter, r *http.Request) {
	blobstore.Send(w, appengine.BlobKey(r.FormValue("blobKey")))
}
Example #15
0
func serveFull(w http.ResponseWriter, r *http.Request, m map[string]interface{}) {
	blobstore.Send(w, appengine.BlobKey(r.FormValue("blobkey")))
}
Example #16
0
func Serve(c *gin.Context) {
	r := c.Request
	w := c.Writer
	blobstore.Send(w, appengine.BlobKey(r.FormValue("blobKey")))
}
Example #17
0
func handleBucketsItem(w http.ResponseWriter, r *http.Request) {
	id := r.URL.Path
	if id == "" {
		w.WriteHeader(404)
		return
	}
	c := appengine.NewContext(r)
	key := datastore.NewKey(c, "Bucket", id, 0, nil)
	switch r.Method {
	case "GET":
		var b Bucket
		err := datastore.Get(c, key, &b)
		if err == datastore.ErrNoSuchEntity {
			w.WriteHeader(404)
			return
		}
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Errorf(c, "query bucket: %s", err.Error())
			return
		}
		w.Header().Set("Content-Type", "application/json")
		err = json.NewEncoder(w).Encode(&b)
		if err != nil {
			log.Errorf(c, "json encode: %s", err.Error())
		}
	case "PUT":
		var b Bucket
		err := json.NewDecoder(r.Body).Decode(&b)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		if b.ID != id {
			http.Error(w, "Bucket ID must match URL ID", http.StatusBadRequest)
			return
		}
		_, err = datastore.Put(c, key, &b)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Errorf(c, "put bucket: %s", err.Error())
			return
		}
		w.WriteHeader(204)
	case "DELETE":
		err := datastore.RunInTransaction(c, func(c context.Context) error {
			metaKey := datastore.NewKey(c, "Meta", "main", 0, nil)
			var m Meta
			err := datastore.Get(c, metaKey, &m)
			if err != nil {
				return err
			}
			b := m.Buckets[:0]
			for _, bucket := range m.Buckets {
				if bucket == id {
					continue
				}
				b = append(b, bucket)
			}
			m.Buckets = b
			_, err = datastore.Put(c, metaKey, &m)
			if err != nil {
				return err
			}
			return err

		}, &datastore.TransactionOptions{XG: true})
		if err != nil {
			log.Warningf(c, "update meta: %s", err.Error())
		}
		var bk Bucket
		err = datastore.Get(c, key, &bk)
		if err == nil && bk.Images != nil { // delete images
			for _, id := range bk.Images {
				err = blobstore.Delete(c, appengine.BlobKey(id))
				if err != nil {
					log.Warningf(c, "delete image blob '%s': %s", id, err.Error())
				}
				err = datastore.Delete(c, datastore.NewKey(c, "Image", id, 0, nil))
				if err != nil {
					log.Warningf(c, "delete image entry '%s': %s", id, err.Error())
				}
			}
		}
		err = datastore.Delete(c, key)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Errorf(c, "delete bucket: %s", err.Error())
			return
		}
		w.WriteHeader(204)
	default:
		http.Error(w, "Valid methods are GET, DELETE and PUT", http.StatusMethodNotAllowed)
		return
	}
}
Example #18
0
func decodeProperty(c context.Context, k string, v interface{}, e *Entity) error {
	var p datastore.Property
	p.Name = k

	var err error

	switch v.(type) {
	// Try to decode property object
	case map[string]interface{}:
		// Decode custom type
		m := v.(map[string]interface{})

		t, ok := m["type"]
		if !ok {
			t = "primitive"
		}

		if index, ok := m["indexed"]; ok {
			if i, ok := index.(bool); ok {
				p.NoIndex = !i
			}
		}

		switch t {
		case "key":
			key, err := decodeKey(c, m["value"])
			if err != nil {
				return err
			}
			p.Value = key
		case "blobkey":
			v, ok := m["value"].(string)
			if !ok {
				return newDecodePropertyError(k, "blobkey", v)
			}
			p.Value = appengine.BlobKey(v)
		case "blob":
			v, ok := m["value"].(string)
			if !ok {
				return newDecodePropertyError(k, "date", v)
			}
			p.Value, err = base64.URLEncoding.DecodeString(v)
			if err != nil {
				return err
			}
		case "date":
			v, ok := m["value"].(string)
			if !ok {
				return newDecodePropertyError(k, "date", v)
			}
			var dt time.Time
			dt, err = time.Parse(DateTimeFormat, v)
			if err != nil {
				return newDecodePropertyError(k, "date", err)
			}
			p.Value = dt.UTC()
		default:
			if v, ok := m["value"]; ok {
				err = decodeJSONPrimitiveValue(v, &p)
			} else {
				err = fmt.Errorf("aetools: complex property %s without 'value' attribute", k)
			}
		}

	default:
		err = decodeJSONPrimitiveValue(v, &p)
	}

	if err == nil {
		e.Properties = append(e.Properties, p)
	}
	return err
}
Example #19
0
func getImage(res http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	// requesting an image based on blob key
	blobstore.Send(res, appengine.BlobKey(ps.ByName("blobKey")))
}
Example #20
0
func TestMarshalUnmarshalPropertyList(t *testing.T) {
	c, closeFunc := NewContext(t)
	defer closeFunc()

	timeVal := time.Now()
	timeProp := datastore.Property{Name: "Time",
		Value: timeVal, NoIndex: false, Multiple: false}

	byteStringVal := datastore.ByteString{0x23}
	byteStringProp := datastore.Property{Name: "ByteString",
		Value: byteStringVal, NoIndex: false, Multiple: false}

	keyVal := datastore.NewKey(c, "Entity", "stringID", 0, nil)
	keyProp := datastore.Property{Name: "Key",
		Value: keyVal, NoIndex: false, Multiple: false}

	blobKeyVal := appengine.BlobKey("blobkey")
	blobKeyProp := datastore.Property{Name: "BlobKey",
		Value: blobKeyVal, NoIndex: false, Multiple: false}

	geoPointVal := appengine.GeoPoint{1, 2}
	geoPointProp := datastore.Property{Name: "GeoPoint",
		Value: geoPointVal, NoIndex: false, Multiple: false}

	pl := datastore.PropertyList{
		timeProp,
		byteStringProp,
		keyProp,
		blobKeyProp,
		geoPointProp,
	}
	data, err := nds.MarshalPropertyList(pl)
	if err != nil {
		t.Fatal(err)
	}

	testEntity := &struct {
		Time       time.Time
		ByteString datastore.ByteString
		Key        *datastore.Key
		BlobKey    appengine.BlobKey
		GeoPoint   appengine.GeoPoint
	}{}

	pl = datastore.PropertyList{}
	if err := nds.UnmarshalPropertyList(data, &pl); err != nil {
		t.Fatal(err)
	}
	if err := nds.SetValue(reflect.ValueOf(testEntity), pl); err != nil {
		t.Fatal(err)
	}

	if !testEntity.Time.Equal(timeVal) {
		t.Fatal("timeVal not equal")
	}

	if string(testEntity.ByteString) != string(byteStringVal) {
		t.Fatal("byteStringVal not equal")
	}

	if !testEntity.Key.Equal(keyVal) {
		t.Fatal("keyVal not equal")
	}

	if testEntity.BlobKey != blobKeyVal {
		t.Fatal("blobKeyVal not equal")
	}

	if !reflect.DeepEqual(testEntity.GeoPoint, geoPointVal) {
		t.Fatal("geoPointVal not equal")
	}
}
Example #21
0
func handleImages(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	switch r.Method {
	case "POST":
		blobs, vals, err := blobstore.ParseUpload(r)
		if err != nil {
			http.Error(w, "bad request", http.StatusBadRequest)
			log.Errorf(c, "bad request: %s", err.Error())
			return
		}
		bucketID := vals.Get("BucketID")
		if bucketID == "" {
			http.Error(w, "BucketID query parameter is required", http.StatusBadRequest)
			return
		}
		url, err := blobstore.UploadURL(c, "/admin/images", nil)
		if err == nil {
			w.Header().Set("UploadURL", url.String())
		}
		imgs := make([]Image, 0, 20)
		for _, infos := range blobs {
			for _, info := range infos {
				var img Image
				img.Name = info.Filename
				imgUrl, err := aimage.ServingURL(c, info.BlobKey, nil)
				if err != nil {
					log.Errorf(c, "failed to get serving url for blob '%s': %s", info.BlobKey, err.Error())
					http.Error(w, err.Error(), http.StatusInternalServerError)
					return
				}
				img.URL = imgUrl.String()
				img.ID = string(info.BlobKey)
				ir := blobstore.NewReader(c, info.BlobKey)
				cfg, _, err := image.DecodeConfig(ir)
				if err != nil {
					log.Warningf(c, "decode image '%s': %s", info.BlobKey, err.Error())
					err = blobstore.Delete(c, info.BlobKey)
					if err != nil {
						log.Errorf(c, "delete blob '%s': %s", info.BlobKey, err.Error())
					}
					continue
				}
				img.Height = cfg.Height
				img.Width = cfg.Width
				imgs = append(imgs, img)
			}
		}

		// add images to bucket and dtore
		err = datastore.RunInTransaction(c, func(c context.Context) error {
			bucketKey := datastore.NewKey(c, "Bucket", bucketID, 0, nil)
			var b Bucket
			err := datastore.Get(c, bucketKey, &b)
			if err != nil {
				return err
			}
			if b.Images == nil {
				b.Images = make([]string, 0, len(imgs))
			}
			for _, img := range imgs {
				_, err = datastore.Put(c, datastore.NewKey(c, "Image", img.ID, 0, nil), &img)
				if err != nil {
					return err
				}
				b.Images = append(b.Images, img.ID)
			}
			_, err = datastore.Put(c, bucketKey, &b)
			return err
		}, &datastore.TransactionOptions{XG: true})

		if err == datastore.ErrNoSuchEntity {
			for _, img := range imgs {
				err = blobstore.Delete(c, appengine.BlobKey(img.ID))
				if err != nil {
					log.Warningf(c, "delete blob '%s': %s", img.ID, err.Error())
				}
			}
			http.NotFound(w, r)
			return
		}
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Errorf(c, "update datastore: %s", err.Error())
			return
		}

		w.Header().Set("Content-Type", "application/json")
		err = json.NewEncoder(w).Encode(&imgs)
		if err != nil {
			log.Errorf(c, "json encode: %s", err.Error())
		}
	case "GET":
		var imgs []Image
		_, err := datastore.NewQuery("Image").GetAll(c, &imgs)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Errorf(c, "query images: %s", err.Error())
			return
		}
		w.Header().Set("Content-Type", "application/json")
		if imgs == nil {
			imgs = []Image{}
		}
		err = json.NewEncoder(w).Encode(&imgs)
		if err != nil {
			log.Errorf(c, "json encode: %s", err.Error())
		}
	default:
		http.Error(w, "Valid methods are GET and POST", http.StatusMethodNotAllowed)
		return
	}
}
Example #22
0
func handleImagesItem(w http.ResponseWriter, r *http.Request) {
	id := r.URL.Path
	if id == "" {
		w.WriteHeader(404)
		return
	}
	c := appengine.NewContext(r)
	key := datastore.NewKey(c, "Image", id, 0, nil)
	switch r.Method {
	case "GET":
		var img Image
		err := datastore.Get(c, key, &img)
		if err == datastore.ErrNoSuchEntity {
			w.WriteHeader(404)
			return
		}
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Errorf(c, "query image: %s", err.Error())
			return
		}
		w.Header().Set("Content-Type", "application/json")
		err = json.NewEncoder(w).Encode(&img)
		if err != nil {
			log.Errorf(c, "json encode: %s", err.Error())
		}
	case "DELETE":
		err := datastore.Delete(c, key)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Errorf(c, "delete image: %s", err.Error())
			return
		}
		err = blobstore.Delete(c, appengine.BlobKey(id))
		if err != nil {
			log.Warningf(c, "delete image '%s': %s", id, err.Error())
		}
		w.WriteHeader(204)
	case "PUT":
		var img Image
		err := json.NewDecoder(r.Body).Decode(&img)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		if img.ID != id {
			http.Error(w, "Image ID must match URL ID", http.StatusBadRequest)
			return
		}
		_, err = datastore.Put(c, key, &img)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			log.Errorf(c, "put image: %s", err.Error())
			return
		}
		w.WriteHeader(204)
	default:
		http.Error(w, "Valid methods are GET, DELETE and PUT", http.StatusMethodNotAllowed)
		return
	}
}
Example #23
0
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

package backup

import (
	"fmt"
	"reflect"
	"time"

	pb "github.com/sromku/datastore-to-sql/backup/pb"
	"google.golang.org/appengine"
)

var (
	typeOfBlobKey    = reflect.TypeOf(appengine.BlobKey(""))
	typeOfByteSlice  = reflect.TypeOf([]byte(nil))
	typeOfByteString = reflect.TypeOf(ByteString(nil))
	typeOfGeoPoint   = reflect.TypeOf(appengine.GeoPoint{})
	typeOfTime       = reflect.TypeOf(time.Time{})
)

// typeMismatchReason returns a string explaining why the property p could not
// be stored in an entity field of type v.Type().
func typeMismatchReason(p Property, v reflect.Value) string {
	entityType := "empty"
	switch p.Value.(type) {
	case int64:
		entityType = "int"
	case bool:
		entityType = "bool"
func idiomPicture(w http.ResponseWriter, r *http.Request) error {
	// From https://developers.google.com/appengine/docs/go/blobstore/#Complete_Sample_App
	blobstore.Send(w, appengine.BlobKey(r.FormValue("blobKey")))
	return nil
}
Example #25
0
	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/internal"

	basepb "google.golang.org/appengine/internal/base"
	blobpb "google.golang.org/appengine/internal/blobstore"
)

const (
	blobInfoKind      = "__BlobInfo__"
	blobFileIndexKind = "__BlobFileIndex__"
	zeroKey           = appengine.BlobKey("")
)

// BlobInfo is the blob metadata that is stored in the datastore.
// Filename may be empty.
type BlobInfo struct {
	BlobKey      appengine.BlobKey
	ContentType  string    `datastore:"content_type"`
	CreationTime time.Time `datastore:"creation"`
	Filename     string    `datastore:"filename"`
	Size         int64     `datastore:"size"`
	MD5          string    `datastore:"md5_hash"`

	// ObjectName is the Google Cloud Storage name for this blob.
	ObjectName string `datastore:"gs_object_name"`
}
Example #26
0
// ParseUpload parses the synthetic POST request that your app gets from
// App Engine after a user's successful upload of blobs. Given the request,
// ParseUpload returns a map of the blobs received (keyed by HTML form
// element name) and other non-blob POST parameters.
func ParseUpload(req *http.Request) (blobs map[string][]*BlobInfo, other url.Values, err error) {
	_, params, err := mime.ParseMediaType(req.Header.Get("Content-Type"))
	if err != nil {
		return nil, nil, err
	}
	boundary := params["boundary"]
	if boundary == "" {
		return nil, nil, errorf("did not find MIME multipart boundary")
	}

	blobs = make(map[string][]*BlobInfo)
	other = make(url.Values)

	mreader := multipart.NewReader(io.MultiReader(req.Body, strings.NewReader("\r\n\r\n")), boundary)
	for {
		part, perr := mreader.NextPart()
		if perr == io.EOF {
			break
		}
		if perr != nil {
			return nil, nil, errorf("error reading next mime part with boundary %q (len=%d): %v",
				boundary, len(boundary), perr)
		}

		bi := &BlobInfo{}
		ctype, params, err := mime.ParseMediaType(part.Header.Get("Content-Disposition"))
		if err != nil {
			return nil, nil, err
		}
		bi.Filename = params["filename"]
		formKey := params["name"]

		ctype, params, err = mime.ParseMediaType(part.Header.Get("Content-Type"))
		if err != nil {
			return nil, nil, err
		}
		bi.BlobKey = appengine.BlobKey(params["blob-key"])
		if ctype != "message/external-body" || bi.BlobKey == "" {
			if formKey != "" {
				slurp, serr := ioutil.ReadAll(part)
				if serr != nil {
					return nil, nil, errorf("error reading %q MIME part", formKey)
				}
				other[formKey] = append(other[formKey], string(slurp))
			}
			continue
		}

		// App Engine sends a MIME header as the body of each MIME part.
		tp := textproto.NewReader(bufio.NewReader(part))
		header, mimeerr := tp.ReadMIMEHeader()
		if mimeerr != nil {
			return nil, nil, mimeerr
		}
		bi.Size, err = strconv.ParseInt(header.Get("Content-Length"), 10, 64)
		if err != nil {
			return nil, nil, err
		}
		bi.ContentType = header.Get("Content-Type")

		// Parse the time from the MIME header like:
		// X-AppEngine-Upload-Creation: 2011-03-15 21:38:34.712136
		createDate := header.Get("X-AppEngine-Upload-Creation")
		if createDate == "" {
			return nil, nil, errorf("expected to find an X-AppEngine-Upload-Creation header")
		}
		bi.CreationTime, err = time.Parse("2006-01-02 15:04:05.000000", createDate)
		if err != nil {
			return nil, nil, errorf("error parsing X-AppEngine-Upload-Creation: %s", err)
		}

		if hdr := header.Get("Content-MD5"); hdr != "" {
			md5, err := base64.URLEncoding.DecodeString(hdr)
			if err != nil {
				return nil, nil, errorf("bad Content-MD5 %q: %v", hdr, err)
			}
			bi.MD5 = string(md5)
		}

		// If the GCS object name was provided, record it.
		bi.ObjectName = header.Get("X-AppEngine-Cloud-Storage-Object")

		blobs[formKey] = append(blobs[formKey], bi)
	}
	return
}