Add user management to api
This commit is contained in:
parent
108de3d6b8
commit
a87e9fc56d
|
@ -1,7 +1,7 @@
|
|||
CREATE TABLE IF NOT EXISTS user (
|
||||
user_id int NOT NULL AUTO_INCREMENT,
|
||||
username varchar(256) NOT NULL UNIQUE,
|
||||
password varchar(256) NOT NULL,
|
||||
password varchar(256),
|
||||
root_path varchar(512),
|
||||
admin boolean NOT NULL DEFAULT 0,
|
||||
|
||||
|
|
|
@ -69,13 +69,16 @@ type ComplexityRoot struct {
|
|||
|
||||
Mutation struct {
|
||||
AuthorizeUser func(childComplexity int, username string, password string) int
|
||||
CreateUser func(childComplexity int, username string, rootPath string, password *string, admin bool) int
|
||||
DeleteShareToken func(childComplexity int, token string) int
|
||||
DeleteUser func(childComplexity int, id int) int
|
||||
InitialSetupWizard func(childComplexity int, username string, password string, rootPath string) int
|
||||
RegisterUser func(childComplexity int, username string, password string, rootPath string) int
|
||||
ScanAll func(childComplexity int) int
|
||||
ScanUser func(childComplexity int, userID int) int
|
||||
ShareAlbum func(childComplexity int, albumID int, expire *time.Time, password *string) int
|
||||
SharePhoto func(childComplexity int, photoID int, expire *time.Time, password *string) int
|
||||
UpdateUser func(childComplexity int, id int, username *string, rootPath *string, admin *bool) int
|
||||
}
|
||||
|
||||
Photo struct {
|
||||
|
@ -172,6 +175,9 @@ type MutationResolver interface {
|
|||
ShareAlbum(ctx context.Context, albumID int, expire *time.Time, password *string) (*models.ShareToken, error)
|
||||
SharePhoto(ctx context.Context, photoID int, expire *time.Time, password *string) (*models.ShareToken, error)
|
||||
DeleteShareToken(ctx context.Context, token string) (*models.ShareToken, error)
|
||||
UpdateUser(ctx context.Context, id int, username *string, rootPath *string, admin *bool) (*models.User, error)
|
||||
CreateUser(ctx context.Context, username string, rootPath string, password *string, admin bool) (*models.User, error)
|
||||
DeleteUser(ctx context.Context, id int) (*models.User, error)
|
||||
}
|
||||
type PhotoResolver interface {
|
||||
Thumbnail(ctx context.Context, obj *models.Photo) (*models.PhotoURL, error)
|
||||
|
@ -319,6 +325,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.Mutation.AuthorizeUser(childComplexity, args["username"].(string), args["password"].(string)), true
|
||||
|
||||
case "Mutation.createUser":
|
||||
if e.complexity.Mutation.CreateUser == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Mutation_createUser_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.CreateUser(childComplexity, args["username"].(string), args["rootPath"].(string), args["password"].(*string), args["admin"].(bool)), true
|
||||
|
||||
case "Mutation.deleteShareToken":
|
||||
if e.complexity.Mutation.DeleteShareToken == nil {
|
||||
break
|
||||
|
@ -331,6 +349,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.Mutation.DeleteShareToken(childComplexity, args["token"].(string)), true
|
||||
|
||||
case "Mutation.deleteUser":
|
||||
if e.complexity.Mutation.DeleteUser == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Mutation_deleteUser_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.DeleteUser(childComplexity, args["id"].(int)), true
|
||||
|
||||
case "Mutation.initialSetupWizard":
|
||||
if e.complexity.Mutation.InitialSetupWizard == nil {
|
||||
break
|
||||
|
@ -398,6 +428,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.Mutation.SharePhoto(childComplexity, args["photoId"].(int), args["expire"].(*time.Time), args["password"].(*string)), true
|
||||
|
||||
case "Mutation.updateUser":
|
||||
if e.complexity.Mutation.UpdateUser == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Mutation_updateUser_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.UpdateUser(childComplexity, args["id"].(int), args["username"].(*string), args["rootPath"].(*string), args["admin"].(*bool)), true
|
||||
|
||||
case "Photo.album":
|
||||
if e.complexity.Photo.Album == nil {
|
||||
break
|
||||
|
@ -881,7 +923,7 @@ type Mutation {
|
|||
): AuthorizeResult
|
||||
|
||||
"Scan all users for new photos"
|
||||
scanAll: ScannerResult!
|
||||
scanAll: ScannerResult! @isAdmin
|
||||
"Scan a single user for new photos"
|
||||
scanUser(userId: Int!): ScannerResult!
|
||||
|
||||
|
@ -891,6 +933,20 @@ type Mutation {
|
|||
sharePhoto(photoId: Int!, expire: Time, password: String): ShareToken
|
||||
"Delete a share token by it's token value"
|
||||
deleteShareToken(token: String!): ShareToken
|
||||
|
||||
updateUser(
|
||||
id: Int!
|
||||
username: String
|
||||
rootPath: String
|
||||
admin: Boolean
|
||||
): User @isAdmin
|
||||
createUser(
|
||||
username: String!
|
||||
rootPath: String!
|
||||
password: String
|
||||
admin: Boolean!
|
||||
): User @isAdmin
|
||||
deleteUser(id: Int!): User @isAdmin
|
||||
}
|
||||
|
||||
type AuthorizeResult {
|
||||
|
@ -1066,6 +1122,44 @@ func (ec *executionContext) field_Mutation_authorizeUser_args(ctx context.Contex
|
|||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_createUser_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
var arg0 string
|
||||
if tmp, ok := rawArgs["username"]; ok {
|
||||
arg0, err = ec.unmarshalNString2string(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["username"] = arg0
|
||||
var arg1 string
|
||||
if tmp, ok := rawArgs["rootPath"]; ok {
|
||||
arg1, err = ec.unmarshalNString2string(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["rootPath"] = arg1
|
||||
var arg2 *string
|
||||
if tmp, ok := rawArgs["password"]; ok {
|
||||
arg2, err = ec.unmarshalOString2ᚖstring(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["password"] = arg2
|
||||
var arg3 bool
|
||||
if tmp, ok := rawArgs["admin"]; ok {
|
||||
arg3, err = ec.unmarshalNBoolean2bool(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["admin"] = arg3
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_deleteShareToken_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
|
@ -1080,6 +1174,20 @@ func (ec *executionContext) field_Mutation_deleteShareToken_args(ctx context.Con
|
|||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_deleteUser_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
var arg0 int
|
||||
if tmp, ok := rawArgs["id"]; ok {
|
||||
arg0, err = ec.unmarshalNInt2int(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["id"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_initialSetupWizard_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
|
@ -1214,6 +1322,44 @@ func (ec *executionContext) field_Mutation_sharePhoto_args(ctx context.Context,
|
|||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_updateUser_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
var arg0 int
|
||||
if tmp, ok := rawArgs["id"]; ok {
|
||||
arg0, err = ec.unmarshalNInt2int(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["id"] = arg0
|
||||
var arg1 *string
|
||||
if tmp, ok := rawArgs["username"]; ok {
|
||||
arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["username"] = arg1
|
||||
var arg2 *string
|
||||
if tmp, ok := rawArgs["rootPath"]; ok {
|
||||
arg2, err = ec.unmarshalOString2ᚖstring(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["rootPath"] = arg2
|
||||
var arg3 *bool
|
||||
if tmp, ok := rawArgs["admin"]; ok {
|
||||
arg3, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["admin"] = arg3
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
|
@ -1949,8 +2095,28 @@ func (ec *executionContext) _Mutation_scanAll(ctx context.Context, field graphql
|
|||
ctx = graphql.WithResolverContext(ctx, rctx)
|
||||
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().ScanAll(rctx)
|
||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().ScanAll(rctx)
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.IsAdmin == nil {
|
||||
return nil, errors.New("directive isAdmin is not implemented")
|
||||
}
|
||||
return ec.directives.IsAdmin(ctx, nil, directive0)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tmp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if data, ok := tmp.(*models.ScannerResult); ok {
|
||||
return data, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/viktorstrate/photoview/api/graphql/models.ScannerResult`, tmp)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
|
@ -2135,6 +2301,189 @@ func (ec *executionContext) _Mutation_deleteShareToken(ctx context.Context, fiel
|
|||
return ec.marshalOShareToken2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐShareToken(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_updateUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
ec.Tracer.EndFieldExecution(ctx)
|
||||
}()
|
||||
rctx := &graphql.ResolverContext{
|
||||
Object: "Mutation",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: true,
|
||||
}
|
||||
ctx = graphql.WithResolverContext(ctx, rctx)
|
||||
rawArgs := field.ArgumentMap(ec.Variables)
|
||||
args, err := ec.field_Mutation_updateUser_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
rctx.Args = args
|
||||
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
||||
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().UpdateUser(rctx, args["id"].(int), args["username"].(*string), args["rootPath"].(*string), args["admin"].(*bool))
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.IsAdmin == nil {
|
||||
return nil, errors.New("directive isAdmin is not implemented")
|
||||
}
|
||||
return ec.directives.IsAdmin(ctx, nil, directive0)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tmp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if data, ok := tmp.(*models.User); ok {
|
||||
return data, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/viktorstrate/photoview/api/graphql/models.User`, tmp)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*models.User)
|
||||
rctx.Result = res
|
||||
ctx = ec.Tracer.StartFieldChildExecution(ctx)
|
||||
return ec.marshalOUser2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_createUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
ec.Tracer.EndFieldExecution(ctx)
|
||||
}()
|
||||
rctx := &graphql.ResolverContext{
|
||||
Object: "Mutation",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: true,
|
||||
}
|
||||
ctx = graphql.WithResolverContext(ctx, rctx)
|
||||
rawArgs := field.ArgumentMap(ec.Variables)
|
||||
args, err := ec.field_Mutation_createUser_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
rctx.Args = args
|
||||
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
||||
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().CreateUser(rctx, args["username"].(string), args["rootPath"].(string), args["password"].(*string), args["admin"].(bool))
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.IsAdmin == nil {
|
||||
return nil, errors.New("directive isAdmin is not implemented")
|
||||
}
|
||||
return ec.directives.IsAdmin(ctx, nil, directive0)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tmp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if data, ok := tmp.(*models.User); ok {
|
||||
return data, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/viktorstrate/photoview/api/graphql/models.User`, tmp)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*models.User)
|
||||
rctx.Result = res
|
||||
ctx = ec.Tracer.StartFieldChildExecution(ctx)
|
||||
return ec.marshalOUser2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_deleteUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
ec.Tracer.EndFieldExecution(ctx)
|
||||
}()
|
||||
rctx := &graphql.ResolverContext{
|
||||
Object: "Mutation",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: true,
|
||||
}
|
||||
ctx = graphql.WithResolverContext(ctx, rctx)
|
||||
rawArgs := field.ArgumentMap(ec.Variables)
|
||||
args, err := ec.field_Mutation_deleteUser_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
rctx.Args = args
|
||||
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
||||
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().DeleteUser(rctx, args["id"].(int))
|
||||
}
|
||||
directive1 := func(ctx context.Context) (interface{}, error) {
|
||||
if ec.directives.IsAdmin == nil {
|
||||
return nil, errors.New("directive isAdmin is not implemented")
|
||||
}
|
||||
return ec.directives.IsAdmin(ctx, nil, directive0)
|
||||
}
|
||||
|
||||
tmp, err := directive1(rctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tmp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if data, ok := tmp.(*models.User); ok {
|
||||
return data, nil
|
||||
}
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/viktorstrate/photoview/api/graphql/models.User`, tmp)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*models.User)
|
||||
rctx.Result = res
|
||||
ctx = ec.Tracer.StartFieldChildExecution(ctx)
|
||||
return ec.marshalOUser2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Photo_id(ctx context.Context, field graphql.CollectedField, obj *models.Photo) (ret graphql.Marshaler) {
|
||||
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
||||
defer func() {
|
||||
|
@ -5401,6 +5750,12 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
|||
out.Values[i] = ec._Mutation_sharePhoto(ctx, field)
|
||||
case "deleteShareToken":
|
||||
out.Values[i] = ec._Mutation_deleteShareToken(ctx, field)
|
||||
case "updateUser":
|
||||
out.Values[i] = ec._Mutation_updateUser(ctx, field)
|
||||
case "createUser":
|
||||
out.Values[i] = ec._Mutation_createUser(ctx, field)
|
||||
case "deleteUser":
|
||||
out.Values[i] = ec._Mutation_deleteUser(ctx, field)
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
|
@ -7030,6 +7385,17 @@ func (ec *executionContext) marshalOTime2ᚖtimeᚐTime(ctx context.Context, sel
|
|||
return ec.marshalOTime2timeᚐTime(ctx, sel, *v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalOUser2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx context.Context, sel ast.SelectionSet, v models.User) graphql.Marshaler {
|
||||
return ec._User(ctx, sel, &v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalOUser2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx context.Context, sel ast.SelectionSet, v *models.User) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
return ec._User(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
@ -14,7 +15,7 @@ import (
|
|||
type User struct {
|
||||
UserID int
|
||||
Username string
|
||||
Password string
|
||||
Password *string
|
||||
RootPath string
|
||||
Admin bool
|
||||
}
|
||||
|
@ -66,7 +67,11 @@ func AuthorizeUser(database *sql.DB, username string, password string) (*User, e
|
|||
}
|
||||
}
|
||||
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
|
||||
if user.Password == nil {
|
||||
return nil, errors.New("user does not have a password")
|
||||
}
|
||||
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(password)); err != nil {
|
||||
if err == bcrypt.ErrMismatchedHashAndPassword {
|
||||
return nil, ErrorInvalidUserCredentials
|
||||
} else {
|
||||
|
@ -77,15 +82,37 @@ func AuthorizeUser(database *sql.DB, username string, password string) (*User, e
|
|||
return user, nil
|
||||
}
|
||||
|
||||
func RegisterUser(database *sql.Tx, username string, password string, rootPath string) (*User, error) {
|
||||
hashedPassBytes, err := bcrypt.GenerateFromPassword([]byte(password), 12)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hashedPass := string(hashedPassBytes)
|
||||
var ErrorInvalidRootPath = errors.New("invalid root path")
|
||||
|
||||
if _, err := database.Exec("INSERT INTO user (username, password, root_path) VALUES (?, ?, ?)", username, hashedPass, rootPath); err != nil {
|
||||
return nil, err
|
||||
func ValidRootPath(rootPath string) bool {
|
||||
_, err := os.Stat(rootPath)
|
||||
if err != nil {
|
||||
log.Printf("Warn: invalid root path: '%s'\n%s\n", rootPath, err)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func RegisterUser(database *sql.Tx, username string, password *string, rootPath string, admin bool) (*User, error) {
|
||||
if !ValidRootPath(rootPath) {
|
||||
return nil, ErrorInvalidRootPath
|
||||
}
|
||||
|
||||
if password != nil {
|
||||
hashedPassBytes, err := bcrypt.GenerateFromPassword([]byte(*password), 12)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hashedPass := string(hashedPassBytes)
|
||||
|
||||
if _, err := database.Exec("INSERT INTO user (username, password, root_path, admin) VALUES (?, ?, ?, ?)", username, hashedPass, rootPath, admin); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if _, err := database.Exec("INSERT INTO user (username, root_path, admin) VALUES (?, ?, ?)", username, rootPath, admin); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
row := database.QueryRow("SELECT * FROM user WHERE username = ?", username)
|
||||
|
|
|
@ -3,6 +3,7 @@ package resolvers
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"github.com/viktorstrate/photoview/api/graphql/auth"
|
||||
"github.com/viktorstrate/photoview/api/graphql/models"
|
||||
|
@ -81,7 +82,7 @@ func (r *mutationResolver) RegisterUser(ctx context.Context, username string, pa
|
|||
return nil, err
|
||||
}
|
||||
|
||||
user, err := models.RegisterUser(tx, username, password, rootPath)
|
||||
user, err := models.RegisterUser(tx, username, &password, rootPath, false)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return &models.AuthorizeResult{
|
||||
|
@ -127,7 +128,7 @@ func (r *mutationResolver) InitialSetupWizard(ctx context.Context, username stri
|
|||
return nil, err
|
||||
}
|
||||
|
||||
user, err := models.RegisterUser(tx, username, password, rootPath)
|
||||
user, err := models.RegisterUser(tx, username, &password, rootPath, true)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return &models.AuthorizeResult{
|
||||
|
@ -136,11 +137,6 @@ func (r *mutationResolver) InitialSetupWizard(ctx context.Context, username stri
|
|||
}, nil
|
||||
}
|
||||
|
||||
if _, err := tx.Exec("UPDATE user SET admin = true WHERE user_id = ?", user.UserID); err != nil {
|
||||
tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
token, err := user.GenerateAccessToken(tx)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
|
@ -157,3 +153,108 @@ func (r *mutationResolver) InitialSetupWizard(ctx context.Context, username stri
|
|||
Token: &token.Value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Admin queries
|
||||
func (r *mutationResolver) UpdateUser(ctx context.Context, id int, username *string, rootPath *string, admin *bool) (*models.User, error) {
|
||||
|
||||
user_rows, err := r.Database.Query("SELECT * FROM user WHERE user_id = ?", id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user_rows.Next() == false {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
user_rows.Close()
|
||||
|
||||
update_str := ""
|
||||
update_args := make([]interface{}, 0)
|
||||
|
||||
if username != nil {
|
||||
update_str += "username = ?, "
|
||||
update_args = append(update_args, username)
|
||||
}
|
||||
if rootPath != nil {
|
||||
if !models.ValidRootPath(*rootPath) {
|
||||
return nil, errors.New("invalid root path")
|
||||
}
|
||||
|
||||
update_str += "root_path = ?, "
|
||||
update_args = append(update_args, rootPath)
|
||||
}
|
||||
if admin != nil {
|
||||
update_str += "admin = ?, "
|
||||
update_args = append(update_args, admin)
|
||||
}
|
||||
|
||||
if len(update_str) == 0 {
|
||||
return nil, errors.New("no updates requested")
|
||||
}
|
||||
|
||||
update_str = update_str[:len(update_str)-2]
|
||||
log.Printf("Updating user with update string: %s\n", update_str)
|
||||
|
||||
update_args = append(update_args, id)
|
||||
|
||||
res, err := r.Database.Exec("UPDATE user SET "+update_str+" WHERE user_id = ?", update_args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rows_aff, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rows_aff == 0 {
|
||||
return nil, errors.New("no users were updated")
|
||||
}
|
||||
|
||||
row := r.Database.QueryRow("SELECT * FROM user WHERE user_id = ?", id)
|
||||
user, err := models.NewUserFromRow(row)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) CreateUser(ctx context.Context, username string, rootPath string, password *string, admin bool) (*models.User, error) {
|
||||
tx, err := r.Database.Begin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user, err := models.RegisterUser(tx, username, password, rootPath, admin)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteUser(ctx context.Context, id int) (*models.User, error) {
|
||||
|
||||
row := r.Database.QueryRow("SELECT * FROM user WHERE user_id = ?", id)
|
||||
user, err := models.NewUserFromRow(row)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := r.Database.Exec("DELETE FROM user WHERE user_id = ?", id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if rows == 0 {
|
||||
return nil, errors.New("no users deleted")
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ type Mutation {
|
|||
): AuthorizeResult
|
||||
|
||||
"Scan all users for new photos"
|
||||
scanAll: ScannerResult!
|
||||
scanAll: ScannerResult! @isAdmin
|
||||
"Scan a single user for new photos"
|
||||
scanUser(userId: Int!): ScannerResult!
|
||||
|
||||
|
@ -63,6 +63,20 @@ type Mutation {
|
|||
sharePhoto(photoId: Int!, expire: Time, password: String): ShareToken
|
||||
"Delete a share token by it's token value"
|
||||
deleteShareToken(token: String!): ShareToken
|
||||
|
||||
updateUser(
|
||||
id: Int!
|
||||
username: String
|
||||
rootPath: String
|
||||
admin: Boolean
|
||||
): User @isAdmin
|
||||
createUser(
|
||||
username: String!
|
||||
rootPath: String!
|
||||
password: String
|
||||
admin: Boolean!
|
||||
): User @isAdmin
|
||||
deleteUser(id: Int!): User @isAdmin
|
||||
}
|
||||
|
||||
type AuthorizeResult {
|
||||
|
|
|
@ -5,7 +5,11 @@ import { Table, Button, Input, Checkbox } from 'semantic-ui-react'
|
|||
import gql from 'graphql-tag'
|
||||
|
||||
const createUserMutation = gql`
|
||||
mutation createUser($username: String, $rootPath: String, $admin: Boolean) {
|
||||
mutation createUser(
|
||||
$username: String!
|
||||
$rootPath: String!
|
||||
$admin: Boolean!
|
||||
) {
|
||||
createUser(username: $username, rootPath: $rootPath, admin: $admin) {
|
||||
id
|
||||
username
|
||||
|
|
Loading…
Reference in New Issue