Browse Source
			
			
			Added File model (still missing edit/remove), fixed uploading to space always failing, added /upload endpoint to rpdata-grapihql server
			
			
				1.0
			
			
		
		Added File model (still missing edit/remove), fixed uploading to space always failing, added /upload endpoint to rpdata-grapihql server
	
		
	
			
			
				1.0
			
			
		
				 3 changed files with 185 additions and 1 deletions
			
			
		| @ -0,0 +1,138 @@ | |||
| package file | |||
| 
 | |||
| import ( | |||
| 	"context" | |||
| 	"crypto/rand" | |||
| 	"encoding/binary" | |||
| 	"io" | |||
| 	"strconv" | |||
| 	"time" | |||
| 
 | |||
| 	"git.aiterp.net/rpdata/api/internal/store" | |||
| 	"github.com/globalsign/mgo" | |||
| 	"github.com/globalsign/mgo/bson" | |||
| ) | |||
| 
 | |||
| var fileCollection *mgo.Collection | |||
| 
 | |||
| // A File is a record of a file stored in the Space.
 | |||
| type File struct { | |||
| 	ID       string    `bson:"_id" json:"id"` | |||
| 	Time     time.Time `bson:"time" json:"time"` | |||
| 	Public   bool      `bson:"public" json:"public"` | |||
| 	Name     string    `bson:"name" json:"name"` | |||
| 	MimeType string    `bson:"mimeType" json:"mimeType"` | |||
| 	Size     int64     `bson:"size" json:"size"` | |||
| 	Author   string    `bson:"author" json:"author"` | |||
| 	URL      string    `bson:"url,omitempty" json:"url,omitempty"` | |||
| } | |||
| 
 | |||
| // Upload adds a file to the space.
 | |||
| func Upload(ctx context.Context, name, mimeType, author string, size int64, input io.Reader) (File, error) { | |||
| 	if name == "" { | |||
| 		date := time.Now().UTC().Format("Jan 02 2006 15:04:05 MST") | |||
| 		name = "Unnamed file (" + date + ")" | |||
| 	} | |||
| 
 | |||
| 	if mimeType == "" { | |||
| 		mimeType = "binary/octet-stream" | |||
| 	} | |||
| 
 | |||
| 	id := makeFileID() | |||
| 
 | |||
| 	path, err := store.UploadFile(ctx, "files", id, mimeType, input, size) | |||
| 	if err != nil { | |||
| 		return File{}, err | |||
| 	} | |||
| 
 | |||
| 	file := File{ | |||
| 		ID:       id, | |||
| 		Time:     time.Now(), | |||
| 		Public:   false, | |||
| 		Author:   author, | |||
| 		Name:     name, | |||
| 		MimeType: mimeType, | |||
| 		Size:     size, | |||
| 		URL:      store.URLFromPath(path), | |||
| 	} | |||
| 
 | |||
| 	err = fileCollection.Insert(file) | |||
| 	if err != nil { | |||
| 		return File{}, err | |||
| 	} | |||
| 
 | |||
| 	return file, nil | |||
| } | |||
| 
 | |||
| // FindID finds a file by ID
 | |||
| func FindID(id string) (File, error) { | |||
| 	file := File{} | |||
| 
 | |||
| 	err := fileCollection.FindId(id).One(&file) | |||
| 	if err != nil { | |||
| 		return File{}, err | |||
| 	} | |||
| 
 | |||
| 	return file, nil | |||
| } | |||
| 
 | |||
| // ListFiles lists files according to the standard lookup. By default it's just the author's own files,
 | |||
| // but if `public` is true it will alos include files made public by other authors. If `mimeTypes` contains
 | |||
| // any, it will limit the results to that.
 | |||
| func ListFiles(author string, public bool, mimeTypes []string) ([]File, error) { | |||
| 	query := bson.M{} | |||
| 
 | |||
| 	if public { | |||
| 		query["$or"] = []bson.M{ | |||
| 			bson.M{"author": author}, | |||
| 			bson.M{"public": true}, | |||
| 		} | |||
| 	} else { | |||
| 		query["author"] = author | |||
| 	} | |||
| 
 | |||
| 	if len(mimeTypes) > 0 { | |||
| 		query["mimeTypes"] = bson.M{"$in": mimeTypes} | |||
| 	} | |||
| 
 | |||
| 	return listFiles(query) | |||
| } | |||
| 
 | |||
| func listFiles(query interface{}) ([]File, error) { | |||
| 	list := make([]File, 0, 32) | |||
| 
 | |||
| 	err := fileCollection.Find(query).All(&list) | |||
| 	if err != nil { | |||
| 		return nil, err | |||
| 	} | |||
| 
 | |||
| 	return list, nil | |||
| } | |||
| 
 | |||
| // makeFileID makes a random file ID that's 32 characters long
 | |||
| func makeFileID() string { | |||
| 	result := "F" + strconv.FormatInt(time.Now().UnixNano(), 36) | |||
| 	offset := 0 | |||
| 	data := make([]byte, 32) | |||
| 
 | |||
| 	rand.Read(data) | |||
| 	for len(result) < 32 { | |||
| 		result += strconv.FormatUint(binary.LittleEndian.Uint64(data[offset:]), 36) | |||
| 		offset += 8 | |||
| 
 | |||
| 		if offset >= 32 { | |||
| 			rand.Read(data) | |||
| 			offset = 0 | |||
| 		} | |||
| 	} | |||
| 
 | |||
| 	return result[:32] | |||
| } | |||
| 
 | |||
| func init() { | |||
| 	store.HandleInit(func(db *mgo.Database) { | |||
| 		fileCollection = db.C("file.headers") | |||
| 
 | |||
| 		fileCollection.EnsureIndexKey("author") | |||
| 	}) | |||
| } | |||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue