MediaItem Upload Support
This commit is contained in:
parent
a5692babb8
commit
548a50278a
@ -73,7 +73,6 @@ type ComplexityRoot struct {
|
||||
RefreshKey func(childComplexity int) int
|
||||
Type func(childComplexity int) int
|
||||
UpdatedAt func(childComplexity int) int
|
||||
User func(childComplexity int) int
|
||||
UserID func(childComplexity int) int
|
||||
}
|
||||
|
||||
@ -94,7 +93,6 @@ type ComplexityRoot struct {
|
||||
OrigName func(childComplexity int) int
|
||||
Tags func(childComplexity int) int
|
||||
UpdatedAt func(childComplexity int) int
|
||||
User func(childComplexity int) int
|
||||
UserID func(childComplexity int) int
|
||||
}
|
||||
|
||||
@ -105,7 +103,6 @@ type ComplexityRoot struct {
|
||||
|
||||
Mutation struct {
|
||||
CreateAlbum func(childComplexity int, input model.NewAlbum) int
|
||||
CreateDevice func(childComplexity int, input model.NewDevice) int
|
||||
CreateMediaItem func(childComplexity int, input model.NewMediaItem) int
|
||||
CreateTag func(childComplexity int, input model.NewTag) int
|
||||
CreateUser func(childComplexity int, input model.NewUser) int
|
||||
@ -146,16 +143,18 @@ type ComplexityRoot struct {
|
||||
}
|
||||
|
||||
User struct {
|
||||
AuthType func(childComplexity int) int
|
||||
CreatedAt func(childComplexity int) int
|
||||
Email func(childComplexity int) int
|
||||
FirstName func(childComplexity int) int
|
||||
ID func(childComplexity int) int
|
||||
LastName func(childComplexity int) int
|
||||
Password func(childComplexity int) int
|
||||
Role func(childComplexity int) int
|
||||
UpdatedAt func(childComplexity int) int
|
||||
Username func(childComplexity int) int
|
||||
AuthType func(childComplexity int) int
|
||||
CreatedAt func(childComplexity int) int
|
||||
Devices func(childComplexity int) int
|
||||
Email func(childComplexity int) int
|
||||
FirstName func(childComplexity int) int
|
||||
ID func(childComplexity int) int
|
||||
LastName func(childComplexity int) int
|
||||
MediaItems func(childComplexity int) int
|
||||
Password func(childComplexity int) int
|
||||
Role func(childComplexity int) int
|
||||
UpdatedAt func(childComplexity int) int
|
||||
Username func(childComplexity int) int
|
||||
}
|
||||
|
||||
UserResponse struct {
|
||||
@ -166,7 +165,6 @@ type ComplexityRoot struct {
|
||||
|
||||
type MutationResolver interface {
|
||||
CreateMediaItem(ctx context.Context, input model.NewMediaItem) (*model.MediaItem, error)
|
||||
CreateDevice(ctx context.Context, input model.NewDevice) (*model.Device, error)
|
||||
CreateAlbum(ctx context.Context, input model.NewAlbum) (*model.Album, error)
|
||||
CreateTag(ctx context.Context, input model.NewTag) (*model.Tag, error)
|
||||
CreateUser(ctx context.Context, input model.NewUser) (*model.User, error)
|
||||
@ -307,13 +305,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.Device.UpdatedAt(childComplexity), true
|
||||
|
||||
case "Device.user":
|
||||
if e.complexity.Device.User == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Device.User(childComplexity), true
|
||||
|
||||
case "Device.userID":
|
||||
if e.complexity.Device.UserID == nil {
|
||||
break
|
||||
@ -412,13 +403,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.MediaItem.UpdatedAt(childComplexity), true
|
||||
|
||||
case "MediaItem.user":
|
||||
if e.complexity.MediaItem.User == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.MediaItem.User(childComplexity), true
|
||||
|
||||
case "MediaItem.userID":
|
||||
if e.complexity.MediaItem.UserID == nil {
|
||||
break
|
||||
@ -452,18 +436,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.Mutation.CreateAlbum(childComplexity, args["input"].(model.NewAlbum)), true
|
||||
|
||||
case "Mutation.createDevice":
|
||||
if e.complexity.Mutation.CreateDevice == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Mutation_createDevice_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.CreateDevice(childComplexity, args["input"].(model.NewDevice)), true
|
||||
|
||||
case "Mutation.createMediaItem":
|
||||
if e.complexity.Mutation.CreateMediaItem == nil {
|
||||
break
|
||||
@ -723,6 +695,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.User.CreatedAt(childComplexity), true
|
||||
|
||||
case "User.devices":
|
||||
if e.complexity.User.Devices == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.User.Devices(childComplexity), true
|
||||
|
||||
case "User.email":
|
||||
if e.complexity.User.Email == nil {
|
||||
break
|
||||
@ -751,6 +730,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.User.LastName(childComplexity), true
|
||||
|
||||
case "User.mediaItems":
|
||||
if e.complexity.User.MediaItems == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.User.MediaItems(childComplexity), true
|
||||
|
||||
case "User.password":
|
||||
if e.complexity.User.Password == nil {
|
||||
break
|
||||
@ -998,6 +984,21 @@ input AuthTypeFilter {
|
||||
# -------------------- Object Definitions --------------------
|
||||
# ------------------------------------------------------------
|
||||
|
||||
type User {
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
createdAt: Time
|
||||
updatedAt: Time
|
||||
email: String! @meta(gorm: "not null;unique")
|
||||
username: String! @meta(gorm: "not null;unique")
|
||||
firstName: String
|
||||
lastName: String
|
||||
role: Role! @meta(gorm: "default:User;not null")
|
||||
authType: AuthType! @meta(gorm: "default:Local;not null")
|
||||
password: String @isPrivate
|
||||
devices: [Device!] @meta(gorm: "foreignKey:UserID")
|
||||
mediaItems: [MediaItem!] @meta(gorm: "foreignKey:UserID")
|
||||
}
|
||||
|
||||
type Device {
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
createdAt: Time
|
||||
@ -1005,21 +1006,7 @@ type Device {
|
||||
name: String! @meta(gorm: "not null")
|
||||
type: DeviceType! @meta(gorm: "default:Unknown;not null")
|
||||
userID: ID! @meta(gorm: "not null")
|
||||
user: User! @meta(gorm: "foreignKey:ID;references:UserID;not null")
|
||||
refreshKey: String @deprecated(reason: "Private Field") # @isPrivate
|
||||
}
|
||||
|
||||
type User {
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
createdAt: Time
|
||||
updatedAt: Time
|
||||
email: String! @meta(gorm: "not null;unique")
|
||||
username: String! @meta(gorm: "not null;unique")
|
||||
firstName: String
|
||||
lastName: String
|
||||
role: Role! @meta(gorm: "default:User;not null")
|
||||
authType: AuthType! @meta(gorm: "default:Local;not null")
|
||||
password: String @deprecated(reason: "Private Field") #@isPrivate
|
||||
refreshKey: String @isPrivate
|
||||
}
|
||||
|
||||
type MediaItem {
|
||||
@ -1035,21 +1022,20 @@ type MediaItem {
|
||||
tags: [Tag] @meta(gorm: "many2many:media_tags")
|
||||
albums: [Album] @meta(gorm: "many2many:media_albums")
|
||||
userID: ID! @meta(gorm: "not null")
|
||||
user: User! @meta(gorm: "foreignKey:ID;references:UserID;not null")
|
||||
}
|
||||
|
||||
type Tag {
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
createdAt: Time
|
||||
updatedAt: Time
|
||||
name: String! @meta(gorm: "unique;not null")
|
||||
name: String! @meta(gorm: "unique;not null")
|
||||
}
|
||||
|
||||
type Album {
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
createdAt: Time
|
||||
updatedAt: Time
|
||||
name: String! @meta(gorm: "unique;not null")
|
||||
name: String! @meta(gorm: "unique;not null")
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------
|
||||
@ -1131,10 +1117,6 @@ input NewUser {
|
||||
password: String
|
||||
}
|
||||
|
||||
input NewDevice {
|
||||
name: String!
|
||||
}
|
||||
|
||||
input NewMediaItem {
|
||||
file: Upload!
|
||||
tags: [ID!]
|
||||
@ -1236,7 +1218,6 @@ type Query {
|
||||
|
||||
type Mutation {
|
||||
createMediaItem(input: NewMediaItem!): MediaItem! @hasMinRole(role: User)
|
||||
createDevice(input: NewDevice!): Device! @hasMinRole(role: User)
|
||||
createAlbum(input: NewAlbum!): Album! @hasMinRole(role: User)
|
||||
createTag(input: NewTag!): Tag! @hasMinRole(role: User)
|
||||
createUser(input: NewUser!): User! @hasMinRole(role: Admin)
|
||||
@ -1294,21 +1275,6 @@ func (ec *executionContext) field_Mutation_createAlbum_args(ctx context.Context,
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_createDevice_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
var arg0 model.NewDevice
|
||||
if tmp, ok := rawArgs["input"]; ok {
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
|
||||
arg0, err = ec.unmarshalNNewDevice2reichardᚗioᚋimaginiᚋgraphᚋmodelᚐNewDevice(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["input"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_createMediaItem_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
@ -2328,7 +2294,7 @@ func (ec *executionContext) _Device_userID(ctx context.Context, field graphql.Co
|
||||
return ec.marshalNID2string(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Device_user(ctx context.Context, field graphql.CollectedField, obj *model.Device) (ret graphql.Marshaler) {
|
||||
func (ec *executionContext) _Device_refreshKey(ctx context.Context, field graphql.CollectedField, obj *model.Device) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
@ -2347,17 +2313,13 @@ func (ec *executionContext) _Device_user(ctx context.Context, field graphql.Coll
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.User, nil
|
||||
return obj.RefreshKey, nil
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
gorm, err := ec.unmarshalOString2ᚖstring(ctx, "foreignKey:ID;references:UserID;not null")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if ec.directives.IsPrivate == nil {
|
||||
return nil, errors.New("directive isPrivate is not implemented")
|
||||
}
|
||||
if ec.directives.Meta == nil {
|
||||
return nil, errors.New("directive meta is not implemented")
|
||||
}
|
||||
return ec.directives.Meta(ctx, obj, directive0, gorm)
|
||||
return ec.directives.IsPrivate(ctx, obj, directive0)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
@ -2367,45 +2329,10 @@ func (ec *executionContext) _Device_user(ctx context.Context, field graphql.Coll
|
||||
if tmp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if data, ok := tmp.(*model.User); ok {
|
||||
if data, ok := tmp.(*string); ok {
|
||||
return data, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be *reichard.io/imagini/graph/model.User`, tmp)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*model.User)
|
||||
fc.Result = res
|
||||
return ec.marshalNUser2ᚖreichardᚗioᚋimaginiᚋgraphᚋmodelᚐUser(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Device_refreshKey(ctx context.Context, field graphql.CollectedField, obj *model.Device) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
fc := &graphql.FieldContext{
|
||||
Object: "Device",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.RefreshKey, nil
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be *string`, tmp)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
@ -3053,65 +2980,6 @@ func (ec *executionContext) _MediaItem_userID(ctx context.Context, field graphql
|
||||
return ec.marshalNID2string(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _MediaItem_user(ctx context.Context, field graphql.CollectedField, obj *model.MediaItem) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
fc := &graphql.FieldContext{
|
||||
Object: "MediaItem",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.User, nil
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
gorm, err := ec.unmarshalOString2ᚖstring(ctx, "foreignKey:ID;references:UserID;not null")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ec.directives.Meta == nil {
|
||||
return nil, errors.New("directive meta is not implemented")
|
||||
}
|
||||
return ec.directives.Meta(ctx, obj, directive0, gorm)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
if tmp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if data, ok := tmp.(*model.User); ok {
|
||||
return data, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be *reichard.io/imagini/graph/model.User`, tmp)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*model.User)
|
||||
fc.Result = res
|
||||
return ec.marshalNUser2ᚖreichardᚗioᚋimaginiᚋgraphᚋmodelᚐUser(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _MediaItemResponse_data(ctx context.Context, field graphql.CollectedField, obj *model.MediaItemResponse) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@ -3245,72 +3113,6 @@ func (ec *executionContext) _Mutation_createMediaItem(ctx context.Context, field
|
||||
return ec.marshalNMediaItem2ᚖreichardᚗioᚋimaginiᚋgraphᚋmodelᚐMediaItem(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_createDevice(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
fc := &graphql.FieldContext{
|
||||
Object: "Mutation",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: true,
|
||||
IsResolver: true,
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
rawArgs := field.ArgumentMap(ec.Variables)
|
||||
args, err := ec.field_Mutation_createDevice_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
fc.Args = args
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().CreateDevice(rctx, args["input"].(model.NewDevice))
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
role, err := ec.unmarshalNRole2reichardᚗioᚋimaginiᚋgraphᚋmodelᚐRole(ctx, "User")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ec.directives.HasMinRole == nil {
|
||||
return nil, errors.New("directive hasMinRole is not implemented")
|
||||
}
|
||||
return ec.directives.HasMinRole(ctx, nil, directive0, role)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
if tmp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if data, ok := tmp.(*model.Device); ok {
|
||||
return data, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be *reichard.io/imagini/graph/model.Device`, tmp)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*model.Device)
|
||||
fc.Result = res
|
||||
return ec.marshalNDevice2ᚖreichardᚗioᚋimaginiᚋgraphᚋmodelᚐDevice(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_createAlbum(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@ -5194,8 +4996,28 @@ func (ec *executionContext) _User_password(ctx context.Context, field graphql.Co
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Password, nil
|
||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Password, nil
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.IsPrivate == nil {
|
||||
return nil, errors.New("directive isPrivate is not implemented")
|
||||
}
|
||||
return ec.directives.IsPrivate(ctx, obj, directive0)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
if tmp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if data, ok := tmp.(*string); ok {
|
||||
return data, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be *string`, tmp)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
@ -5209,6 +5031,118 @@ func (ec *executionContext) _User_password(ctx context.Context, field graphql.Co
|
||||
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _User_devices(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
fc := &graphql.FieldContext{
|
||||
Object: "User",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Devices, nil
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
gorm, err := ec.unmarshalOString2ᚖstring(ctx, "foreignKey:UserID")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ec.directives.Meta == nil {
|
||||
return nil, errors.New("directive meta is not implemented")
|
||||
}
|
||||
return ec.directives.Meta(ctx, obj, directive0, gorm)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
if tmp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if data, ok := tmp.([]*model.Device); ok {
|
||||
return data, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be []*reichard.io/imagini/graph/model.Device`, tmp)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.([]*model.Device)
|
||||
fc.Result = res
|
||||
return ec.marshalODevice2ᚕᚖreichardᚗioᚋimaginiᚋgraphᚋmodelᚐDeviceᚄ(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _User_mediaItems(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
fc := &graphql.FieldContext{
|
||||
Object: "User",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.MediaItems, nil
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
gorm, err := ec.unmarshalOString2ᚖstring(ctx, "foreignKey:UserID")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ec.directives.Meta == nil {
|
||||
return nil, errors.New("directive meta is not implemented")
|
||||
}
|
||||
return ec.directives.Meta(ctx, obj, directive0, gorm)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
if tmp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if data, ok := tmp.([]*model.MediaItem); ok {
|
||||
return data, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be []*reichard.io/imagini/graph/model.MediaItem`, tmp)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.([]*model.MediaItem)
|
||||
fc.Result = res
|
||||
return ec.marshalOMediaItem2ᚕᚖreichardᚗioᚋimaginiᚋgraphᚋmodelᚐMediaItemᚄ(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _UserResponse_data(ctx context.Context, field graphql.CollectedField, obj *model.UserResponse) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@ -6931,26 +6865,6 @@ func (ec *executionContext) unmarshalInputNewAlbum(ctx context.Context, obj inte
|
||||
return it, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalInputNewDevice(ctx context.Context, obj interface{}) (model.NewDevice, error) {
|
||||
var it model.NewDevice
|
||||
var asMap = obj.(map[string]interface{})
|
||||
|
||||
for k, v := range asMap {
|
||||
switch k {
|
||||
case "name":
|
||||
var err error
|
||||
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name"))
|
||||
it.Name, err = ec.unmarshalNString2string(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return it, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalInputNewMediaItem(ctx context.Context, obj interface{}) (model.NewMediaItem, error) {
|
||||
var it model.NewMediaItem
|
||||
var asMap = obj.(map[string]interface{})
|
||||
@ -7610,11 +7524,6 @@ func (ec *executionContext) _Device(ctx context.Context, sel ast.SelectionSet, o
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "user":
|
||||
out.Values[i] = ec._Device_user(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "refreshKey":
|
||||
out.Values[i] = ec._Device_refreshKey(ctx, field, obj)
|
||||
default:
|
||||
@ -7707,11 +7616,6 @@ func (ec *executionContext) _MediaItem(ctx context.Context, sel ast.SelectionSet
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "user":
|
||||
out.Values[i] = ec._MediaItem_user(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
@ -7772,11 +7676,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "createDevice":
|
||||
out.Values[i] = ec._Mutation_createDevice(ctx, field)
|
||||
if out.Values[i] == graphql.Null {
|
||||
invalids++
|
||||
}
|
||||
case "createAlbum":
|
||||
out.Values[i] = ec._Mutation_createAlbum(ctx, field)
|
||||
if out.Values[i] == graphql.Null {
|
||||
@ -8163,6 +8062,10 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj
|
||||
}
|
||||
case "password":
|
||||
out.Values[i] = ec._User_password(ctx, field, obj)
|
||||
case "devices":
|
||||
out.Values[i] = ec._User_devices(ctx, field, obj)
|
||||
case "mediaItems":
|
||||
out.Values[i] = ec._User_mediaItems(ctx, field, obj)
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
@ -8641,11 +8544,6 @@ func (ec *executionContext) unmarshalNNewAlbum2reichardᚗioᚋimaginiᚋgraph
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNNewDevice2reichardᚗioᚋimaginiᚋgraphᚋmodelᚐNewDevice(ctx context.Context, v interface{}) (model.NewDevice, error) {
|
||||
res, err := ec.unmarshalInputNewDevice(ctx, v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNNewMediaItem2reichardᚗioᚋimaginiᚋgraphᚋmodelᚐNewMediaItem(ctx context.Context, v interface{}) (model.NewMediaItem, error) {
|
||||
res, err := ec.unmarshalInputNewMediaItem(ctx, v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
@ -9211,6 +9109,46 @@ func (ec *executionContext) marshalODevice2ᚕᚖreichardᚗioᚋimaginiᚋgraph
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalODevice2ᚕᚖreichardᚗioᚋimaginiᚋgraphᚋmodelᚐDeviceᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Device) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ret := make(graphql.Array, len(v))
|
||||
var wg sync.WaitGroup
|
||||
isLen1 := len(v) == 1
|
||||
if !isLen1 {
|
||||
wg.Add(len(v))
|
||||
}
|
||||
for i := range v {
|
||||
i := i
|
||||
fc := &graphql.FieldContext{
|
||||
Index: &i,
|
||||
Result: &v[i],
|
||||
}
|
||||
ctx := graphql.WithFieldContext(ctx, fc)
|
||||
f := func(i int) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = nil
|
||||
}
|
||||
}()
|
||||
if !isLen1 {
|
||||
defer wg.Done()
|
||||
}
|
||||
ret[i] = ec.marshalNDevice2ᚖreichardᚗioᚋimaginiᚋgraphᚋmodelᚐDevice(ctx, sel, v[i])
|
||||
}
|
||||
if isLen1 {
|
||||
f(i)
|
||||
} else {
|
||||
go f(i)
|
||||
}
|
||||
|
||||
}
|
||||
wg.Wait()
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalODevice2ᚖreichardᚗioᚋimaginiᚋgraphᚋmodelᚐDevice(ctx context.Context, sel ast.SelectionSet, v *model.Device) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
@ -9523,6 +9461,46 @@ func (ec *executionContext) marshalOMediaItem2ᚕᚖreichardᚗioᚋimaginiᚋgr
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalOMediaItem2ᚕᚖreichardᚗioᚋimaginiᚋgraphᚋmodelᚐMediaItemᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.MediaItem) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ret := make(graphql.Array, len(v))
|
||||
var wg sync.WaitGroup
|
||||
isLen1 := len(v) == 1
|
||||
if !isLen1 {
|
||||
wg.Add(len(v))
|
||||
}
|
||||
for i := range v {
|
||||
i := i
|
||||
fc := &graphql.FieldContext{
|
||||
Index: &i,
|
||||
Result: &v[i],
|
||||
}
|
||||
ctx := graphql.WithFieldContext(ctx, fc)
|
||||
f := func(i int) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = nil
|
||||
}
|
||||
}()
|
||||
if !isLen1 {
|
||||
defer wg.Done()
|
||||
}
|
||||
ret[i] = ec.marshalNMediaItem2ᚖreichardᚗioᚋimaginiᚋgraphᚋmodelᚐMediaItem(ctx, sel, v[i])
|
||||
}
|
||||
if isLen1 {
|
||||
f(i)
|
||||
} else {
|
||||
go f(i)
|
||||
}
|
||||
|
||||
}
|
||||
wg.Wait()
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalOMediaItem2ᚖreichardᚗioᚋimaginiᚋgraphᚋmodelᚐMediaItem(ctx context.Context, sel ast.SelectionSet, v *model.MediaItem) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
|
74
graph/helpers.go
Normal file
74
graph/helpers.go
Normal file
@ -0,0 +1,74 @@
|
||||
package graph
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dsoprea/go-exif/v3"
|
||||
exifcommon "github.com/dsoprea/go-exif/v3/common"
|
||||
"reichard.io/imagini/graph/model"
|
||||
)
|
||||
|
||||
func deriveDeviceType(r *http.Request) model.DeviceType {
|
||||
userAgent := strings.ToLower(r.Header.Get("User-Agent"))
|
||||
if strings.Contains(userAgent, "ios-imagini") {
|
||||
return model.DeviceTypeIOs
|
||||
} else if strings.Contains(userAgent, "android-imagini") {
|
||||
return model.DeviceTypeAndroid
|
||||
} else if strings.Contains(userAgent, "chrome") {
|
||||
return model.DeviceTypeChrome
|
||||
} else if strings.Contains(userAgent, "firefox") {
|
||||
return model.DeviceTypeFirefox
|
||||
} else if strings.Contains(userAgent, "msie") {
|
||||
return model.DeviceTypeInternetExplorer
|
||||
} else if strings.Contains(userAgent, "edge") {
|
||||
return model.DeviceTypeEdge
|
||||
} else if strings.Contains(userAgent, "safari") {
|
||||
return model.DeviceTypeSafari
|
||||
}
|
||||
return model.DeviceTypeUnknown
|
||||
}
|
||||
|
||||
func mediaItemFromEXIFData(filePath string) (*model.MediaItem, error) {
|
||||
rawExif, err := exif.SearchFileAndExtractExif(filePath)
|
||||
entries, _, err := exif.GetFlatExifData(rawExif, nil)
|
||||
|
||||
decLong := float64(1)
|
||||
decLat := float64(1)
|
||||
|
||||
mediaItem := &model.MediaItem{}
|
||||
for _, v := range entries {
|
||||
if v.TagName == "DateTimeOriginal" {
|
||||
formattedTime, _ := time.Parse("2006:01:02 15:04:05", v.Formatted)
|
||||
mediaItem.ExifDate = &formattedTime
|
||||
} else if v.TagName == "GPSLatitude" {
|
||||
latStruct := v.Value.([]exifcommon.Rational)
|
||||
decLat *= deriveDecimalCoordinate(
|
||||
latStruct[0].Numerator/latStruct[0].Denominator,
|
||||
latStruct[1].Numerator/latStruct[1].Denominator,
|
||||
float64(latStruct[2].Numerator)/float64(latStruct[2].Denominator),
|
||||
)
|
||||
} else if v.TagName == "GPSLongitude" {
|
||||
longStruct := v.Value.([]exifcommon.Rational)
|
||||
decLong *= deriveDecimalCoordinate(
|
||||
longStruct[0].Numerator/longStruct[0].Denominator,
|
||||
longStruct[1].Numerator/longStruct[1].Denominator,
|
||||
float64(longStruct[2].Numerator)/float64(longStruct[2].Denominator),
|
||||
)
|
||||
} else if v.TagName == "GPSLatitudeRef" && v.Formatted == "S" {
|
||||
decLat *= -1
|
||||
} else if v.TagName == "GPSLongitudeRef" && v.Formatted == "W" {
|
||||
decLong *= -1
|
||||
}
|
||||
}
|
||||
|
||||
mediaItem.Latitude = &decLat
|
||||
mediaItem.Longitude = &decLong
|
||||
|
||||
return mediaItem, err
|
||||
}
|
||||
|
||||
func deriveDecimalCoordinate(degrees, minutes uint32, seconds float64) float64 {
|
||||
return float64(degrees) + (float64(minutes) / 60) + (seconds / 3600)
|
||||
}
|
@ -57,7 +57,6 @@ type Device struct {
|
||||
Name string `json:"name" gorm:"not null"`
|
||||
Type DeviceType `json:"type" gorm:"default:Unknown;not null"`
|
||||
UserID string `json:"userID" gorm:"not null"`
|
||||
User *User `json:"user" gorm:"foreignKey:ID;references:UserID;not null"`
|
||||
RefreshKey *string `json:"refreshKey" `
|
||||
}
|
||||
|
||||
@ -125,7 +124,6 @@ type MediaItem struct {
|
||||
Tags []*Tag `json:"tags" gorm:"many2many:media_tags"`
|
||||
Albums []*Album `json:"albums" gorm:"many2many:media_albums"`
|
||||
UserID string `json:"userID" gorm:"not null"`
|
||||
User *User `json:"user" gorm:"foreignKey:ID;references:UserID;not null"`
|
||||
}
|
||||
|
||||
type MediaItemFilter struct {
|
||||
@ -152,10 +150,6 @@ type NewAlbum struct {
|
||||
Name string `json:"name" `
|
||||
}
|
||||
|
||||
type NewDevice struct {
|
||||
Name string `json:"name" `
|
||||
}
|
||||
|
||||
type NewMediaItem struct {
|
||||
File graphql.Upload `json:"file" `
|
||||
Tags []string `json:"tags" `
|
||||
@ -239,16 +233,18 @@ type TimeFilter struct {
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID string `json:"id" gorm:"primaryKey;not null"`
|
||||
CreatedAt *time.Time `json:"createdAt" `
|
||||
UpdatedAt *time.Time `json:"updatedAt" `
|
||||
Email string `json:"email" gorm:"not null;unique"`
|
||||
Username string `json:"username" gorm:"not null;unique"`
|
||||
FirstName *string `json:"firstName" `
|
||||
LastName *string `json:"lastName" `
|
||||
Role Role `json:"role" gorm:"default:User;not null"`
|
||||
AuthType AuthType `json:"authType" gorm:"default:Local;not null"`
|
||||
Password *string `json:"password" `
|
||||
ID string `json:"id" gorm:"primaryKey;not null"`
|
||||
CreatedAt *time.Time `json:"createdAt" `
|
||||
UpdatedAt *time.Time `json:"updatedAt" `
|
||||
Email string `json:"email" gorm:"not null;unique"`
|
||||
Username string `json:"username" gorm:"not null;unique"`
|
||||
FirstName *string `json:"firstName" `
|
||||
LastName *string `json:"lastName" `
|
||||
Role Role `json:"role" gorm:"default:User;not null"`
|
||||
AuthType AuthType `json:"authType" gorm:"default:Local;not null"`
|
||||
Password *string `json:"password" `
|
||||
Devices []*Device `json:"devices" gorm:"foreignKey:UserID"`
|
||||
MediaItems []*MediaItem `json:"mediaItems" gorm:"foreignKey:UserID"`
|
||||
}
|
||||
|
||||
type UserFilter struct {
|
||||
|
@ -2,6 +2,7 @@ package graph
|
||||
|
||||
import (
|
||||
"reichard.io/imagini/internal/auth"
|
||||
"reichard.io/imagini/internal/config"
|
||||
"reichard.io/imagini/internal/db"
|
||||
)
|
||||
|
||||
@ -10,6 +11,7 @@ import (
|
||||
// It serves as dependency injection for your app, add any dependencies you require here.
|
||||
|
||||
type Resolver struct {
|
||||
Auth *auth.AuthManager
|
||||
DB *db.DBManager
|
||||
Config *config.Config
|
||||
Auth *auth.AuthManager
|
||||
DB *db.DBManager
|
||||
}
|
||||
|
@ -139,6 +139,21 @@ input AuthTypeFilter {
|
||||
# -------------------- Object Definitions --------------------
|
||||
# ------------------------------------------------------------
|
||||
|
||||
type User {
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
createdAt: Time
|
||||
updatedAt: Time
|
||||
email: String! @meta(gorm: "not null;unique")
|
||||
username: String! @meta(gorm: "not null;unique")
|
||||
firstName: String
|
||||
lastName: String
|
||||
role: Role! @meta(gorm: "default:User;not null")
|
||||
authType: AuthType! @meta(gorm: "default:Local;not null")
|
||||
password: String @isPrivate
|
||||
devices: [Device!] @meta(gorm: "foreignKey:UserID")
|
||||
mediaItems: [MediaItem!] @meta(gorm: "foreignKey:UserID")
|
||||
}
|
||||
|
||||
type Device {
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
createdAt: Time
|
||||
@ -146,23 +161,9 @@ type Device {
|
||||
name: String! @meta(gorm: "not null")
|
||||
type: DeviceType! @meta(gorm: "default:Unknown;not null")
|
||||
userID: ID! @meta(gorm: "not null")
|
||||
user: User! @meta(gorm: "foreignKey:ID;references:UserID;not null")
|
||||
refreshKey: String @isPrivate
|
||||
}
|
||||
|
||||
type User {
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
createdAt: Time
|
||||
updatedAt: Time
|
||||
email: String! @meta(gorm: "not null;unique")
|
||||
username: String! @meta(gorm: "not null;unique")
|
||||
firstName: String
|
||||
lastName: String
|
||||
role: Role! @meta(gorm: "default:User;not null")
|
||||
authType: AuthType! @meta(gorm: "default:Local;not null")
|
||||
password: String @isPrivate
|
||||
}
|
||||
|
||||
type MediaItem {
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
createdAt: Time
|
||||
@ -176,21 +177,20 @@ type MediaItem {
|
||||
tags: [Tag] @meta(gorm: "many2many:media_tags")
|
||||
albums: [Album] @meta(gorm: "many2many:media_albums")
|
||||
userID: ID! @meta(gorm: "not null")
|
||||
user: User! @meta(gorm: "foreignKey:ID;references:UserID;not null")
|
||||
}
|
||||
|
||||
type Tag {
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
createdAt: Time
|
||||
updatedAt: Time
|
||||
name: String! @meta(gorm: "unique;not null")
|
||||
name: String! @meta(gorm: "unique;not null")
|
||||
}
|
||||
|
||||
type Album {
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
id: ID! @meta(gorm: "primaryKey;not null")
|
||||
createdAt: Time
|
||||
updatedAt: Time
|
||||
name: String! @meta(gorm: "unique;not null")
|
||||
name: String! @meta(gorm: "unique;not null")
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------
|
||||
@ -272,10 +272,6 @@ input NewUser {
|
||||
password: String
|
||||
}
|
||||
|
||||
input NewDevice {
|
||||
name: String!
|
||||
}
|
||||
|
||||
input NewMediaItem {
|
||||
file: Upload!
|
||||
tags: [ID!]
|
||||
@ -377,7 +373,6 @@ type Query {
|
||||
|
||||
type Mutation {
|
||||
createMediaItem(input: NewMediaItem!): MediaItem! @hasMinRole(role: User)
|
||||
createDevice(input: NewDevice!): Device! @hasMinRole(role: User)
|
||||
createAlbum(input: NewAlbum!): Album! @hasMinRole(role: User)
|
||||
createTag(input: NewTag!): Tag! @hasMinRole(role: User)
|
||||
createUser(input: NewUser!): User! @hasMinRole(role: Admin)
|
||||
|
@ -4,22 +4,100 @@ package graph
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gabriel-vasile/mimetype"
|
||||
"github.com/google/uuid"
|
||||
"reichard.io/imagini/graph/generated"
|
||||
"reichard.io/imagini/graph/model"
|
||||
)
|
||||
|
||||
// Done
|
||||
func (r *mutationResolver) CreateMediaItem(ctx context.Context, input model.NewMediaItem) (*model.MediaItem, error) {
|
||||
panic(fmt.Errorf("not implemented"))
|
||||
}
|
||||
// Get Context
|
||||
authContext := ctx.Value("auth").(*model.AuthContext)
|
||||
accessToken := *authContext.AccessToken
|
||||
userID, ok := accessToken.Get("sub")
|
||||
if !ok {
|
||||
return nil, errors.New("Upload Failed")
|
||||
}
|
||||
|
||||
func (r *mutationResolver) CreateDevice(ctx context.Context, input model.NewDevice) (*model.Device, error) {
|
||||
panic(fmt.Errorf("not implemented"))
|
||||
// File header placeholder
|
||||
fileHeader := make([]byte, 64)
|
||||
|
||||
// Copy headers into the buffer
|
||||
if _, err := input.File.File.Read(fileHeader); err != nil {
|
||||
return nil, errors.New("Upload Failed")
|
||||
}
|
||||
|
||||
// Determine media type
|
||||
fileMime := mimetype.Detect(fileHeader)
|
||||
contentType := fileMime.String()
|
||||
var isVideo bool
|
||||
if strings.HasPrefix(contentType, "image/") {
|
||||
isVideo = false
|
||||
} else if strings.HasPrefix(contentType, "video/") {
|
||||
isVideo = true
|
||||
} else {
|
||||
return nil, errors.New("Upload Failed")
|
||||
}
|
||||
|
||||
// Derive Folder & File Path
|
||||
mediaItemID := uuid.New().String()
|
||||
fileName := mediaItemID + fileMime.Extension()
|
||||
folderPath := path.Join("/" + r.Config.DataPath + "/media/" + userID.(string))
|
||||
os.MkdirAll(folderPath, 0700)
|
||||
filePath := path.Join(folderPath + "/" + fileName)
|
||||
|
||||
// Create File
|
||||
f, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return nil, errors.New("Upload Failed")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Copy header to file
|
||||
_, err = io.Copy(f, bytes.NewReader(fileHeader))
|
||||
if err != nil {
|
||||
return nil, errors.New("Upload Failed")
|
||||
}
|
||||
|
||||
// Copy remaining file
|
||||
_, err = io.Copy(f, input.File.File)
|
||||
if err != nil {
|
||||
return nil, errors.New("Upload Failed")
|
||||
}
|
||||
|
||||
// Create MediaItem From EXIF Data
|
||||
mediaItem, err := mediaItemFromEXIFData(filePath)
|
||||
if err != nil {
|
||||
return nil, errors.New("Upload Failed")
|
||||
}
|
||||
|
||||
// Add Additional MediaItem Fields
|
||||
mediaItem.ID = mediaItemID
|
||||
mediaItem.UserID = userID.(string)
|
||||
mediaItem.IsVideo = isVideo
|
||||
mediaItem.FileName = fileName
|
||||
mediaItem.OrigName = input.File.Filename
|
||||
|
||||
// Create MediaItem in DB
|
||||
err = r.DB.CreateMediaItem(mediaItem)
|
||||
if err != nil {
|
||||
return nil, errors.New("Upload Failed")
|
||||
}
|
||||
|
||||
// Success
|
||||
return mediaItem, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) CreateAlbum(ctx context.Context, input model.NewAlbum) (*model.Album, error) {
|
||||
@ -50,11 +128,17 @@ func (r *mutationResolver) CreateUser(ctx context.Context, input model.NewUser)
|
||||
}
|
||||
|
||||
func (r *queryResolver) Login(ctx context.Context, user string, password string, deviceID *string) (*model.AuthResponse, error) {
|
||||
// Set Cookie From Context
|
||||
// Get Context
|
||||
authContext := ctx.Value("auth").(*model.AuthContext)
|
||||
resp := authContext.AuthResponse
|
||||
req := authContext.AuthRequest
|
||||
|
||||
// Clear All Cookies By Default
|
||||
accessCookie := http.Cookie{Name: "AccessToken", Path: "/", HttpOnly: true, MaxAge: -1, Expires: time.Now().Add(-100 * time.Hour)}
|
||||
refreshCookie := http.Cookie{Name: "RefreshToken", Path: "/", HttpOnly: true, MaxAge: -1, Expires: time.Now().Add(-100 * time.Hour)}
|
||||
http.SetCookie(*resp, &accessCookie)
|
||||
http.SetCookie(*resp, &refreshCookie)
|
||||
|
||||
// Do Login
|
||||
foundUser, success := r.Auth.AuthenticateUser(user, password)
|
||||
if !success {
|
||||
@ -62,7 +146,7 @@ func (r *queryResolver) Login(ctx context.Context, user string, password string,
|
||||
}
|
||||
|
||||
// Upsert Device
|
||||
foundDevice := model.Device{}
|
||||
foundDevice := model.Device{UserID: foundUser.ID}
|
||||
if deviceID != nil {
|
||||
parsedDeviceID, err := uuid.Parse(*deviceID)
|
||||
if err != nil {
|
||||
@ -75,8 +159,6 @@ func (r *queryResolver) Login(ctx context.Context, user string, password string,
|
||||
}
|
||||
} else {
|
||||
foundDevice.Type = deriveDeviceType(req)
|
||||
foundDevice.UserID = foundUser.ID
|
||||
// TODO: foundDevice.User = &foundUser
|
||||
err := r.DB.CreateDevice(&foundDevice)
|
||||
if err != nil {
|
||||
return &model.AuthResponse{Result: model.AuthResultFailure}, nil
|
||||
@ -94,18 +176,25 @@ func (r *queryResolver) Login(ctx context.Context, user string, password string,
|
||||
}
|
||||
|
||||
// Set appropriate cookies
|
||||
accessCookie := http.Cookie{Name: "AccessToken", Value: accessToken, Path: "/", HttpOnly: true}
|
||||
refreshCookie := http.Cookie{Name: "RefreshToken", Value: refreshToken, Path: "/", HttpOnly: true}
|
||||
accessCookie = http.Cookie{Name: "AccessToken", Value: accessToken, Path: "/", HttpOnly: true}
|
||||
refreshCookie = http.Cookie{Name: "RefreshToken", Value: refreshToken, Path: "/", HttpOnly: true}
|
||||
http.SetCookie(*resp, &accessCookie)
|
||||
http.SetCookie(*resp, &refreshCookie)
|
||||
|
||||
// TODO: Prob bandaid
|
||||
foundDevice.User = &foundUser
|
||||
return &model.AuthResponse{Result: model.AuthResultSuccess, Device: &foundDevice}, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Logout(ctx context.Context) (*model.AuthResponse, error) {
|
||||
// panic(fmt.Errorf("not implemented"))
|
||||
// Set Cookie From Context
|
||||
authContext := ctx.Value("auth").(*model.AuthContext)
|
||||
resp := authContext.AuthResponse
|
||||
|
||||
// Clear All Cookies
|
||||
accessCookie := http.Cookie{Name: "AccessToken", Path: "/", HttpOnly: true, MaxAge: -1, Expires: time.Now().Add(-100 * time.Hour)}
|
||||
refreshCookie := http.Cookie{Name: "RefreshToken", Path: "/", HttpOnly: true, MaxAge: -1, Expires: time.Now().Add(-100 * time.Hour)}
|
||||
http.SetCookie(*resp, &accessCookie)
|
||||
http.SetCookie(*resp, &refreshCookie)
|
||||
|
||||
return &model.AuthResponse{Result: model.AuthResultSuccess}, nil
|
||||
}
|
||||
|
||||
@ -172,29 +261,3 @@ func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
|
||||
|
||||
type mutationResolver struct{ *Resolver }
|
||||
type queryResolver struct{ *Resolver }
|
||||
|
||||
// !!! WARNING !!!
|
||||
// The code below was going to be deleted when updating resolvers. It has been copied here so you have
|
||||
// one last chance to move it out of harms way if you want. There are two reasons this happens:
|
||||
// - When renaming or deleting a resolver the old code will be put in here. You can safely delete
|
||||
// it when you're done.
|
||||
// - You have helper methods in this file. Move them out to keep these resolver files clean.
|
||||
func deriveDeviceType(r *http.Request) model.DeviceType {
|
||||
userAgent := strings.ToLower(r.Header.Get("User-Agent"))
|
||||
if strings.Contains(userAgent, "ios-imagini") {
|
||||
return model.DeviceTypeIOs
|
||||
} else if strings.Contains(userAgent, "android-imagini") {
|
||||
return model.DeviceTypeAndroid
|
||||
} else if strings.Contains(userAgent, "chrome") {
|
||||
return model.DeviceTypeChrome
|
||||
} else if strings.Contains(userAgent, "firefox") {
|
||||
return model.DeviceTypeFirefox
|
||||
} else if strings.Contains(userAgent, "msie") {
|
||||
return model.DeviceTypeInternetExplorer
|
||||
} else if strings.Contains(userAgent, "edge") {
|
||||
return model.DeviceTypeEdge
|
||||
} else if strings.Contains(userAgent, "safari") {
|
||||
return model.DeviceTypeSafari
|
||||
}
|
||||
return model.DeviceTypeUnknown
|
||||
}
|
||||
|
1
internal/api/media_item.go
Normal file
1
internal/api/media_item.go
Normal file
@ -0,0 +1 @@
|
||||
package api
|
@ -12,8 +12,9 @@ func (api *API) registerRoutes() {
|
||||
// Set up Directives
|
||||
graphConfig := generated.Config{
|
||||
Resolvers: &graph.Resolver{
|
||||
DB: api.DB,
|
||||
Auth: api.Auth,
|
||||
DB: api.DB,
|
||||
Auth: api.Auth,
|
||||
Config: api.Config,
|
||||
},
|
||||
Directives: generated.DirectiveRoot{
|
||||
Meta: api.metaDirective,
|
||||
|
@ -48,9 +48,28 @@ func NewMgr(c *config.Config) *DBManager {
|
||||
dbm.bootstrapDatabase()
|
||||
}
|
||||
|
||||
dbm.testFeatures()
|
||||
|
||||
return dbm
|
||||
}
|
||||
|
||||
func (dbm *DBManager) testFeatures() {
|
||||
|
||||
// Get Devices By UserID
|
||||
// var myDevices []model.Device
|
||||
// dbm.db.Debug().Where(&model.Device{UserID: "97589354-cd42-40e2-bc5e-7ba6badf89fa"}).Find(&myDevices)
|
||||
// fmt.Printf("Devices: %+v\n", myDevices)
|
||||
|
||||
// Get User by DeviceID
|
||||
// var myUser []model.User
|
||||
// dbm.db.Debug().Model(&model.User{}).
|
||||
// Select("users.*").
|
||||
// Joins("left join devices on users.id = devices.user_id").
|
||||
// Where("devices.id = ?", "4e9aa851-f25b-4330-91dc-c0f975e56fa1").
|
||||
// Find(&myUser)
|
||||
// fmt.Printf("User: %+v\n", myUser)
|
||||
}
|
||||
|
||||
func (dbm *DBManager) bootstrapDatabase() {
|
||||
log.Info("[query] Bootstrapping database.")
|
||||
|
||||
|
Reference in New Issue
Block a user