Browse Source

graph2: Added File type and queries.

1.0
Gisle Aune 6 years ago
parent
commit
bac57bc378
  1. 4
      graph2/gqlgen.yml
  2. 4
      graph2/graph.go
  3. 34
      graph2/queries/file.go
  4. 7
      graph2/schema/root.gql
  5. 52
      graph2/schema/types/File.gql
  6. 16
      graph2/types/file.go
  7. 16
      models/file.go
  8. 81
      models/files/db.go
  9. 11
      models/files/find.go
  10. 36
      models/files/list.go

4
graph2/gqlgen.yml

@ -34,5 +34,9 @@ models:
fields: fields:
fictionalDate: fictionalDate:
resolver: true resolver: true
File:
model: git.aiterp.net/rpdata/api/models.File
FilesFilter:
model: git.aiterp.net/rpdata/api/models/files.Filter
Date: Date:
model: git.aiterp.net/rpdata/api/models/scalars.Date model: git.aiterp.net/rpdata/api/models/scalars.Date

4
graph2/graph.go

@ -29,3 +29,7 @@ func (r *rootResolver) Log() LogResolver {
func (r *rootResolver) Chapter() ChapterResolver { func (r *rootResolver) Chapter() ChapterResolver {
return &types.ChapterResolver return &types.ChapterResolver
} }
func (r *rootResolver) File() FileResolver {
return &types.FileResolver
}

34
graph2/queries/file.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

7
graph2/schema/root.gql

@ -37,6 +37,13 @@ type Query {
# Find all distinct tags used in stories # Find all distinct tags used in stories
tags: [Tag!]! tags: [Tag!]!
# Find file by ID
file(id: String!): File!
# Find files
files(filter: FilesFilter): [File!]!
} }
# A Date represents a RFC3339 encoded date with up to millisecond precision. # A Date represents a RFC3339 encoded date with up to millisecond precision.

52
graph2/schema/types/File.gql

@ -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
}

16
graph2/types/file.go

@ -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

16
models/file.go

@ -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"`
}

81
models/files/db.go

@ -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,
}

11
models/files/find.go

@ -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})
}

36
models/files/list.go

@ -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)
}
Loading…
Cancel
Save