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
Gisle Aune
7 years ago
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