add graphql schema

This commit is contained in:
Dawid Wysokiński 2021-03-06 11:54:55 +01:00
parent 4f9c6b67df
commit 49c8dd355a
22 changed files with 9448 additions and 45 deletions

5
go.mod
View File

@ -4,6 +4,7 @@ go 1.16
require (
github.com/99designs/gqlgen v0.13.0
github.com/agnivade/levenshtein v1.1.0 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/gin-contrib/cors v1.3.1
github.com/gin-gonic/gin v1.6.3
@ -14,5 +15,9 @@ require (
github.com/pkg/errors v0.9.1
github.com/sethvargo/go-password v0.2.0
github.com/sirupsen/logrus v1.8.0
github.com/vektah/gqlparser/v2 v2.1.0
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

14
go.sum
View File

@ -4,8 +4,11 @@ github.com/99designs/gqlgen v0.13.0/go.mod h1:NV130r6f4tpRWuAI+zsrSdooO/eWUv+Gyy
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/agnivade/levenshtein v1.0.3/go.mod h1:4SFRZbbXWLF4MU1T9Qg0pGgH3Pjs+t6ie5efyrwRJXs=
github.com/agnivade/levenshtein v1.1.0 h1:n6qGwyHG61v3ABce1rPVZklEYRT8NFpCMrpZdBUbYGM=
github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@ -16,6 +19,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@ -212,8 +217,9 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b h1:lAZ0/chPUDWwjqosYR0X4M490zQhMsiJ4K3DbA7o+3g=
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b h1:ggRgirZABFolTmi3sn6Ivd9SipZwLedQ5wR0aAKnFxU=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -228,8 +234,9 @@ golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@ -261,8 +268,9 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -1,5 +1,6 @@
#!/bin/sh
cd ./internal/graphql
go get -u github.com/99designs/gqlgen
go run github.com/99designs/gqlgen
go mod tidy
cd ../..

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
package generated
import (
"github.com/zdam-egzamin-zawodowy/backend/internal/models"
)
type ProfessionList struct {
Total int `json:"total"`
Items []*models.Profession `json:"items"`
}
type QualificationList struct {
Total int `json:"total"`
Items []*models.Qualification `json:"items"`
}
type QuestionList struct {
Total int `json:"total"`
Items []*models.Question `json:"items"`
}
type UserList struct {
Total int `json:"total"`
Items []*models.User `json:"items"`
}

View File

@ -10,4 +10,58 @@ resolver:
filename: resolvers/resolver.go
package: resolvers
type: Resolver
struct_tag: gqlgen
struct_tag: gqlgen
models:
ID:
model:
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32
Role:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.Role
User:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.User
UserFilter:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.UserFilter
UserInput:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.UserInput
UpdateManyUsersInput:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.UserInput
Profession:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.Profession
ProfessionFilter:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.ProfessionFilter
ProfessionInput:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.ProfessionInput
Qualification:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.Qualification
QualificationFilter:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.QualificationFilter
QualificationFilterOr:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.QualificationFilterOr
QualificationInput:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.QualificationInput
Answer:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.Answer
Question:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.Question
QuestionFilter:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.QuestionFilter
QuestionInput:
model:
- github.com/zdam-egzamin-zawodowy/backend/internal/models.QuestionInput

View File

@ -0,0 +1,32 @@
package resolvers
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
import (
"context"
"fmt"
"github.com/zdam-egzamin-zawodowy/backend/internal/graphql/generated"
"github.com/zdam-egzamin-zawodowy/backend/internal/models"
)
func (r *mutationResolver) CreateProfession(ctx context.Context, input models.ProfessionInput) (*models.Profession, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) UpdateProfession(ctx context.Context, id int, input models.ProfessionInput) (*models.Profession, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) DeleteProfessions(ctx context.Context, ids []int) ([]*models.Profession, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Professions(ctx context.Context, filter *models.ProfessionFilter, limit *int, offset *int, sort []string) (*generated.ProfessionList, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Profession(ctx context.Context, id *int, slug *string) (*models.Profession, error) {
panic(fmt.Errorf("not implemented"))
}

View File

@ -0,0 +1,32 @@
package resolvers
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
import (
"context"
"fmt"
"github.com/zdam-egzamin-zawodowy/backend/internal/graphql/generated"
"github.com/zdam-egzamin-zawodowy/backend/internal/models"
)
func (r *mutationResolver) CreateQualification(ctx context.Context, input models.QualificationInput) (*models.Qualification, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) UpdateQualification(ctx context.Context, id int, input models.QualificationInput) (*models.Qualification, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) DeleteQualifications(ctx context.Context, ids []int) ([]*models.Qualification, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Qualifications(ctx context.Context, filter *models.QualificationFilter, limit *int, offset *int, sort []string) (*generated.QualificationList, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Qualification(ctx context.Context, id *int, slug *string) (*models.Qualification, error) {
panic(fmt.Errorf("not implemented"))
}

View File

@ -0,0 +1,36 @@
package resolvers
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
import (
"context"
"fmt"
"github.com/zdam-egzamin-zawodowy/backend/internal/graphql/generated"
"github.com/zdam-egzamin-zawodowy/backend/internal/models"
)
func (r *mutationResolver) CreateQuestion(ctx context.Context, input models.QuestionInput) (*models.Question, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) UpdateQuestion(ctx context.Context, id int, input models.QuestionInput) (*models.Question, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) DeleteQuestions(ctx context.Context, ids []int) ([]*models.Question, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) GenerateTest(ctx context.Context, qualificationIDs []int, limit *int) ([]*models.Question, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Questions(ctx context.Context, filter *models.QuestionFilter, limit *int, offset *int, sort []string) (*generated.QuestionList, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *questionResolver) Qualification(ctx context.Context, obj *models.Question) (*models.Qualification, error) {
panic(fmt.Errorf("not implemented"))
}

View File

@ -0,0 +1,17 @@
package resolvers
import "github.com/zdam-egzamin-zawodowy/backend/internal/graphql/generated"
// This file will not be regenerated automatically.
//
// It serves as dependency injection for your app, add any dependencies you require here.
type Resolver struct{}
type mutationResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }
type questionResolver struct{ *Resolver }
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
func (r *Resolver) Question() generated.QuestionResolver { return &questionResolver{r} }

View File

@ -0,0 +1,44 @@
package resolvers
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
import (
"context"
"fmt"
"github.com/zdam-egzamin-zawodowy/backend/internal/graphql/generated"
"github.com/zdam-egzamin-zawodowy/backend/internal/models"
)
func (r *mutationResolver) CreateUser(ctx context.Context, input models.UserInput) (*models.User, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) UpdateUser(ctx context.Context, id int, input models.UserInput) (*models.User, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) UpdateManyUsers(ctx context.Context, ids []int, input models.UserInput) ([]*models.User, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) DeleteUsers(ctx context.Context, ids []int) ([]*models.User, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *mutationResolver) SignIn(ctx context.Context, email string, password string, staySignedIn *bool) (*models.User, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Users(ctx context.Context, filter *models.UserFilter, limit *int, offset *int, sort []string) (*generated.UserList, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) User(ctx context.Context, id int) (*models.User, error) {
panic(fmt.Errorf("not implemented"))
}
func (r *queryResolver) Me(ctx context.Context) (*models.User, error) {
panic(fmt.Errorf("not implemented"))
}

View File

@ -0,0 +1,7 @@
directive @goField(
forceResolver: Boolean
name: String
) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION
directive @authenticated(yes: Boolean!) on FIELD_DEFINITION
directive @hasRole(role: Role!) on FIELD_DEFINITION

View File

@ -0,0 +1,61 @@
type Profession {
id: ID!
slug: String!
name: String!
description: String
createdAt: Time!
}
type ProfessionList {
total: Int!
items: [Profession!]
}
input ProfessionInput {
name: String
description: String
}
input ProfessionFilter {
id: [ID!]
idNEQ: [ID!]
slug: [String!]
slugNEQ: [String!]
name: [String!]
nameNEQ: [String!]
nameIEQ: String
nameMATCH: String
descriptionIEQ: String
descriptionMATCH: String
createdAt: Time
createdAtGT: Time
createdAtGTE: Time
createdAtLT: Time
createdAtLTE: Time
}
extend type Query {
professions(
filter: ProfessionFilter
limit: Int
offset: Int
sort: [String!]
): ProfessionList!
profession(id: Int, slug: String): Profession
}
extend type Mutation {
createProfession(input: ProfessionInput!): Profession
@authenticated(yes: true)
@hasRole(role: ADMIN)
updateProfession(id: ID!, input: ProfessionInput!): Profession
@authenticated(yes: true)
@hasRole(role: ADMIN)
deleteProfessions(ids: [ID!]!): [Profession!]
@authenticated(yes: true)
@hasRole(role: ADMIN)
}

View File

@ -0,0 +1,87 @@
type Qualification {
id: ID!
slug: String!
name: String!
code: String!
formula: String
description: String
createdAt: Time!
}
type QualificationList {
total: Int!
items: [Qualification!]
}
input QualificationInput {
name: String
description: String
code: String
formula: String
associateProfession: [Int!]
dissociateProfession: [Int!]
}
input QualificationFilterOr {
nameMatch: String
nameIEQ: String
codeMatch: String
codeIEQ: String
}
input QualificationFilter {
id: [ID!]
idNEQ: [ID!]
slug: [String!]
slugNEQ: [String!]
formula: [String!]
formulaNEQ: [String!]
name: [String!]
nameNEQ: [String!]
nameIEQ: String
nameMATCH: String
code: [String!]
codeNEQ: [String!]
codeIEQ: String
codeMATCH: String
descriptionIEQ: String
descriptionMATCH: String
professionID: [Int!]
createdAt: Time
createdAtGT: Time
createdAtGTE: Time
createdAtLT: Time
createdAtLTE: Time
or: QualificationFilterOr
}
extend type Query {
qualifications(
filter: QualificationFilter
limit: Int
offset: Int
sort: [String!]
): QualificationList!
qualification(id: Int, slug: String): Qualification
}
extend type Mutation {
createQualification(input: QualificationInput!): Qualification
@authenticated(yes: true)
@hasRole(role: ADMIN)
updateQualification(id: ID!, input: QualificationInput!): Qualification
@authenticated(yes: true)
@hasRole(role: ADMIN)
deleteQualifications(ids: [ID!]!): [Qualification!]
@authenticated(yes: true)
@hasRole(role: ADMIN)
}

View File

@ -0,0 +1,95 @@
enum Answer {
A
B
C
D
}
type Question {
id: ID!
from: String
content: String!
explanation: String
correctAnswer: Answer!
image: String
answerA: Answer
answerAImage: String
answerB: Answer
answerBImage: String
answerC: Answer
answerCImage: String
answerD: Answer
answerDImage: String
qualification: Qualification @goField(forceResolver: true)
createdAt: Time!
updatedAt: Time!
}
type QuestionList {
total: Int!
items: [Question!]
}
input QuestionInput {
content: String
from: String
explanation: String
correctAnswer: Answer
qualificationID: Int
image: Upload
deleteImage: Boolean
answerA: Answer
answerAImage: Upload
deleteAnswerAImage: Boolean
answerB: Answer
answerBImage: Upload
deleteAnswerBImage: Boolean
answerC: Answer
answerCImage: Upload
deleteAnswerCImage: Boolean
answerD: Answer
answerDImage: Upload
deleteAnswerDImage: Boolean
}
input QuestionFilter {
id: [ID!]
idNEQ: [ID!]
from: [String!]
contentIEQ: String
contentMATCH: String
qualificationID: [Int!]
qualificationIDNEQ: [Int!]
qualificationFilter: QualificationFilter
createdAt: Time
createdAtGT: Time
createdAtGTE: Time
createdAtLT: Time
createdAtLTE: Time
}
extend type Query {
questions(
filter: QuestionFilter
limit: Int
offset: Int
sort: [String!]
): QuestionList! @authenticated(yes: true) @hasRole(role: ADMIN)
}
extend type Mutation {
createQuestion(input: QuestionInput!): Question
@authenticated(yes: true)
@hasRole(role: ADMIN)
updateQuestion(id: ID!, input: QuestionInput!): Question
@authenticated(yes: true)
@hasRole(role: ADMIN)
deleteQuestions(ids: [ID!]!): [Question!]
@authenticated(yes: true)
@hasRole(role: ADMIN)
generateTest(qualificationIDs: [ID!]!, limit: Int): [Question!]
}

View File

@ -0,0 +1,2 @@
scalar Time
scalar Upload

View File

@ -0,0 +1,85 @@
enum Role {
ADMIN
USER
}
type User {
id: ID!
displayName: String!
role: Role!
email: String!
activated: Boolean!
createdAt: Time!
}
type UserList {
total: Int!
items: [User!]
}
input UserInput {
displayName: String
password: String
email: String
role: Role
activated: Boolean
}
input UpdateManyUsersInput {
role: Role
activated: Boolean
}
input UserFilter {
id: [ID!]
idNEQ: [ID!]
activated: Boolean
displayName: [String!]
displayNameNEQ: [String!]
displayNameIEQ: String
displayNameMATCH: String
email: [String!]
emailNEQ: [String!]
emailIEQ: String
emailMATCH: String
role: [Role!]
roleNEQ: [Role!]
createdAt: Time
createdAtGT: Time
createdAtGTE: Time
createdAtLT: Time
createdAtLTE: Time
}
extend type Query {
users(
filter: UserFilter
limit: Int
offset: Int
sort: [String!]
): UserList! @authenticated(yes: true) @hasRole(role: ADMIN)
user(id: Int!): User @authenticated(yes: true) @hasRole(role: ADMIN)
me: User
}
extend type Mutation {
createUser(input: UserInput!): User
@authenticated(yes: true)
@hasRole(role: ADMIN)
updateUser(id: ID!, input: UserInput!): User
@authenticated(yes: true)
@hasRole(role: ADMIN)
updateManyUsers(ids: [ID!]!, input: UpdateManyUsersInput!): [User!]
@authenticated(yes: true)
@hasRole(role: ADMIN)
deleteUsers(ids: [ID!]!): [User!]
@authenticated(yes: true)
@hasRole(role: ADMIN)
signIn(email: String!, password: String!, staySignedIn: Boolean): User
@authenticated(yes: false)
}

View File

@ -47,12 +47,10 @@ func (input *ProfessionInput) IsEmpty() bool {
func (input *ProfessionInput) Sanitize() *ProfessionInput {
if input.Name != nil {
trimmed := strings.TrimSpace(*input.Name)
input.Name = &trimmed
*input.Name = strings.TrimSpace(*input.Name)
}
if input.Description != nil {
trimmed := strings.TrimSpace(*input.Description)
input.Description = &trimmed
*input.Description = strings.TrimSpace(*input.Description)
}
return input

View File

@ -66,20 +66,16 @@ func (input *QualificationInput) IsEmpty() bool {
func (input *QualificationInput) Sanitize() *QualificationInput {
if input.Name != nil {
trimmed := strings.TrimSpace(*input.Name)
input.Name = &trimmed
*input.Name = strings.TrimSpace(*input.Name)
}
if input.Description != nil {
trimmed := strings.TrimSpace(*input.Description)
input.Description = &trimmed
*input.Description = strings.TrimSpace(*input.Description)
}
if input.Code != nil {
trimmed := strings.TrimSpace(*input.Code)
input.Code = &trimmed
*input.Code = strings.TrimSpace(*input.Code)
}
if input.Formula != nil {
trimmed := strings.TrimSpace(*input.Formula)
input.Formula = &trimmed
*input.Formula = strings.TrimSpace(*input.Formula)
}
return input
@ -155,6 +151,9 @@ type QualificationFilter struct {
Slug []string `json:"slug" xml:"slug" gqlgen:"slug"`
SlugNEQ []string `json:"slugNEQ" xml:"slugNEQ" gqlgen:"slugNEQ"`
Formula []string `gqlgen:"formula" json:"formula" xml:"formula"`
FormulaNEQ []string `json:"formulaNEQ" xml:"formulaNEQ" gqlgen:"formulaNEQ"`
Name []string `gqlgen:"name" json:"name" xml:"name"`
NameNEQ []string `json:"nameNEQ" xml:"nameNEQ" gqlgen:"nameNEQ"`
NameMATCH string `json:"nameMATCH" xml:"nameMATCH" gqlgen:"nameMATCH"`
@ -165,9 +164,6 @@ type QualificationFilter struct {
CodeMATCH string `json:"codeMATCH" xml:"codeMATCH" gqlgen:"codeMATCH"`
CodeIEQ string `gqlgen:"codeIEQ" json:"codeIEQ" xml:"codeIEQ"`
Formula []string `gqlgen:"formula" json:"formula" xml:"formula"`
FormulaNEQ []string `json:"formulaNEQ" xml:"formulaNEQ" gqlgen:"formulaNEQ"`
DescriptionMATCH string `gqlgen:"descriptionMATCH" json:"descriptionMATCH" xml:"descriptionMATCH"`
DescriptionIEQ string `json:"descriptionIEQ" xml:"descriptionIEQ" gqlgen:"descriptionIEQ"`

View File

@ -83,16 +83,13 @@ func (input *QuestionInput) IsEmpty() bool {
func (input *QuestionInput) Sanitize() *QuestionInput {
if input.Content != nil {
trimmed := strings.TrimSpace(*input.Content)
input.Content = &trimmed
*input.Content = strings.TrimSpace(*input.Content)
}
if input.From != nil {
trimmed := strings.TrimSpace(*input.From)
input.From = &trimmed
*input.From = strings.TrimSpace(*input.From)
}
if input.Explanation != nil {
trimmed := strings.TrimSpace(*input.Explanation)
input.Explanation = &trimmed
*input.Explanation = strings.TrimSpace(*input.Explanation)
}
return input

View File

@ -10,8 +10,8 @@ import (
type Role string
const (
RoleUser Role = "user"
RoleAdmin Role = "admin"
RoleUser Role = "user"
)
func (role Role) IsValid() bool {

View File

@ -68,6 +68,20 @@ func (input *UserInput) IsEmpty() bool {
input.Activated == nil
}
func (input *UserInput) Sanitize() *UserInput {
if input.DisplayName != nil {
*input.DisplayName = strings.TrimSpace(*input.DisplayName)
}
if input.Password != nil {
*input.Password = strings.ToLower(strings.TrimSpace(*input.Password))
}
if input.Email != nil {
*input.Email = strings.ToLower(strings.TrimSpace(*input.Email))
}
return input
}
func (input *UserInput) ToUser() *User {
u := &User{
Activated: input.Activated,
@ -87,25 +101,6 @@ func (input *UserInput) ToUser() *User {
return u
}
func (input *UserInput) Sanitize() *UserInput {
if input.DisplayName != nil {
trimmed := strings.TrimSpace(*input.DisplayName)
input.DisplayName = &trimmed
}
if input.Password != nil {
sanitized := strings.ToLower(strings.TrimSpace(*input.Password))
input.Password = &sanitized
}
if input.Email != nil {
sanitized := strings.ToLower(strings.TrimSpace(*input.Email))
input.Email = &sanitized
}
return input
}
func (input *UserInput) ApplyUpdate(q *orm.Query) (*orm.Query, error) {
if !input.IsEmpty() {
if input.DisplayName != nil {