Gisle Aune
6 years ago
10 changed files with 261 additions and 0 deletions
-
4graph2/gqlgen.yml
-
4graph2/graph.go
-
34graph2/queries/file.go
-
7graph2/schema/root.gql
-
52graph2/schema/types/File.gql
-
16graph2/types/file.go
-
16models/file.go
-
81models/files/db.go
-
11models/files/find.go
-
36models/files/list.go
@ -0,0 +1,34 @@ |
|||
package queries |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"git.aiterp.net/rpdata/api/internal/auth" |
|||
"git.aiterp.net/rpdata/api/models" |
|||
"git.aiterp.net/rpdata/api/models/files" |
|||
) |
|||
|
|||
func (r *resolver) File(ctx context.Context, id string) (models.File, error) { |
|||
return files.FindID(id) |
|||
} |
|||
|
|||
func (r *resolver) Files(ctx context.Context, filter *files.Filter) ([]models.File, error) { |
|||
token := auth.TokenFromContext(ctx) |
|||
|
|||
if filter == nil { |
|||
filter = &files.Filter{} |
|||
} |
|||
|
|||
// Only allow users to view public files that are not their own.
|
|||
if token != nil { |
|||
if filter.Public == nil || *filter.Public == false { |
|||
filter.Author = &token.UserID |
|||
} |
|||
} else { |
|||
filter.Public = &trueValue |
|||
} |
|||
|
|||
return files.List(filter) |
|||
} |
|||
|
|||
var trueValue = true |
@ -0,0 +1,52 @@ |
|||
# A File contains information about a file and where to download it. |
|||
type File { |
|||
# The file's unique ID |
|||
id: String! |
|||
|
|||
# The kind of file. Most will be "upload", but some that are ported from the wiki will have other values for this. |
|||
kind: String! |
|||
|
|||
# The time of uploading |
|||
time: Date! |
|||
|
|||
# Whether the file is publicly listable. Someone with knowledge of the ID |
|||
# will still be able to view it, however. |
|||
public: Boolean! |
|||
|
|||
# The file's name |
|||
name: String! |
|||
|
|||
# The MIME type of the file |
|||
mimeType: String! |
|||
|
|||
# The file's size in bytes |
|||
size: Int! |
|||
|
|||
# The uploader |
|||
author: String! |
|||
|
|||
# The URL where the file is hosted |
|||
url: String |
|||
} |
|||
|
|||
# Filter for the files quiery. |
|||
input FilesFilter { |
|||
# If set, this will limit the results to either public or private files. |
|||
public: Boolean |
|||
|
|||
# Limit the MIME types of the files. |
|||
mimeType: [String!] |
|||
} |
|||
|
|||
# Input for editFile mutation |
|||
input EditFileInput { |
|||
# The file's unique ID |
|||
id: String! |
|||
|
|||
# Whether the file is publicly listable. Someone with knowledge of the ID |
|||
# will still be able to view it, however. |
|||
public: Boolean |
|||
|
|||
# The file's name |
|||
name: String |
|||
} |
@ -0,0 +1,16 @@ |
|||
package types |
|||
|
|||
import ( |
|||
"context" |
|||
|
|||
"git.aiterp.net/rpdata/api/models" |
|||
) |
|||
|
|||
type fileResolver struct{} |
|||
|
|||
func (r *fileResolver) Size(ctx context.Context, file *models.File) (int, error) { |
|||
return int(file.Size), nil |
|||
} |
|||
|
|||
// FileResolver is a resolver
|
|||
var FileResolver fileResolver |
@ -0,0 +1,16 @@ |
|||
package models |
|||
|
|||
import "time" |
|||
|
|||
// 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"` |
|||
Kind string `bson:"kind" json:"kind"` |
|||
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"` |
|||
} |
@ -0,0 +1,81 @@ |
|||
package files |
|||
|
|||
import ( |
|||
"crypto/rand" |
|||
"encoding/binary" |
|||
"strconv" |
|||
"time" |
|||
|
|||
"git.aiterp.net/rpdata/api/internal/store" |
|||
"git.aiterp.net/rpdata/api/models" |
|||
"github.com/globalsign/mgo" |
|||
) |
|||
|
|||
var collection *mgo.Collection |
|||
|
|||
func find(query interface{}) (models.File, error) { |
|||
file := models.File{} |
|||
|
|||
err := collection.Find(query).One(&file) |
|||
if err != nil { |
|||
return models.File{}, err |
|||
} |
|||
|
|||
return file, nil |
|||
} |
|||
|
|||
func list(query interface{}) ([]models.File, error) { |
|||
list := make([]models.File, 0, 32) |
|||
|
|||
err := collection.Find(query).Sort("-time").All(&list) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
return list, nil |
|||
} |
|||
|
|||
// makeID makes a random file ID that's 32 characters long
|
|||
func makeID() 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) { |
|||
collection = db.C("file.headers") |
|||
|
|||
collection.EnsureIndexKey("author") |
|||
collection.EnsureIndexKey("public") |
|||
collection.EnsureIndexKey("kind", "name", "author") |
|||
collection.EnsureIndexKey("author", "public") |
|||
collection.EnsureIndexKey("kind") |
|||
}) |
|||
} |
|||
|
|||
var allowdMimeTypes = map[string]bool{ |
|||
"": false, |
|||
"image/jpeg": true, |
|||
"image/png": true, |
|||
"image/gif": true, |
|||
"text/plain": true, |
|||
"application/json": true, |
|||
"application/pdf": false, |
|||
"binary/octet-stream": false, |
|||
"video/mp4": false, |
|||
"audio/mp3": false, |
|||
} |
@ -0,0 +1,11 @@ |
|||
package files |
|||
|
|||
import ( |
|||
"git.aiterp.net/rpdata/api/models" |
|||
"github.com/globalsign/mgo/bson" |
|||
) |
|||
|
|||
// FindID finds a file by ID
|
|||
func FindID(id string) (models.File, error) { |
|||
return find(bson.M{"_id": id}) |
|||
} |
@ -0,0 +1,36 @@ |
|||
package files |
|||
|
|||
import ( |
|||
"git.aiterp.net/rpdata/api/models" |
|||
"github.com/globalsign/mgo/bson" |
|||
) |
|||
|
|||
// Filter for files.List
|
|||
type Filter struct { |
|||
Author *string |
|||
Public *bool |
|||
MimeType []string |
|||
} |
|||
|
|||
// List 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. If `author` is empty, it will only list public files
|
|||
func List(filter *Filter) ([]models.File, error) { |
|||
query := bson.M{} |
|||
|
|||
if filter != nil { |
|||
if filter.Author != nil { |
|||
query["author"] = *filter.Author |
|||
} |
|||
|
|||
if filter.Public != nil { |
|||
query["public"] = *filter.Public |
|||
} |
|||
|
|||
if len(filter.MimeType) > 0 { |
|||
query["mimeTypes"] = bson.M{"$in": filter.MimeType} |
|||
} |
|||
} |
|||
|
|||
return list(query) |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue