diff --git a/.YetAnotherToDoList.yaml b/.YetAnotherToDoList.yaml
index 0991163..0e89962 100644
--- a/.YetAnotherToDoList.yaml
+++ b/.YetAnotherToDoList.yaml
@@ -1,4 +1,16 @@
-sqlite3_file: 'YetAnotherToDoList.sqlite3'
-log_file: 'YetAnotherToDoList.log'
-log_UTC: false
-port: 4242
+database:
+ sqlite3File: 'YetAnotherToDoList.sqlite3'
+ secret: 'aS3cureAppl1cationk3y'
+ initialAdmin:
+ userName: 'admin'
+ password: 'temporaryPassword'
+
+logging:
+ logFile: 'YetAnotherToDoList.log'
+ logUTC: false
+
+server:
+ portHTTP: 4242
+ portHTTPS: 4241
+ certFile: 'certFile.crt'
+ keyFile: 'keyFile.key'
diff --git a/CMD_HISTORY.md b/CMD_HISTORY.md
index 547777e..1e86d80 100644
--- a/CMD_HISTORY.md
+++ b/CMD_HISTORY.md
@@ -62,3 +62,8 @@ Commands were run in the order listed below on a debian based system.
pnpm install villus graphql
pnpm install graphql-tag
```
+- Add go-chi
+ ```bash
+ go get -u github.com/go-chi/chi/v5
+ go mod tidy
+ ```
diff --git a/cmd/root.go b/cmd/root.go
index 81918a9..539b327 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -74,8 +74,8 @@ func init() {
// will be global for your application.
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.YetAnotherToDoList.yaml)")
- rootCmd.PersistentFlags().String("log_file", "", "Path to log file")
- rootCmd.PersistentFlags().String("sqlite3_file", "", "Path to SQLite3 database")
+ rootCmd.PersistentFlags().String("logFile", "", "Path to log file")
+ rootCmd.PersistentFlags().String("sqlite3File", "", "Path to SQLite3 database")
// Cobra also supports local flags, which will only run
// when this action is called directly.
@@ -120,7 +120,7 @@ func initLog() {
time_zone_local, _ := time.Now().Zone()
time_zone_offset := strings.Split(time.Now().In(time.Local).String(), " ")[2]
- if viper.GetBool("log_UTC") {
+ if viper.GetBool("logging.logUTC") {
utc = log.LUTC
time_zone_use = "UTC"
time_zone_alt = time_zone_local
@@ -140,25 +140,25 @@ func initLog() {
logger_flags := log.Ldate | log.Ltime | utc
globals.Logger = log.New(os.Stdout, "", logger_flags)
- if err := viper.BindPFlag("log_file", rootCmd.Flags().Lookup("log_file")); err != nil {
+ if err := viper.BindPFlag("logging.logFile", rootCmd.Flags().Lookup("logFile")); err != nil {
fmt.Println("Unable to bind flag:", err)
}
- if viper.GetString("log_file") != "" {
- log_path, err := filepath.Abs(viper.GetString("log_file"))
+ if viper.GetString("logging.logFile") != "" {
+ log_path, err := filepath.Abs(viper.GetString("logging.logFile"))
globals.Logger.SetOutput(os.Stdout)
if err != nil {
globals.Logger.Println("Invalid path for log file", log_path)
}
- log_file, err := os.OpenFile(log_path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
+ logFile, err := os.OpenFile(log_path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
globals.Logger.Println("Failed to write to log file:", err)
} else {
globals.Logger.Println("Switching to log file", log_path)
- globals.Logger.SetOutput(log_file)
+ globals.Logger.SetOutput(logFile)
}
}
@@ -170,19 +170,21 @@ func initLog() {
}
func initDB() {
- if err := viper.BindPFlag("sqlite3_file", rootCmd.Flags().Lookup("sqlite3_file")); err != nil {
+ if err := viper.BindPFlag("database.sqlite3File", rootCmd.Flags().Lookup("sqlite3File")); err != nil {
fmt.Println("Unable to bind flag:", err)
}
- if viper.GetString("sqlite3_file") == "" {
+ if viper.GetString("database.sqlite3File") == "" {
globals.Logger.Fatalln("No SQLite3 file specified")
}
- db_path, err := filepath.Abs(viper.GetString("sqlite3_file"))
+ db_path, err := filepath.Abs(viper.GetString("database.sqlite3File"))
if err != nil {
globals.Logger.Fatalln("Invalid path for SQLite3 file", db_path)
}
globals.Logger.Println("Connecting to SQLite3", db_path)
- globals.DB = database.InitSQLite3(db_path, globals.DB_schema, globals.Logger)
+ globals.DB = database.InitSQLite3(db_path, globals.DB_schema, globals.Logger, []byte(viper.GetString("database.secret")), viper.GetString("database.initialAdmin.userName"), viper.GetString("database.initialAdmin.password"))
+ globals.DB.CleanExpiredRefreshTokensTicker(time.Minute * 10)
+ globals.DB.CleanRevokedAccessTokensTicker(time.Minute * 10)
}
diff --git a/cmd/server.go b/cmd/server.go
index f68e9e6..2cb016d 100644
--- a/cmd/server.go
+++ b/cmd/server.go
@@ -38,7 +38,7 @@ var serverCmd = &cobra.Command{
}
globals.Logger.Println("starting http server...")
- server.StartServer(viper.GetInt("port"))
+ server.StartServer(viper.GetInt("server.portHTTP"), viper.GetInt("server.portHTTPS"), viper.GetString("server.certFile"), viper.GetString("server.keyFile"))
},
}
diff --git a/database/crypto_helpers.go b/database/crypto_helpers.go
new file mode 100644
index 0000000..dc95a0e
--- /dev/null
+++ b/database/crypto_helpers.go
@@ -0,0 +1,475 @@
+/*
+YetAnotherToDoList
+Copyright © 2023 gilex-dev gilex-dev@proton.me
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 3.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+package database
+
+import (
+ "bytes"
+ "crypto/hmac"
+ "crypto/rand"
+ "crypto/sha256"
+ "database/sql"
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "slices"
+ "strconv"
+ "strings"
+ "time"
+ "unicode"
+
+ "golang.org/x/crypto/bcrypt"
+ "somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/graph/model"
+)
+
+type RefreshToken struct {
+ Selector string `json:"selector"`
+ Token string `json:"token"`
+ ExpiryDate int `json:"expiryDate"`
+}
+
+type AccessToken struct {
+ UserId string `json:"userId"`
+ IsAdmin bool `json:"isAdmin"`
+ IsUserCreator bool `json:"isUserCreator"`
+ ExpiryDate int `json:"expiryDate"`
+}
+
+const refreshTokenLifetime = "+10 day" // TODO: add to viper
+const accessTokenLifetime = time.Minute * 10
+
+const minPasswordLength = 10
+const minUserNameLength = 10
+
+var RevokedAccessTokens []*AccessToken
+
+// ValidatePassword validates the passed string against the password criteria.
+func ValidatePassword(password string) error {
+ if len([]rune(password)) < minPasswordLength {
+ return fmt.Errorf("password must be at least %d characters long", minPasswordLength)
+ }
+ for i, c := range password {
+ if !(unicode.IsLetter(c) || unicode.IsNumber(c)) {
+ return fmt.Errorf("password contains none-alphanumeric symbol at index %d", i)
+ }
+ }
+ return nil
+}
+
+// ValidateUserName validates the passed string against the user name criteria.
+func ValidateUserName(userName string) error {
+ if len([]rune(userName)) < minUserNameLength {
+ return fmt.Errorf("userName must be at least %d characters long", minUserNameLength)
+ }
+ for i, c := range userName {
+ if !(unicode.IsLetter(c) || unicode.IsNumber(c)) {
+ return fmt.Errorf("userName contains none-alphanumeric symbol at index %d", i)
+ }
+ }
+ return nil
+}
+
+// GenerateHashFromPassword generates a hash of the passed password. Returns salt and salted & peppered hash.
+func (db CustomDB) GenerateHashFromPassword(password string) (passwordHash []byte, err error) {
+ hashBytes, err := bcrypt.GenerateFromPassword(bytes.Join([][]byte{db.secret, []byte(password)}, nil), bcrypt.DefaultCost)
+ if err != nil {
+ return nil, err
+ }
+
+ return hashBytes, nil
+}
+
+// GetRefreshTokenOwner takes a tokenId and return the owner's userId. Call before Update/Get/DeleteRefreshToken when not IS_admin.
+func (db CustomDB) GetRefreshTokenOwner(tokenId string) (string, error) {
+ numTokenId, err := strconv.Atoi(tokenId)
+ if err != nil {
+ return "", errors.New("invalid tokenId")
+ }
+
+ statement, err := db.connection.Prepare("SELECT FK_User_userId, FROM RefreshToken WHERE tokenId = ?")
+ if err != nil {
+ return "", err
+ }
+
+ result := statement.QueryRow(numTokenId)
+ var owner string
+ if err := result.Scan(&owner); err != nil {
+ return "", err
+ }
+
+ return owner, nil
+}
+
+func (db CustomDB) ValidateUserCredentials(userId *string, userName *string, password string) (validUserId string, err error) {
+ var result *sql.Row
+ var hash string
+
+ if userId != nil { // user userId
+ numUserId, err := strconv.Atoi(*userId)
+ if err != nil {
+ return "", errors.New("userId not numeric")
+ }
+
+ statement, err := db.connection.Prepare("SELECT passwordHash FROM User WHERE userId = ?")
+ if err != nil {
+ return "", err
+ }
+
+ result = statement.QueryRow(numUserId)
+ if err := result.Scan(&hash); err != nil {
+ return "", err
+ }
+ } else if userName != nil { // user userName
+ statement, err := db.connection.Prepare("SELECT userId, passwordHash FROM User WHERE userName = ?")
+ if err != nil {
+ return "", err
+ }
+
+ result = statement.QueryRow(&userName)
+ if err := result.Scan(&userId, &hash); err != nil {
+ return "", err
+ }
+ } else {
+ return "", errors.New("neither userId nor userName specified")
+ }
+
+ if err := bcrypt.CompareHashAndPassword([]byte(hash), bytes.Join([][]byte{db.secret, []byte(password)}, nil)); err != nil {
+ return "", err
+ }
+ return *userId, nil
+}
+
+// IssueRefreshToken issues a refresh token if the passed user credentials are valid. Returned refresh token can be passed to IssueAccessToken.
+func (db CustomDB) IssueRefreshToken(userId string, tokenName *string) (refreshToken *RefreshToken, refreshTokenId string, err error) {
+ numUserId, err := strconv.Atoi(userId)
+ if err != nil {
+ return nil, "", errors.New("userId not numeric")
+ }
+ selector := make([]byte, 9)
+ if _, err := rand.Read(selector); err != nil {
+ return nil, "", err
+ }
+
+ token := make([]byte, 33)
+ if _, err := rand.Read(token); err != nil {
+ return nil, "", err
+ }
+
+ statement, err := db.connection.Prepare("INSERT INTO RefreshToken (FK_User_userId, selector, tokenHash, expiryDate, tokenName) VALUES (?, ?, ?, unixepoch('now','" + refreshTokenLifetime + "'), NULLIF(?, '')) RETURNING tokenId, expiryDate")
+ if err != nil {
+ return nil, "", err
+ }
+
+ encSelector := base64.RawURLEncoding.EncodeToString(selector)
+ encToken := base64.RawURLEncoding.EncodeToString(token)
+
+ tokenHash := sha256.Sum256(token)
+
+ var expiryDate int // int(time.Now().AddDate(0, 1, 0).Unix())
+ var tokenId string
+ result := statement.QueryRow(numUserId, encSelector, base64.RawURLEncoding.EncodeToString(tokenHash[:]), &tokenName)
+
+ if err := result.Scan(&tokenId, &expiryDate); err != nil {
+ return nil, "", err
+ }
+
+ return &RefreshToken{Selector: encSelector, Token: encToken, ExpiryDate: expiryDate}, tokenId, nil
+}
+
+func (db CustomDB) GetRefreshToken(token *model.RefreshToken) (*model.RefreshToken, error) {
+ numTokenId, err := strconv.Atoi(token.ID)
+ if err != nil {
+ return nil, errors.New("invalid tokenId")
+ }
+
+ statement, err := db.connection.Prepare("SELECT expiryDate, tokenName FROM RefreshToken WHERE tokenId = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ result := statement.QueryRow(numTokenId)
+ if err := result.Scan(&token.ID, &token.ExpiryDate, &token.TokenName); err != nil {
+ return nil, err
+ }
+
+ return token, nil
+}
+
+func (db CustomDB) GetRefreshTokensFrom(userId string) ([]*model.RefreshToken, error) {
+ numUserId, err := strconv.Atoi(userId)
+ if err != nil {
+ return nil, errors.New("invalid userId")
+ }
+ statement, err := db.connection.Prepare("SELECT tokenId, expiaryDate, tokenName FROM RefreshToken WHERE FK_User_userId = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := statement.Query(numUserId)
+ if err != nil {
+ return nil, err
+ }
+
+ defer rows.Close()
+
+ var all []*model.RefreshToken
+ for rows.Next() {
+ token := model.RefreshToken{}
+ if err := rows.Scan(&token.ID, &token.ExpiryDate, &token.TokenName); err != nil {
+ return nil, err
+ }
+ all = append(all, &token)
+ }
+ return all, nil
+}
+
+func (db CustomDB) GetAllRefreshTokens() ([]*model.RefreshToken, error) {
+
+ statement, err := db.connection.Prepare("SELECT tokenID, FK_User_userId, expiryDate, tokenName FROM RefreshToken")
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := statement.Query()
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ var all []*model.RefreshToken
+ for rows.Next() {
+ var token model.RefreshToken
+ if err := rows.Scan(&token.ID, &token.UserID, &token.ExpiryDate, &token.TokenName); err != nil {
+ return nil, err
+ }
+ all = append(all, &token)
+ }
+ return all, nil
+}
+
+func (db CustomDB) UpdateRefreshToken(tokenId string, changes *model.UpdateRefreshToken) (*model.RefreshToken, error) {
+ numTokenId, err := strconv.Atoi(tokenId)
+ if err != nil {
+ return nil, errors.New("invalid tokenId")
+ }
+
+ statement, err := db.connection.Prepare("UPDATE AuthToken SET tokenName = ? WHERE tokenId = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := statement.Exec(changes.TokenName, numTokenId)
+
+ if err != nil {
+ return nil, err
+ }
+
+ num, err := rows.RowsAffected()
+ if err != nil {
+ return nil, err
+ }
+
+ if num < 1 {
+ return nil, errors.New("no rows affected")
+ }
+
+ token, err := db.GetRefreshToken(&model.RefreshToken{ID: tokenId})
+ if err != nil {
+ return nil, errors.New("failed to get updated token")
+
+ }
+ return token, nil
+}
+
+// RevokeRefreshToken revokes the access token matching the tokenId. Also calls RevokeAccessToken.
+func (db CustomDB) RevokeRefreshToken(tokenId string) (*string, error) {
+ // TODO: return string instead of *string
+ numTokenId, err := strconv.Atoi(tokenId)
+ if err != nil {
+ return nil, errors.New("invalid tokenId")
+ }
+
+ statement, err := db.connection.Prepare("DELETE FROM RefreshToken WHERE tokenId = ? RETURNING FK_User_userId")
+ if err != nil {
+ return nil, err
+ }
+
+ result := statement.QueryRow(numTokenId)
+
+ var userId string
+ if err := result.Scan(&userId); err != nil {
+ return nil, err
+ }
+
+ RevokeAccessToken(&AccessToken{UserId: userId, ExpiryDate: int(time.Now().Add(accessTokenLifetime).Unix())})
+ return &tokenId, nil
+}
+
+// IssueAccessToken issues an access token if the passed refresh token is valid. Returned access token must be passed to SignAccessToken to be accepted.
+func (db CustomDB) IssueAccessToken(refreshToken *RefreshToken) (*AccessToken, error) {
+ statement, err := db.connection.Prepare("SELECT RefreshToken.tokenHash, RefreshToken.FK_User_userId, Role.IS_admin, ROLE.IS_userCreator FROM RefreshToken INNER JOIN R_User_Role ON RefreshToken.FK_User_userId = R_User_Role.FK_User_userId INNER JOIN Role ON R_User_Role.FK_Role_roleId = Role.roleId WHERE RefreshToken.selector = ? AND RefreshToken.expiryDate >= unixepoch('now')")
+ if err != nil {
+ return nil, err
+ }
+
+ result := statement.QueryRow(refreshToken.Selector)
+
+ var tokenHash string
+ var newAccessToken AccessToken
+ if err := result.Scan(&tokenHash, &newAccessToken.UserId, &newAccessToken.IsAdmin, &newAccessToken.IsUserCreator); err != nil {
+ return nil, err
+ }
+
+ decUserToken, err := base64.RawURLEncoding.DecodeString(refreshToken.Token)
+ if err != nil {
+ return nil, err
+ }
+
+ userTokenHash := sha256.Sum256(decUserToken)
+ encUserTokenHash := base64.RawURLEncoding.EncodeToString(userTokenHash[:])
+ if encUserTokenHash != tokenHash {
+ return nil, errors.New("failed to issue access token: refreshToken does not match")
+ }
+
+ newAccessToken.ExpiryDate = int(time.Now().Add(accessTokenLifetime).Unix())
+ return &newAccessToken, nil
+}
+
+// SignAccessToken signs an access token and attaches a header. Returns access token encoded as jwt.
+func (db CustomDB) SignAccessToken(accessToken AccessToken) (encAccessToken string, err error) {
+
+ data, err := json.Marshal(accessToken)
+ if err != nil {
+ return "", err
+ }
+
+ body := base64.RawURLEncoding.EncodeToString(data)
+ header := base64.RawURLEncoding.EncodeToString([]byte(`{"alg":"HS256","typ":"JWT"}`))
+ combined := header + "." + body
+
+ mac := hmac.New(sha256.New, db.secret)
+ mac.Write([]byte(combined))
+ signature := mac.Sum(nil)
+
+ return combined + "." + base64.RawURLEncoding.EncodeToString(signature), nil
+}
+
+func (db CustomDB) CheckAccessToken(encAccessToken string) (accessToken *AccessToken, err error) {
+ accessTokenBlob := strings.Split(encAccessToken, ".")
+
+ header, err := base64.RawURLEncoding.DecodeString(accessTokenBlob[0])
+ if err != nil {
+ return nil, err
+ }
+
+ if !bytes.Equal(header, []byte(`{"alg":"HS256","typ":"JWT"}`)) {
+ return nil, errors.New("access token header wrong")
+ }
+
+ body, err := base64.RawURLEncoding.DecodeString(accessTokenBlob[1])
+ if err != nil {
+ return nil, err
+ }
+
+ var data AccessToken
+ err = json.Unmarshal(body, &data)
+ if err != nil {
+ return nil, err
+ }
+
+ // TODO: maybe change part of signKey instead?
+ for _, revokedAccessToken := range RevokedAccessTokens {
+ if data.UserId == revokedAccessToken.UserId && data.ExpiryDate <= revokedAccessToken.ExpiryDate {
+ return nil, errors.New("access token revoked")
+ }
+ }
+
+ if data.ExpiryDate < int(time.Now().Unix()) {
+ return nil, errors.New("access token expired")
+ }
+
+ if data.ExpiryDate < initTimeStamp+int(accessTokenLifetime.Seconds()) {
+ return nil, errors.New("access token expired prematurely")
+ }
+
+ signature, err := base64.RawURLEncoding.DecodeString(accessTokenBlob[2])
+ if err != nil {
+ return nil, err
+ }
+
+ mac := hmac.New(sha256.New, db.secret)
+ mac.Write([]byte(accessTokenBlob[0]))
+ mac.Write([]byte("."))
+ mac.Write([]byte(accessTokenBlob[1]))
+ expectedSignature := mac.Sum(nil)
+ if !hmac.Equal(signature, expectedSignature) {
+ return nil, errors.New("access token signature does not match")
+ }
+
+ return &data, nil
+}
+
+// RevokeAccessToken revokes all access tokens with matching UserId and UserRole that don't have a later ExpiryDate.
+// revokedAccessToken.ExpiryDate should be set to now + token-lifetime.
+func RevokeAccessToken(accessToken *AccessToken) {
+ RevokedAccessTokens = append(RevokedAccessTokens, accessToken)
+}
+
+// CleanRevokedTokensTicker removes expired tokens from the list. This should be called in an interval of > accessTokenLifetime.
+func (db CustomDB) CleanRevokedAccessTokensTicker(interval time.Duration) (stopCleaner chan bool) {
+ ticker := time.NewTicker(interval)
+ stop := make(chan bool)
+
+ go func() {
+ for {
+ select {
+ case <-stop:
+ return
+ case <-ticker.C:
+ db.logger.Println("cleaning revoked access tokens")
+ for i, revokedAccessToken := range RevokedAccessTokens {
+ if revokedAccessToken.ExpiryDate < int(time.Now().Unix()) {
+ revokedAccessToken = nil
+ slices.Delete(RevokedAccessTokens, i, i+1)
+ }
+ }
+ }
+ }
+ }()
+ return stop
+}
+
+func (db CustomDB) CleanExpiredRefreshTokensTicker(interval time.Duration) (stopCleaner chan bool) {
+ ticker := time.NewTicker(interval)
+ stop := make(chan bool)
+
+ go func() {
+ for {
+ select {
+ case <-stop:
+ return
+ case <-ticker.C:
+ db.logger.Println("cleaning expired refresh tokens")
+ _, err := db.connection.Exec("DELETE FROM RefreshToken WHERE expiryDate < unixepoch('now')")
+ if err != nil {
+ db.logger.Println("failed to clean expired refresh tokens")
+ }
+ }
+ }
+ }()
+ return stop
+}
diff --git a/database/main.go b/database/main.go
index efa5c76..ef0880d 100644
--- a/database/main.go
+++ b/database/main.go
@@ -18,10 +18,9 @@ package database
import (
"database/sql"
- "errors"
"fmt"
"log"
- "strconv"
+ "time"
"somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/graph/model"
)
@@ -30,11 +29,14 @@ type CustomDB struct {
connection *sql.DB
logger *log.Logger
schema uint
+ secret []byte
}
-func InitSQLite3(path string, schema uint, logger *log.Logger) *CustomDB {
+var initTimeStamp int
- db := CustomDB{logger: logger, schema: schema}
+func InitSQLite3(path string, schema uint, logger *log.Logger, secret []byte, initialAdminName string, initialAdminPassword string) *CustomDB {
+ initTimeStamp = int(time.Now().Unix())
+ db := CustomDB{logger: logger, schema: schema, secret: secret}
var err error
db.connection, err = sql.Open("sqlite3", "file:"+path+"?_foreign_keys=1")
@@ -58,6 +60,10 @@ func InitSQLite3(path string, schema uint, logger *log.Logger) *CustomDB {
if err = db.createSQLite3Tables(); err != nil {
db.logger.Fatalln("Error in creating table: ", err)
}
+ err = db.CreateInitialAdmin(initialAdminName, initialAdminPassword)
+ if err != nil {
+ db.logger.Fatal("failed to create initial admin. Try to fix and delete old database file: ", err)
+ }
case user_version > db.schema:
db.logger.Fatalln("Incompatible database schema version. Try updating this software.")
case user_version < db.schema:
@@ -71,8 +77,11 @@ func (db CustomDB) createSQLite3Tables() error {
name string
sql string
}{
- {"User", "userId INTEGER PRIMARY KEY NOT NULL, userName VARCHAR NOT NULL UNIQUE, fullName VARCHAR"},
- {"Todo", "todoId INTEGER PRIMARY KEY NOT NULL, text VARCHAR NOT NULL, IS_done BOOL NOT NULL DEFAULT false, FK_User_userId INTEGER NOT NULL, FOREIGN KEY(FK_User_userId) REFERENCES User(userId) ON UPDATE CASCADE ON DELETE CASCADE"},
+ {"User", "userId INTEGER PRIMARY KEY NOT NULL, userName VARCHAR NOT NULL UNIQUE CHECK(length(userName)!=0), passwordHash VARCHAR NOT NULL CHECK(length(passwordHash)!=0), fullName VARCHAR CHECK(length(fullName)!=0)"},
+ {"Todo", "todoId INTEGER PRIMARY KEY NOT NULL, text VARCHAR NOT NULL CHECK(length(text)!=0), IS_done BOOL NOT NULL, FK_User_userId INTEGER NOT NULL, FOREIGN KEY(FK_User_userId) REFERENCES User(userId) ON UPDATE CASCADE ON DELETE CASCADE"},
+ {"R_User_Role", "relationId INTEGER PRIMARY KEY NOT NULL, FK_Role_roleId INTEGER NOT NULL, FK_User_userId INTEGER NOT NULL, UNIQUE(FK_Role_roleId, FK_User_userId), FOREIGN KEY(FK_Role_roleId) REFERENCES Role(roleId) ON UPDATE CASCADE ON DELETE CASCADE, FOREIGN KEY(FK_User_userId) REFERENCES User(userId) ON UPDATE CASCADE ON DELETE CASCADE"},
+ {"Role", "roleId INTEGER PRIMARY KEY NOT NULL, roleName VARCHAR NOT NULL UNIQUE CHECK(length(roleName)!=0), IS_admin BOOL NOT NULL, IS_userCreator BOOL NOT NULL"},
+ {"RefreshToken", "tokenId INTEGER PRIMARY KEY NOT NULL, FK_User_userId INTEGER NOT NULL, selector VARCHAR NOT NULL CHECK(length(selector)!=0) UNIQUE, tokenHash VARCHAR NOT NULL CHECK(length(tokenHash)!=0), expiryDate INTEGER NOT NULL, tokenName VARCHAR CHECK(length(tokenName)!=0), FOREIGN KEY(FK_User_userId) REFERENCES User(userId) ON UPDATE CASCADE ON DELETE CASCADE"},
}
for _, table := range tables {
_, err := db.connection.Exec("CREATE TABLE IF NOT EXISTS " + table.name + " (" + table.sql + ")")
@@ -91,262 +100,18 @@ func (db CustomDB) createSQLite3Tables() error {
return nil
}
-func (db CustomDB) GetUser(user *model.User) (*model.User, error) {
- id, err := strconv.Atoi(user.ID)
+func (db CustomDB) CreateInitialAdmin(initialAdminName string, initialAdminPassword string) error {
+ role, err := db.CreateRole(&model.NewRole{RoleName: "admin", IsAdmin: true, IsUserCreator: true})
if err != nil {
- return nil, errors.New("invalid userId")
+ return err
}
- statement, err := db.connection.Prepare("SELECT userName, fullName FROM User WHERE userId = ?")
+ user, err := db.CreateUser(model.NewUser{UserName: initialAdminName, Password: initialAdminPassword})
if err != nil {
- return nil, err
+ return err
}
-
- result := statement.QueryRow(id)
- if err := result.Scan(&user.UserName, &user.FullName); err != nil {
- return nil, err
+ _, err = db.AddRole(user.ID, role.ID)
+ if err != nil {
+ return err
}
-
- return user, nil
-}
-
-func (db CustomDB) GetTodo(todo *model.Todo) (*model.Todo, error) {
- id, err := strconv.Atoi(todo.ID)
- if err != nil {
- return nil, errors.New("invalid todoId")
- }
- statement, err := db.connection.Prepare("SELECT text, IS_done FROM Todo WHERE todoId = ?")
- if err != nil {
- return nil, err
- }
-
- result := statement.QueryRow(id)
- if err := result.Scan(&todo.Text, &todo.Done); err != nil {
- return nil, err
- }
-
- return todo, nil
-}
-
-func (db CustomDB) GetTodosFrom(user *model.User) ([]*model.Todo, error) {
- id, err := strconv.Atoi(user.ID)
- if err != nil {
- return nil, errors.New("invalid userId")
- }
- statement, err := db.connection.Prepare("SELECT todoId, text, IS_done FROM Todo WHERE FK_User_userId = ?")
- if err != nil {
- return nil, err
- }
-
- rows, err := statement.Query(id)
- if err != nil {
- return nil, err
- }
-
- defer rows.Close()
-
- var all []*model.Todo
- for rows.Next() {
- todo := model.Todo{User: user}
- if err := rows.Scan(&todo.ID, &todo.Text, &todo.Done); err != nil {
- return nil, err
- }
- all = append(all, &todo)
- }
- return all, nil
-}
-
-func (db CustomDB) GetAllUsers() ([]*model.User, error) {
- rows, err := db.connection.Query("SELECT userId, userName, fullName FROM User")
- if err != nil {
- return nil, err
- }
-
- defer rows.Close()
-
- var all []*model.User
- for rows.Next() {
- var user model.User
- if err := rows.Scan(&user.ID, &user.UserName, &user.FullName); err != nil {
- return nil, err
- }
- all = append(all, &user)
- }
- return all, nil
-}
-
-func (db CustomDB) GetAllTodos() ([]*model.Todo, error) {
- rows, err := db.connection.Query("SELECT Todo.todoID, Todo.text, Todo.IS_done, User.userID FROM Todo INNER JOIN User ON Todo.FK_User_userID=User.userID")
- if err != nil {
- return nil, err
- }
-
- defer rows.Close()
-
- var todos []*model.Todo
- for rows.Next() {
- var todo = model.Todo{User: &model.User{}}
- if err := rows.Scan(&todo.ID, &todo.Text, &todo.Done, &todo.User.ID); err != nil {
- return nil, err
- }
- todos = append(todos, &todo)
- }
- return todos, nil
-}
-
-func (db CustomDB) AddUser(newUser model.NewUser) (*model.User, error) {
- statement, err := db.connection.Prepare("INSERT INTO User (userName, fullName) VALUES (?, ?)")
- if err != nil {
- return nil, err
- }
-
- rows, err := statement.Exec(newUser.UserName, newUser.FullName)
- if err != nil {
- return nil, err
- }
-
- num, err := rows.RowsAffected()
- if err != nil {
- return nil, err
- }
-
- if num < 1 {
- return nil, errors.New("no rows affected")
- }
-
- insertId, err := rows.LastInsertId()
- if err != nil {
- return nil, err
- }
- return &model.User{ID: strconv.FormatInt(insertId, 10), UserName: newUser.UserName, FullName: newUser.FullName}, nil
-}
-
-func (db CustomDB) AddTodo(newTodo model.NewTodo) (*model.Todo, error) {
- statement, err := db.connection.Prepare("INSERT INTO Todo (text, FK_User_userID) VALUES (?, ?)")
- if err != nil {
- return nil, err
- }
-
- rows, err := statement.Exec(newTodo.Text, newTodo.UserID)
- if err != nil {
- return nil, err
- }
-
- num, err := rows.RowsAffected()
- if err != nil {
- return nil, err
- }
-
- if num < 1 {
- return nil, errors.New("no rows affected")
- }
-
- insertId, err := rows.LastInsertId()
- if err != nil {
- return nil, err
- }
- return &model.Todo{ID: strconv.FormatInt(insertId, 10), Text: newTodo.Text, Done: false}, nil
-}
-
-func (db CustomDB) UpdateUser(userId string, changes *model.UpdateUser) (*model.User, error) {
-
- id, err := strconv.Atoi(userId)
- if err != nil {
- return nil, errors.New("invalid userId")
- }
-
- statement, err := db.connection.Prepare("UPDATE User SET userName = IFNULL(?, userName), fullName = IFNULL(?, fullName) WHERE userId = ?")
- if err != nil {
- return nil, err
- }
-
- rows, err := statement.Exec(changes.UserName, changes.FullName, id)
- if err != nil {
- return nil, err
- }
-
- num, err := rows.RowsAffected()
- if err != nil {
- return nil, err
- }
-
- if num < 1 {
- return nil, errors.New("no rows affected")
- }
-
- return db.GetUser(&model.User{ID: userId})
-}
-
-func (db CustomDB) UpdateTodo(todoId string, changes *model.UpdateTodo) (*model.Todo, error) {
-
- id, err := strconv.Atoi(todoId)
- if err != nil {
- return nil, errors.New("invalid userId")
- }
-
- statement, err := db.connection.Prepare("UPDATE Todo SET text = IFNULL(?, text), IS_done = IFNULL(?, IS_done) WHERE todoId = ?")
- if err != nil {
- return nil, err
- }
-
- rows, err := statement.Exec(changes.Text, changes.Done, id)
- if err != nil {
- return nil, err
- }
-
- num, err := rows.RowsAffected()
- if err != nil {
- return nil, err
- }
-
- if num < 1 {
- return nil, errors.New("no rows affected")
- }
-
- return db.GetTodo(&model.Todo{ID: todoId})
-}
-
-func (db CustomDB) DeleteUser(userId string) (*string, error) {
- statement, err := db.connection.Prepare("DELETE FROM User WHERE userId = ?")
- if err != nil {
- return nil, err
- }
-
- rows, err := statement.Exec(userId)
- if err != nil {
- return nil, err
- }
-
- num, err := rows.RowsAffected()
- if err != nil {
- return nil, err
- }
-
- if num < 1 {
- return nil, errors.New("no rows affected")
- }
-
- return &userId, nil
-}
-
-func (db CustomDB) DeleteTodo(todoId string) (*string, error) {
- statement, err := db.connection.Prepare("DELETE FROM Todo WHERE todoId = ?")
- if err != nil {
- return nil, err
- }
-
- rows, err := statement.Exec(todoId)
- if err != nil {
- return nil, err
- }
-
- num, err := rows.RowsAffected()
- if err != nil {
- return nil, err
- }
-
- if num < 1 {
- return nil, errors.New("no rows affected")
- }
-
- return &todoId, nil
+ return nil
}
diff --git a/database/role.go b/database/role.go
new file mode 100644
index 0000000..02f2580
--- /dev/null
+++ b/database/role.go
@@ -0,0 +1,168 @@
+/*
+YetAnotherToDoList
+Copyright © 2023 gilex-dev gilex-dev@proton.me
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 3.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+package database
+
+import (
+ "errors"
+ "strconv"
+
+ "somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/graph/model"
+)
+
+func (db CustomDB) CreateRole(newRole *model.NewRole) (role *model.Role, err error) {
+ statement, err := db.connection.Prepare("INSERT INTO Role (roleName, IS_admin, IS_userCreator) VALUES (?, ?, ?)")
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := statement.Exec(newRole.RoleName, newRole.IsAdmin, newRole.IsUserCreator)
+ if err != nil {
+ return nil, err
+ }
+
+ num, err := rows.RowsAffected()
+ if err != nil {
+ return nil, err
+ }
+
+ if num < 1 {
+ return nil, errors.New("no rows affected")
+ }
+
+ insertId, err := rows.LastInsertId()
+ if err != nil {
+ return nil, err
+ }
+ return &model.Role{ID: strconv.FormatInt(insertId, 10), RoleName: newRole.RoleName, IsAdmin: newRole.IsAdmin, IsUserCreator: newRole.IsUserCreator}, nil
+}
+
+func (db CustomDB) GetRole(role *model.Role) (*model.Role, error) {
+ id, err := strconv.Atoi(role.ID)
+ if err != nil {
+ return nil, errors.New("invalid roleId")
+ }
+ statement, err := db.connection.Prepare("SELECT roleName, IS_admin, IS_userCreator FROM Role WHERE roleId = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ result := statement.QueryRow(id)
+ if err := result.Scan(&role.RoleName, &role.IsAdmin, &role.IsUserCreator); err != nil {
+ return nil, err
+ }
+
+ return role, nil
+}
+
+func (db CustomDB) GetRolesFrom(userId string) ([]*model.Role, error) {
+ numUserId, err := strconv.Atoi(userId)
+ if err != nil {
+ return nil, errors.New("invalid userId")
+ }
+ statement, err := db.connection.Prepare("SELECT Role.roleId, Role.roleName, Role.IS_admin, Role.IS_userCreator FROM Role INNER JOIN R_User_Role ON R_User_Role.FK_Role_roleId = Role.roleId WHERE R_User_Role.FK_User_userId = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := statement.Query(numUserId)
+ if err != nil {
+ return nil, err
+ }
+
+ defer rows.Close()
+
+ var all []*model.Role
+ for rows.Next() {
+ role := model.Role{}
+ if err := rows.Scan(&role.ID, &role.RoleName, &role.IsAdmin, &role.IsUserCreator); err != nil {
+ return nil, err
+ }
+ all = append(all, &role)
+ }
+ return all, nil
+}
+
+func (db CustomDB) GetAllRoles() ([]*model.Role, error) {
+ rows, err := db.connection.Query("SELECT roleId, roleName, IS_admin, IS_userCreator FROM Role")
+ if err != nil {
+ return nil, err
+ }
+
+ defer rows.Close()
+
+ var all []*model.Role
+ for rows.Next() {
+ var role model.Role
+ if err := rows.Scan(&role.ID, &role.RoleName, &role.IsAdmin, &role.IsUserCreator); err != nil {
+ return nil, err
+ }
+ all = append(all, &role)
+ }
+ return all, nil
+}
+
+func (db CustomDB) UpdateRole(roleId string, changes *model.UpdateRole) (*model.Role, error) {
+
+ id, err := strconv.Atoi(roleId)
+ if err != nil {
+ return nil, errors.New("invalid userId")
+ }
+
+ statement, err := db.connection.Prepare("UPDATE Role SET roleName = IFNULL(?, roleName), IS_admin = IFNULL(?, IS_admin), IS_userCreator = IFNULL(?, IS_userCreator) WHERE roleId = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := statement.Exec(changes.RoleName, changes.IsAdmin, changes.IsUserCreator, id)
+ if err != nil {
+ return nil, err
+ }
+
+ num, err := rows.RowsAffected()
+ if err != nil {
+ return nil, err
+ }
+
+ if num < 1 {
+ return nil, errors.New("no rows affected")
+ }
+
+ return db.GetRole(&model.Role{ID: roleId})
+}
+
+func (db CustomDB) DeleteRole(roleId string) (*string, error) {
+ statement, err := db.connection.Prepare("DELETE FROM Role WHERE roleId = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := statement.Exec(roleId)
+ if err != nil {
+ return nil, err
+ }
+
+ num, err := rows.RowsAffected()
+ if err != nil {
+ return nil, err
+ }
+
+ if num < 1 {
+ return nil, errors.New("no rows affected")
+ }
+
+ return &roleId, nil
+}
diff --git a/database/todo.go b/database/todo.go
new file mode 100644
index 0000000..9fed4a7
--- /dev/null
+++ b/database/todo.go
@@ -0,0 +1,199 @@
+/*
+YetAnotherToDoList
+Copyright © 2023 gilex-dev gilex-dev@proton.me
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 3.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+package database
+
+import (
+ "errors"
+ "strconv"
+
+ "somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/graph/model"
+)
+
+// GetOwner takes a todoId and return the owner's userId. Call before Update/Get/DeleteTodo when not IS_admin.
+func (db CustomDB) GetOwner(todoId string) (string, error) {
+ numTodoId, err := strconv.Atoi(todoId)
+ if err != nil {
+ return "", errors.New("invalid todoId")
+ }
+
+ statement, err := db.connection.Prepare("SELECT FK_User_userId, FROM Todo WHERE todoId = ?")
+ if err != nil {
+ return "", err
+ }
+
+ result := statement.QueryRow(numTodoId)
+ var owner string
+ if err := result.Scan(&owner); err != nil {
+ return "", err
+ }
+
+ return owner, nil
+}
+
+// GetTodo takes a *model.Todo with at least ID set and adds the missing fields.
+func (db CustomDB) GetTodo(todo *model.Todo) (*model.Todo, error) {
+ numTodoId, err := strconv.Atoi(todo.ID)
+ if err != nil {
+ return nil, errors.New("invalid todoId")
+ }
+
+ statement, err := db.connection.Prepare("SELECT text, IS_done FROM Todo WHERE todoId = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ result := statement.QueryRow(numTodoId)
+ if err := result.Scan(&todo.Text, &todo.Done); err != nil {
+ return nil, err
+ }
+
+ return todo, nil
+}
+
+// GetTodosFrom gets all todos from the passed *model.User. ID must be set.
+func (db CustomDB) GetTodosFrom(user *model.User) ([]*model.Todo, error) {
+ id, err := strconv.Atoi(user.ID)
+ if err != nil {
+ return nil, errors.New("invalid userId")
+ }
+ statement, err := db.connection.Prepare("SELECT todoId, text, IS_done FROM Todo WHERE FK_User_userId = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := statement.Query(id)
+ if err != nil {
+ return nil, err
+ }
+
+ defer rows.Close()
+
+ var all []*model.Todo
+ for rows.Next() {
+ todo := model.Todo{User: user}
+ if err := rows.Scan(&todo.ID, &todo.Text, &todo.Done); err != nil {
+ return nil, err
+ }
+ all = append(all, &todo)
+ }
+ return all, nil
+}
+
+// GetAllTodos gets all todos from the database. Check if the source has the rights to call this.
+func (db CustomDB) GetAllTodos() ([]*model.Todo, error) {
+ rows, err := db.connection.Query("SELECT todoID, text, IS_done, FK_User_userID FROM Todo")
+ if err != nil {
+ return nil, err
+ }
+
+ defer rows.Close()
+
+ var todos []*model.Todo
+ for rows.Next() {
+ var todo = model.Todo{User: &model.User{}}
+ if err := rows.Scan(&todo.ID, &todo.Text, &todo.Done, &todo.User.ID); err != nil {
+ return nil, err
+ }
+ todos = append(todos, &todo)
+ }
+ return todos, nil
+}
+
+// AddTodo adds a Todo to passed UserID. Check if the source has the rights to call this.
+func (db CustomDB) AddTodo(newTodo model.NewTodo) (*model.Todo, error) {
+ statement, err := db.connection.Prepare("INSERT INTO Todo (text, FK_User_userID) VALUES (?, ?)")
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := statement.Exec(newTodo.Text, newTodo.UserID)
+ if err != nil {
+ return nil, err
+ }
+
+ num, err := rows.RowsAffected()
+ if err != nil {
+ return nil, err
+ }
+
+ if num < 1 {
+ return nil, errors.New("no rows affected")
+ }
+
+ insertId, err := rows.LastInsertId()
+ if err != nil {
+ return nil, err
+ }
+ return &model.Todo{ID: strconv.FormatInt(insertId, 10), Text: newTodo.Text, Done: false}, nil
+}
+
+func (db CustomDB) UpdateTodo(todoId string, changes *model.UpdateTodo) (*model.Todo, error) {
+
+ numTodoId, err := strconv.Atoi(todoId)
+ if err != nil {
+ return nil, errors.New("invalid todoId")
+ }
+
+ statement, err := db.connection.Prepare("UPDATE Todo SET text = IFNULL(?, text), IS_done = IFNULL(?, IS_done) WHERE todoId = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := statement.Exec(changes.Text, changes.Done, numTodoId)
+ if err != nil {
+ return nil, err
+ }
+
+ num, err := rows.RowsAffected()
+ if err != nil {
+ return nil, err
+ }
+
+ if num < 1 {
+ return nil, errors.New("no rows affected")
+ }
+
+ return db.GetTodo(&model.Todo{ID: todoId})
+}
+
+func (db CustomDB) DeleteTodo(todoId string) (deletedTodoId *string, err error) {
+ numTodoId, err := strconv.Atoi(todoId)
+ if err != nil {
+ return nil, errors.New("invalid todoId")
+ }
+
+ statement, err := db.connection.Prepare("DELETE FROM Todo WHERE todoId = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := statement.Exec(numTodoId)
+ if err != nil {
+ return nil, err
+ }
+
+ num, err := rows.RowsAffected()
+ if err != nil {
+ return nil, err
+ }
+
+ if num < 1 {
+ return nil, errors.New("no rows affected")
+ }
+
+ return &todoId, nil
+}
diff --git a/database/user.go b/database/user.go
new file mode 100644
index 0000000..e070b92
--- /dev/null
+++ b/database/user.go
@@ -0,0 +1,257 @@
+/*
+YetAnotherToDoList
+Copyright © 2023 gilex-dev gilex-dev@proton.me
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 3.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+package database
+
+import (
+ "errors"
+ "strconv"
+ "time"
+
+ "somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/graph/model"
+)
+
+func (db CustomDB) CreateUser(newUser model.NewUser) (*model.User, error) {
+ statement, err := db.connection.Prepare("INSERT INTO User (userName, fullName, passwordHash) VALUES (?, NULLIF(?, ''), ?)")
+ if err != nil {
+ return nil, err
+ }
+
+ if ValidateUserName(newUser.UserName); err != nil {
+ return nil, err
+ }
+
+ if ValidatePassword(newUser.Password); err != nil {
+ return nil, err
+ }
+
+ passwordHash, err := db.GenerateHashFromPassword(newUser.Password)
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := statement.Exec(newUser.UserName, newUser.FullName, string(passwordHash))
+ if err != nil {
+ return nil, err
+ }
+
+ num, err := rows.RowsAffected()
+ if err != nil {
+ return nil, err
+ }
+
+ if num < 1 {
+ return nil, errors.New("no rows affected")
+ }
+
+ insertId, err := rows.LastInsertId()
+ if err != nil {
+ return nil, err
+ }
+ return &model.User{ID: strconv.FormatInt(insertId, 10), UserName: newUser.UserName, FullName: newUser.FullName}, nil
+}
+
+// GetUser takes a *model.User with at least ID or UserName set and adds the missing fields.
+func (db CustomDB) GetUser(user *model.User) (*model.User, error) {
+ numUserId, err := strconv.Atoi(user.ID)
+ if err != nil {
+ return nil, errors.New("invalid userId")
+ }
+ statement, err := db.connection.Prepare("SELECT userID, userName, fullName FROM User WHERE userId = ? OR userName = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ result := statement.QueryRow(numUserId, user.UserName)
+ if err := result.Scan(&user.ID, &user.UserName, &user.FullName); err != nil {
+ return nil, err
+ }
+
+ return user, nil
+}
+
+func (db CustomDB) GetAllUsers() ([]*model.User, error) {
+ rows, err := db.connection.Query("SELECT userId, userName, fullName FROM User")
+ if err != nil {
+ return nil, err
+ }
+
+ defer rows.Close()
+
+ var all []*model.User
+ for rows.Next() {
+ var user model.User
+ if err := rows.Scan(&user.ID, &user.UserName, &user.FullName); err != nil {
+ return nil, err
+ }
+ all = append(all, &user)
+ }
+ return all, nil
+}
+
+func (db CustomDB) UpdateUser(userId string, changes *model.UpdateUser) (*model.User, error) {
+ var passwordHash *string
+ needAccessTokenRefresh := false
+
+ id, err := strconv.Atoi(userId)
+ if err != nil {
+ return nil, errors.New("invalid userId")
+ }
+
+ statement, err := db.connection.Prepare("UPDATE User SET userName = IFNULL(?, userName), fullName = IFNULL(NULLIF(?, ''), fullName), passwordHash = IFNULL(?, passwordHash) WHERE userId = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ if *changes.UserName == "" { // interpret empty string as nil
+ changes.UserName = nil
+ } else {
+ if err := ValidateUserName(*changes.UserName); err != nil {
+ return nil, err
+ }
+ needAccessTokenRefresh = true
+ }
+
+ if *changes.Password == "" { // interpret empty string as nil
+ passwordHash = nil
+ } else {
+ if err := ValidatePassword(*changes.Password); err != nil {
+ return nil, err
+ }
+ passwordHashByte, err := db.GenerateHashFromPassword(*changes.Password)
+ if err != nil {
+ return nil, err
+ }
+ passwordHashString := string(passwordHashByte)
+ passwordHash = &passwordHashString
+ needAccessTokenRefresh = true
+ }
+
+ rows, err := statement.Exec(changes.UserName, changes.FullName, passwordHash, id)
+ if err != nil {
+ return nil, err
+ }
+
+ num, err := rows.RowsAffected()
+ if err != nil {
+ return nil, err
+ }
+
+ if num < 1 {
+ return nil, errors.New("no rows affected")
+ }
+
+ if needAccessTokenRefresh {
+ RevokeAccessToken(&AccessToken{UserId: userId, ExpiryDate: int(time.Now().Add(accessTokenLifetime).Unix())})
+ }
+
+ return db.GetUser(&model.User{ID: userId})
+}
+
+func (db CustomDB) DeleteUser(userId string) (*string, error) {
+ statement, err := db.connection.Prepare("DELETE FROM User WHERE userId = ?")
+ if err != nil {
+ return nil, err
+ }
+
+ rows, err := statement.Exec(userId)
+ if err != nil {
+ return nil, err
+ }
+
+ num, err := rows.RowsAffected()
+ if err != nil {
+ return nil, err
+ }
+
+ if num < 1 {
+ return nil, errors.New("no rows affected")
+ }
+
+ RevokeAccessToken(&AccessToken{UserId: userId, ExpiryDate: int(time.Now().Add(accessTokenLifetime).Unix())})
+ return &userId, nil
+}
+
+func (db CustomDB) AddRole(userId string, roleId string) (relationId string, err error) {
+ encUserId, err := strconv.Atoi(userId)
+ if err != nil {
+ return "", errors.New("invalid userId")
+ }
+ encRoleId, err := strconv.Atoi(roleId)
+ if err != nil {
+ return "", errors.New("invalid roleId")
+ }
+
+ statement, err := db.connection.Prepare("INSERT INTO R_User_Role (FK_User_userId, FK_Role_roleId) VALUES (?, ?)")
+ if err != nil {
+ return "", err
+ }
+
+ rows, err := statement.Exec(encUserId, encRoleId)
+ if err != nil {
+ return "", err
+ }
+
+ num, err := rows.RowsAffected()
+ if err != nil {
+ return "", err
+ }
+
+ if num < 1 {
+ return "", errors.New("no rows affected")
+ }
+
+ insertId, err := rows.LastInsertId()
+ if err != nil {
+ return "", err
+ }
+
+ RevokeAccessToken(&AccessToken{UserId: userId, ExpiryDate: int(time.Now().Add(accessTokenLifetime).Unix())})
+ return strconv.FormatInt(insertId, 10), nil
+}
+
+func (db CustomDB) RemoveRole(userId string, roleId string) (relationId string, err error) {
+ encUserId, err := strconv.Atoi(userId)
+ if err != nil {
+ return "", errors.New("invalid userId")
+ }
+ encRoleId, err := strconv.Atoi(roleId)
+ if err != nil {
+ return "", errors.New("invalid roleId")
+ }
+
+ statement, err := db.connection.Prepare("DELETE FROM R_User_Role WHERE FK_User_userId = ? AND FK_Role_roleId = ?")
+ if err != nil {
+ return "", err
+ }
+
+ rows, err := statement.Exec(encUserId, encRoleId)
+ if err != nil {
+ return "", err
+ }
+
+ num, err := rows.RowsAffected()
+ if err != nil {
+ return "", err
+ }
+
+ if num < 1 {
+ return "", errors.New("no rows affected")
+ }
+
+ RevokeAccessToken(&AccessToken{UserId: userId, ExpiryDate: int(time.Now().Add(accessTokenLifetime).Unix())})
+ return strconv.FormatInt(int64(encRoleId), 10), nil
+}
diff --git a/frontend/vite.config.js b/frontend/vite.config.js
index 1d7aae1..c63427c 100644
--- a/frontend/vite.config.js
+++ b/frontend/vite.config.js
@@ -7,7 +7,7 @@ export default defineConfig({
server: {
port: 4243,
proxy: {
- '^/(api|playground|version)': 'http://localhost:4242/'
+ '^/(api|playground|version|auth)': 'http://localhost:4242/'
}
},
build: {
diff --git a/go.mod b/go.mod
index df39274..5e4a8b8 100644
--- a/go.mod
+++ b/go.mod
@@ -4,10 +4,12 @@ go 1.20
require (
github.com/99designs/gqlgen v0.17.37
+ github.com/go-chi/chi v1.5.5
github.com/mattn/go-sqlite3 v1.14.17
github.com/spf13/cobra v1.7.0
github.com/spf13/viper v1.16.0
github.com/vektah/gqlparser/v2 v2.5.9
+ golang.org/x/crypto v0.9.0
)
require (
diff --git a/go.sum b/go.sum
index 3dc942d..7c8f422 100644
--- a/go.sum
+++ b/go.sum
@@ -69,6 +69,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/go-chi/chi v1.5.5 h1:vOB/HbEMt9QqBqErz07QehcOKHaWFtuj87tTDVz2qXE=
+github.com/go-chi/chi v1.5.5/go.mod h1:C9JqLr3tIYjDOZpzn+BCuxY8z8vmca43EeMgyZt7irw=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -216,6 +218,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
+golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
diff --git a/gqlgen.yaml b/gqlgen.yaml
index 58104b4..4b077a1 100644
--- a/gqlgen.yaml
+++ b/gqlgen.yaml
@@ -108,3 +108,5 @@ models:
fields:
todos:
resolver: true
+ roles:
+ resolver: true
diff --git a/graph/generated.go b/graph/generated.go
index 84e3619..bbc3c6f 100644
--- a/graph/generated.go
+++ b/graph/generated.go
@@ -48,19 +48,47 @@ type DirectiveRoot struct {
type ComplexityRoot struct {
Mutation struct {
- CreateTodo func(childComplexity int, input model.NewTodo) int
- CreateUser func(childComplexity int, input model.NewUser) int
- DeleteTodo func(childComplexity int, id string) int
- DeleteUser func(childComplexity int, id string) int
- UpdateTodo func(childComplexity int, id string, changes model.UpdateTodo) int
- UpdateUser func(childComplexity int, id string, changes model.UpdateUser) int
+ AddRole func(childComplexity int, userID string, roleID string) int
+ CreateRefreshToken func(childComplexity int, input model.NewRefreshToken) int
+ CreateRole func(childComplexity int, input model.NewRole) int
+ CreateTodo func(childComplexity int, input model.NewTodo) int
+ CreateUser func(childComplexity int, input model.NewUser) int
+ DeleteRefreshToken func(childComplexity int, id string) int
+ DeleteRole func(childComplexity int, id string) int
+ DeleteTodo func(childComplexity int, id string) int
+ DeleteUser func(childComplexity int, id string) int
+ RemoveRole func(childComplexity int, userID string, roleID string) int
+ UpdateRefreshToken func(childComplexity int, id string, changes model.UpdateRefreshToken) int
+ UpdateRole func(childComplexity int, id string, changes model.UpdateRole) int
+ UpdateTodo func(childComplexity int, id string, changes model.UpdateTodo) int
+ UpdateUser func(childComplexity int, id string, changes model.UpdateUser) int
}
Query struct {
- Todo func(childComplexity int, id string) int
- Todos func(childComplexity int) int
- User func(childComplexity int, id string) int
- Users func(childComplexity int) int
+ RefreshToken func(childComplexity int, id string) int
+ RefreshTokens func(childComplexity int) int
+ Role func(childComplexity int, id string) int
+ Roles func(childComplexity int) int
+ Todo func(childComplexity int, id string) int
+ Todos func(childComplexity int) int
+ User func(childComplexity int, id string) int
+ Users func(childComplexity int) int
+ }
+
+ RefreshToken struct {
+ ExpiryDate func(childComplexity int) int
+ ID func(childComplexity int) int
+ Selector func(childComplexity int) int
+ Token func(childComplexity int) int
+ TokenName func(childComplexity int) int
+ UserID func(childComplexity int) int
+ }
+
+ Role struct {
+ ID func(childComplexity int) int
+ IsAdmin func(childComplexity int) int
+ IsUserCreator func(childComplexity int) int
+ RoleName func(childComplexity int) int
}
Todo struct {
@@ -73,6 +101,7 @@ type ComplexityRoot struct {
User struct {
FullName func(childComplexity int) int
ID func(childComplexity int) int
+ Roles func(childComplexity int) int
Todos func(childComplexity int) int
UserName func(childComplexity int) int
}
@@ -81,22 +110,35 @@ type ComplexityRoot struct {
type MutationResolver interface {
CreateUser(ctx context.Context, input model.NewUser) (*model.User, error)
CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error)
+ CreateRole(ctx context.Context, input model.NewRole) (*model.Role, error)
+ CreateRefreshToken(ctx context.Context, input model.NewRefreshToken) (*model.RefreshToken, error)
UpdateTodo(ctx context.Context, id string, changes model.UpdateTodo) (*model.Todo, error)
UpdateUser(ctx context.Context, id string, changes model.UpdateUser) (*model.User, error)
+ UpdateRole(ctx context.Context, id string, changes model.UpdateRole) (*model.Role, error)
+ UpdateRefreshToken(ctx context.Context, id string, changes model.UpdateRefreshToken) (*model.RefreshToken, error)
DeleteUser(ctx context.Context, id string) (*string, error)
DeleteTodo(ctx context.Context, id string) (*string, error)
+ DeleteRole(ctx context.Context, id string) (*string, error)
+ DeleteRefreshToken(ctx context.Context, id string) (*string, error)
+ AddRole(ctx context.Context, userID string, roleID string) ([]*model.Role, error)
+ RemoveRole(ctx context.Context, userID string, roleID string) ([]*model.Role, error)
}
type QueryResolver interface {
Todos(ctx context.Context) ([]*model.Todo, error)
Users(ctx context.Context) ([]*model.User, error)
+ Roles(ctx context.Context) ([]*model.Role, error)
+ RefreshTokens(ctx context.Context) ([]*model.RefreshToken, error)
User(ctx context.Context, id string) (*model.User, error)
Todo(ctx context.Context, id string) (*model.Todo, error)
+ Role(ctx context.Context, id string) (*model.Role, error)
+ RefreshToken(ctx context.Context, id string) (*model.RefreshToken, error)
}
type TodoResolver interface {
User(ctx context.Context, obj *model.Todo) (*model.User, error)
}
type UserResolver interface {
Todos(ctx context.Context, obj *model.User) ([]*model.Todo, error)
+ Roles(ctx context.Context, obj *model.User) ([]*model.Role, error)
}
type executableSchema struct {
@@ -114,6 +156,42 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
_ = ec
switch typeName + "." + field {
+ case "Mutation.addRole":
+ if e.complexity.Mutation.AddRole == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation_addRole_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.AddRole(childComplexity, args["userId"].(string), args["roleId"].(string)), true
+
+ case "Mutation.createRefreshToken":
+ if e.complexity.Mutation.CreateRefreshToken == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation_createRefreshToken_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.CreateRefreshToken(childComplexity, args["input"].(model.NewRefreshToken)), true
+
+ case "Mutation.createRole":
+ if e.complexity.Mutation.CreateRole == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation_createRole_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.CreateRole(childComplexity, args["input"].(model.NewRole)), true
+
case "Mutation.createTodo":
if e.complexity.Mutation.CreateTodo == nil {
break
@@ -138,6 +216,30 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.CreateUser(childComplexity, args["input"].(model.NewUser)), true
+ case "Mutation.deleteRefreshToken":
+ if e.complexity.Mutation.DeleteRefreshToken == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation_deleteRefreshToken_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.DeleteRefreshToken(childComplexity, args["id"].(string)), true
+
+ case "Mutation.deleteRole":
+ if e.complexity.Mutation.DeleteRole == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation_deleteRole_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.DeleteRole(childComplexity, args["id"].(string)), true
+
case "Mutation.deleteTodo":
if e.complexity.Mutation.DeleteTodo == nil {
break
@@ -162,6 +264,42 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.DeleteUser(childComplexity, args["id"].(string)), true
+ case "Mutation.removeRole":
+ if e.complexity.Mutation.RemoveRole == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation_removeRole_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.RemoveRole(childComplexity, args["userId"].(string), args["roleId"].(string)), true
+
+ case "Mutation.updateRefreshToken":
+ if e.complexity.Mutation.UpdateRefreshToken == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation_updateRefreshToken_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.UpdateRefreshToken(childComplexity, args["id"].(string), args["changes"].(model.UpdateRefreshToken)), true
+
+ case "Mutation.updateRole":
+ if e.complexity.Mutation.UpdateRole == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation_updateRole_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.UpdateRole(childComplexity, args["id"].(string), args["changes"].(model.UpdateRole)), true
+
case "Mutation.updateTodo":
if e.complexity.Mutation.UpdateTodo == nil {
break
@@ -186,6 +324,44 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.UpdateUser(childComplexity, args["id"].(string), args["changes"].(model.UpdateUser)), true
+ case "Query.refreshToken":
+ if e.complexity.Query.RefreshToken == nil {
+ break
+ }
+
+ args, err := ec.field_Query_refreshToken_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Query.RefreshToken(childComplexity, args["id"].(string)), true
+
+ case "Query.refreshTokens":
+ if e.complexity.Query.RefreshTokens == nil {
+ break
+ }
+
+ return e.complexity.Query.RefreshTokens(childComplexity), true
+
+ case "Query.role":
+ if e.complexity.Query.Role == nil {
+ break
+ }
+
+ args, err := ec.field_Query_role_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Query.Role(childComplexity, args["id"].(string)), true
+
+ case "Query.roles":
+ if e.complexity.Query.Roles == nil {
+ break
+ }
+
+ return e.complexity.Query.Roles(childComplexity), true
+
case "Query.todo":
if e.complexity.Query.Todo == nil {
break
@@ -224,6 +400,76 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Query.Users(childComplexity), true
+ case "RefreshToken.expiryDate":
+ if e.complexity.RefreshToken.ExpiryDate == nil {
+ break
+ }
+
+ return e.complexity.RefreshToken.ExpiryDate(childComplexity), true
+
+ case "RefreshToken.id":
+ if e.complexity.RefreshToken.ID == nil {
+ break
+ }
+
+ return e.complexity.RefreshToken.ID(childComplexity), true
+
+ case "RefreshToken.selector":
+ if e.complexity.RefreshToken.Selector == nil {
+ break
+ }
+
+ return e.complexity.RefreshToken.Selector(childComplexity), true
+
+ case "RefreshToken.token":
+ if e.complexity.RefreshToken.Token == nil {
+ break
+ }
+
+ return e.complexity.RefreshToken.Token(childComplexity), true
+
+ case "RefreshToken.tokenName":
+ if e.complexity.RefreshToken.TokenName == nil {
+ break
+ }
+
+ return e.complexity.RefreshToken.TokenName(childComplexity), true
+
+ case "RefreshToken.userId":
+ if e.complexity.RefreshToken.UserID == nil {
+ break
+ }
+
+ return e.complexity.RefreshToken.UserID(childComplexity), true
+
+ case "Role.id":
+ if e.complexity.Role.ID == nil {
+ break
+ }
+
+ return e.complexity.Role.ID(childComplexity), true
+
+ case "Role.isAdmin":
+ if e.complexity.Role.IsAdmin == nil {
+ break
+ }
+
+ return e.complexity.Role.IsAdmin(childComplexity), true
+
+ case "Role.isUserCreator":
+ if e.complexity.Role.IsUserCreator == nil {
+ break
+ }
+
+ return e.complexity.Role.IsUserCreator(childComplexity), true
+
+ case "Role.roleName":
+ if e.complexity.Role.RoleName == nil {
+ break
+ }
+
+ return e.complexity.Role.RoleName(childComplexity), true
+
case "Todo.done":
if e.complexity.Todo.Done == nil {
break
@@ -266,6 +512,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.User.ID(childComplexity), true
+ case "User.roles":
+ if e.complexity.User.Roles == nil {
+ break
+ }
+
+ return e.complexity.User.Roles(childComplexity), true
+
case "User.todos":
if e.complexity.User.Todos == nil {
break
@@ -288,10 +541,14 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
rc := graphql.GetOperationContext(ctx)
ec := executionContext{rc, e, 0, 0, make(chan graphql.DeferredResult)}
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
+ ec.unmarshalInputNewRefreshToken,
+ ec.unmarshalInputNewRole,
ec.unmarshalInputNewTodo,
ec.unmarshalInputNewUser,
- ec.unmarshalInputupdateTodo,
- ec.unmarshalInputupdateUser,
+ ec.unmarshalInputUpdateRefreshToken,
+ ec.unmarshalInputUpdateRole,
+ ec.unmarshalInputUpdateTodo,
+ ec.unmarshalInputUpdateUser,
)
first := true
@@ -408,6 +665,60 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...)
// region ***************************** args.gotpl *****************************
+func (ec *executionContext) field_Mutation_addRole_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["userId"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("userId"))
+ arg0, err = ec.unmarshalNID2string(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["userId"] = arg0
+ var arg1 string
+ if tmp, ok := rawArgs["roleId"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("roleId"))
+ arg1, err = ec.unmarshalNID2string(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["roleId"] = arg1
+ return args, nil
+}
+
+func (ec *executionContext) field_Mutation_createRefreshToken_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
+ var err error
+ args := map[string]interface{}{}
+ var arg0 model.NewRefreshToken
+ if tmp, ok := rawArgs["input"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
+ arg0, err = ec.unmarshalNNewRefreshToken2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐNewRefreshToken(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["input"] = arg0
+ return args, nil
+}
+
+func (ec *executionContext) field_Mutation_createRole_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
+ var err error
+ args := map[string]interface{}{}
+ var arg0 model.NewRole
+ if tmp, ok := rawArgs["input"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
+ arg0, err = ec.unmarshalNNewRole2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐNewRole(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["input"] = arg0
+ return args, nil
+}
+
func (ec *executionContext) field_Mutation_createTodo_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
@@ -438,6 +749,36 @@ func (ec *executionContext) field_Mutation_createUser_args(ctx context.Context,
return args, nil
}
+func (ec *executionContext) field_Mutation_deleteRefreshToken_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["id"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
+ arg0, err = ec.unmarshalNID2string(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["id"] = arg0
+ return args, nil
+}
+
+func (ec *executionContext) field_Mutation_deleteRole_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["id"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
+ arg0, err = ec.unmarshalNID2string(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["id"] = arg0
+ return args, nil
+}
+
func (ec *executionContext) field_Mutation_deleteTodo_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
@@ -468,6 +809,78 @@ func (ec *executionContext) field_Mutation_deleteUser_args(ctx context.Context,
return args, nil
}
+func (ec *executionContext) field_Mutation_removeRole_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["userId"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("userId"))
+ arg0, err = ec.unmarshalNID2string(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["userId"] = arg0
+ var arg1 string
+ if tmp, ok := rawArgs["roleId"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("roleId"))
+ arg1, err = ec.unmarshalNID2string(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["roleId"] = arg1
+ return args, nil
+}
+
+func (ec *executionContext) field_Mutation_updateRefreshToken_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["id"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
+ arg0, err = ec.unmarshalNID2string(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["id"] = arg0
+ var arg1 model.UpdateRefreshToken
+ if tmp, ok := rawArgs["changes"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("changes"))
+ arg1, err = ec.unmarshalNUpdateRefreshToken2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐUpdateRefreshToken(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["changes"] = arg1
+ return args, nil
+}
+
+func (ec *executionContext) field_Mutation_updateRole_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["id"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
+ arg0, err = ec.unmarshalNID2string(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["id"] = arg0
+ var arg1 model.UpdateRole
+ if tmp, ok := rawArgs["changes"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("changes"))
+ arg1, err = ec.unmarshalNUpdateRole2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐUpdateRole(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["changes"] = arg1
+ return args, nil
+}
+
func (ec *executionContext) field_Mutation_updateTodo_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
@@ -483,7 +896,7 @@ func (ec *executionContext) field_Mutation_updateTodo_args(ctx context.Context,
var arg1 model.UpdateTodo
if tmp, ok := rawArgs["changes"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("changes"))
- arg1, err = ec.unmarshalNupdateTodo2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐUpdateTodo(ctx, tmp)
+ arg1, err = ec.unmarshalNUpdateTodo2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐUpdateTodo(ctx, tmp)
if err != nil {
return nil, err
}
@@ -507,7 +920,7 @@ func (ec *executionContext) field_Mutation_updateUser_args(ctx context.Context,
var arg1 model.UpdateUser
if tmp, ok := rawArgs["changes"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("changes"))
- arg1, err = ec.unmarshalNupdateUser2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐUpdateUser(ctx, tmp)
+ arg1, err = ec.unmarshalNUpdateUser2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐUpdateUser(ctx, tmp)
if err != nil {
return nil, err
}
@@ -531,6 +944,36 @@ func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs
return args, nil
}
+func (ec *executionContext) field_Query_refreshToken_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["id"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
+ arg0, err = ec.unmarshalNID2string(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["id"] = arg0
+ return args, nil
+}
+
+func (ec *executionContext) field_Query_role_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["id"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
+ arg0, err = ec.unmarshalNID2string(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["id"] = arg0
+ return args, nil
+}
+
func (ec *executionContext) field_Query_todo_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
@@ -646,6 +1089,8 @@ func (ec *executionContext) fieldContext_Mutation_createUser(ctx context.Context
return ec.fieldContext_User_fullName(ctx, field)
case "todos":
return ec.fieldContext_User_todos(ctx, field)
+ case "roles":
+ return ec.fieldContext_User_roles(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type User", field.Name)
},
@@ -729,6 +1174,140 @@ func (ec *executionContext) fieldContext_Mutation_createTodo(ctx context.Context
return fc, nil
}
+func (ec *executionContext) _Mutation_createRole(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Mutation_createRole(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().CreateRole(rctx, fc.Args["input"].(model.NewRole))
+ })
+ 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.Role)
+ fc.Result = res
+ return ec.marshalNRole2ᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRole(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Mutation_createRole(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "id":
+ return ec.fieldContext_Role_id(ctx, field)
+ case "roleName":
+ return ec.fieldContext_Role_roleName(ctx, field)
+ case "isAdmin":
+ return ec.fieldContext_Role_isAdmin(ctx, field)
+ case "isUserCreator":
+ return ec.fieldContext_Role_isUserCreator(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type Role", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Mutation_createRole_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Mutation_createRefreshToken(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Mutation_createRefreshToken(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().CreateRefreshToken(rctx, fc.Args["input"].(model.NewRefreshToken))
+ })
+ 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.RefreshToken)
+ fc.Result = res
+ return ec.marshalNRefreshToken2ᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRefreshToken(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Mutation_createRefreshToken(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "id":
+ return ec.fieldContext_RefreshToken_id(ctx, field)
+ case "expiryDate":
+ return ec.fieldContext_RefreshToken_expiryDate(ctx, field)
+ case "tokenName":
+ return ec.fieldContext_RefreshToken_tokenName(ctx, field)
+ case "selector":
+ return ec.fieldContext_RefreshToken_selector(ctx, field)
+ case "token":
+ return ec.fieldContext_RefreshToken_token(ctx, field)
+ case "userId":
+ return ec.fieldContext_RefreshToken_userId(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type RefreshToken", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Mutation_createRefreshToken_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
func (ec *executionContext) _Mutation_updateTodo(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_updateTodo(ctx, field)
if err != nil {
@@ -841,6 +1420,8 @@ func (ec *executionContext) fieldContext_Mutation_updateUser(ctx context.Context
return ec.fieldContext_User_fullName(ctx, field)
case "todos":
return ec.fieldContext_User_todos(ctx, field)
+ case "roles":
+ return ec.fieldContext_User_roles(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type User", field.Name)
},
@@ -859,6 +1440,140 @@ func (ec *executionContext) fieldContext_Mutation_updateUser(ctx context.Context
return fc, nil
}
+func (ec *executionContext) _Mutation_updateRole(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Mutation_updateRole(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().UpdateRole(rctx, fc.Args["id"].(string), fc.Args["changes"].(model.UpdateRole))
+ })
+ 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.Role)
+ fc.Result = res
+ return ec.marshalNRole2ᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRole(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Mutation_updateRole(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "id":
+ return ec.fieldContext_Role_id(ctx, field)
+ case "roleName":
+ return ec.fieldContext_Role_roleName(ctx, field)
+ case "isAdmin":
+ return ec.fieldContext_Role_isAdmin(ctx, field)
+ case "isUserCreator":
+ return ec.fieldContext_Role_isUserCreator(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type Role", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Mutation_updateRole_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Mutation_updateRefreshToken(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Mutation_updateRefreshToken(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().UpdateRefreshToken(rctx, fc.Args["id"].(string), fc.Args["changes"].(model.UpdateRefreshToken))
+ })
+ 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.RefreshToken)
+ fc.Result = res
+ return ec.marshalNRefreshToken2ᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRefreshToken(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Mutation_updateRefreshToken(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "id":
+ return ec.fieldContext_RefreshToken_id(ctx, field)
+ case "expiryDate":
+ return ec.fieldContext_RefreshToken_expiryDate(ctx, field)
+ case "tokenName":
+ return ec.fieldContext_RefreshToken_tokenName(ctx, field)
+ case "selector":
+ return ec.fieldContext_RefreshToken_selector(ctx, field)
+ case "token":
+ return ec.fieldContext_RefreshToken_token(ctx, field)
+ case "userId":
+ return ec.fieldContext_RefreshToken_userId(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type RefreshToken", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Mutation_updateRefreshToken_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
func (ec *executionContext) _Mutation_deleteUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_deleteUser(ctx, field)
if err != nil {
@@ -963,6 +1678,240 @@ func (ec *executionContext) fieldContext_Mutation_deleteTodo(ctx context.Context
return fc, nil
}
+func (ec *executionContext) _Mutation_deleteRole(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Mutation_deleteRole(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().DeleteRole(rctx, fc.Args["id"].(string))
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOID2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Mutation_deleteRole(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type ID does not have child fields")
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Mutation_deleteRole_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Mutation_deleteRefreshToken(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Mutation_deleteRefreshToken(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().DeleteRefreshToken(rctx, fc.Args["id"].(string))
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOID2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Mutation_deleteRefreshToken(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type ID does not have child fields")
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Mutation_deleteRefreshToken_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Mutation_addRole(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Mutation_addRole(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().AddRole(rctx, fc.Args["userId"].(string), fc.Args["roleId"].(string))
+ })
+ 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.Role)
+ fc.Result = res
+ return ec.marshalNRole2ᚕᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRoleᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Mutation_addRole(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "id":
+ return ec.fieldContext_Role_id(ctx, field)
+ case "roleName":
+ return ec.fieldContext_Role_roleName(ctx, field)
+ case "isAdmin":
+ return ec.fieldContext_Role_isAdmin(ctx, field)
+ case "isUserCreator":
+ return ec.fieldContext_Role_isUserCreator(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type Role", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Mutation_addRole_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Mutation_removeRole(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Mutation_removeRole(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().RemoveRole(rctx, fc.Args["userId"].(string), fc.Args["roleId"].(string))
+ })
+ 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.Role)
+ fc.Result = res
+ return ec.marshalNRole2ᚕᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRoleᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Mutation_removeRole(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "id":
+ return ec.fieldContext_Role_id(ctx, field)
+ case "roleName":
+ return ec.fieldContext_Role_roleName(ctx, field)
+ case "isAdmin":
+ return ec.fieldContext_Role_isAdmin(ctx, field)
+ case "isUserCreator":
+ return ec.fieldContext_Role_isUserCreator(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type Role", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Mutation_removeRole_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
func (ec *executionContext) _Query_todos(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Query_todos(ctx, field)
if err != nil {
@@ -1064,6 +2013,8 @@ func (ec *executionContext) fieldContext_Query_users(ctx context.Context, field
return ec.fieldContext_User_fullName(ctx, field)
case "todos":
return ec.fieldContext_User_todos(ctx, field)
+ case "roles":
+ return ec.fieldContext_User_roles(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type User", field.Name)
},
@@ -1071,6 +2022,118 @@ func (ec *executionContext) fieldContext_Query_users(ctx context.Context, field
return fc, nil
}
+func (ec *executionContext) _Query_roles(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Query_roles(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Query().Roles(rctx)
+ })
+ 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.Role)
+ fc.Result = res
+ return ec.marshalNRole2ᚕᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRoleᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Query_roles(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Query",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "id":
+ return ec.fieldContext_Role_id(ctx, field)
+ case "roleName":
+ return ec.fieldContext_Role_roleName(ctx, field)
+ case "isAdmin":
+ return ec.fieldContext_Role_isAdmin(ctx, field)
+ case "isUserCreator":
+ return ec.fieldContext_Role_isUserCreator(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type Role", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Query_refreshTokens(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Query_refreshTokens(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Query().RefreshTokens(rctx)
+ })
+ 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.RefreshToken)
+ fc.Result = res
+ return ec.marshalNRefreshToken2ᚕᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRefreshTokenᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Query_refreshTokens(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Query",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "id":
+ return ec.fieldContext_RefreshToken_id(ctx, field)
+ case "expiryDate":
+ return ec.fieldContext_RefreshToken_expiryDate(ctx, field)
+ case "tokenName":
+ return ec.fieldContext_RefreshToken_tokenName(ctx, field)
+ case "selector":
+ return ec.fieldContext_RefreshToken_selector(ctx, field)
+ case "token":
+ return ec.fieldContext_RefreshToken_token(ctx, field)
+ case "userId":
+ return ec.fieldContext_RefreshToken_userId(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type RefreshToken", field.Name)
+ },
+ }
+ return fc, nil
+}
+
func (ec *executionContext) _Query_user(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Query_user(ctx, field)
if err != nil {
@@ -1118,6 +2181,8 @@ func (ec *executionContext) fieldContext_Query_user(ctx context.Context, field g
return ec.fieldContext_User_fullName(ctx, field)
case "todos":
return ec.fieldContext_User_todos(ctx, field)
+ case "roles":
+ return ec.fieldContext_User_roles(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type User", field.Name)
},
@@ -1201,6 +2266,140 @@ func (ec *executionContext) fieldContext_Query_todo(ctx context.Context, field g
return fc, nil
}
+func (ec *executionContext) _Query_role(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Query_role(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Query().Role(rctx, fc.Args["id"].(string))
+ })
+ 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.Role)
+ fc.Result = res
+ return ec.marshalNRole2ᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRole(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Query_role(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Query",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "id":
+ return ec.fieldContext_Role_id(ctx, field)
+ case "roleName":
+ return ec.fieldContext_Role_roleName(ctx, field)
+ case "isAdmin":
+ return ec.fieldContext_Role_isAdmin(ctx, field)
+ case "isUserCreator":
+ return ec.fieldContext_Role_isUserCreator(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type Role", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Query_role_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Query_refreshToken(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Query_refreshToken(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Query().RefreshToken(rctx, fc.Args["id"].(string))
+ })
+ 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.RefreshToken)
+ fc.Result = res
+ return ec.marshalNRefreshToken2ᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRefreshToken(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Query_refreshToken(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Query",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "id":
+ return ec.fieldContext_RefreshToken_id(ctx, field)
+ case "expiryDate":
+ return ec.fieldContext_RefreshToken_expiryDate(ctx, field)
+ case "tokenName":
+ return ec.fieldContext_RefreshToken_tokenName(ctx, field)
+ case "selector":
+ return ec.fieldContext_RefreshToken_selector(ctx, field)
+ case "token":
+ return ec.fieldContext_RefreshToken_token(ctx, field)
+ case "userId":
+ return ec.fieldContext_RefreshToken_userId(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type RefreshToken", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Query_refreshToken_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Query___type(ctx, field)
if err != nil {
@@ -1330,6 +2529,437 @@ func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, fie
return fc, nil
}
+func (ec *executionContext) _RefreshToken_id(ctx context.Context, field graphql.CollectedField, obj *model.RefreshToken) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_RefreshToken_id(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.ID, nil
+ })
+ 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.(string)
+ fc.Result = res
+ return ec.marshalNID2string(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_RefreshToken_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "RefreshToken",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type ID does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _RefreshToken_expiryDate(ctx context.Context, field graphql.CollectedField, obj *model.RefreshToken) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_RefreshToken_expiryDate(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.ExpiryDate, nil
+ })
+ 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.(int)
+ fc.Result = res
+ return ec.marshalNInt2int(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_RefreshToken_expiryDate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "RefreshToken",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type Int does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _RefreshToken_tokenName(ctx context.Context, field graphql.CollectedField, obj *model.RefreshToken) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_RefreshToken_tokenName(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.TokenName, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_RefreshToken_tokenName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "RefreshToken",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _RefreshToken_selector(ctx context.Context, field graphql.CollectedField, obj *model.RefreshToken) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_RefreshToken_selector(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Selector, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_RefreshToken_selector(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "RefreshToken",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _RefreshToken_token(ctx context.Context, field graphql.CollectedField, obj *model.RefreshToken) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_RefreshToken_token(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Token, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_RefreshToken_token(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "RefreshToken",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _RefreshToken_userId(ctx context.Context, field graphql.CollectedField, obj *model.RefreshToken) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_RefreshToken_userId(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.UserID, nil
+ })
+ 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.(string)
+ fc.Result = res
+ return ec.marshalNString2string(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_RefreshToken_userId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "RefreshToken",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Role_id(ctx context.Context, field graphql.CollectedField, obj *model.Role) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Role_id(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.ID, nil
+ })
+ 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.(string)
+ fc.Result = res
+ return ec.marshalNID2string(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Role_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Role",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type ID does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Role_roleName(ctx context.Context, field graphql.CollectedField, obj *model.Role) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Role_roleName(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.RoleName, nil
+ })
+ 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.(string)
+ fc.Result = res
+ return ec.marshalNString2string(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Role_roleName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Role",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Role_isAdmin(ctx context.Context, field graphql.CollectedField, obj *model.Role) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Role_isAdmin(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.IsAdmin, nil
+ })
+ 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.(bool)
+ fc.Result = res
+ return ec.marshalNBoolean2bool(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Role_isAdmin(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Role",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type Boolean does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Role_isUserCreator(ctx context.Context, field graphql.CollectedField, obj *model.Role) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Role_isUserCreator(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.IsUserCreator, nil
+ })
+ 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.(bool)
+ fc.Result = res
+ return ec.marshalNBoolean2bool(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Role_isUserCreator(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Role",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type Boolean does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
func (ec *executionContext) _Todo_id(ctx context.Context, field graphql.CollectedField, obj *model.Todo) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Todo_id(ctx, field)
if err != nil {
@@ -1509,6 +3139,8 @@ func (ec *executionContext) fieldContext_Todo_user(ctx context.Context, field gr
return ec.fieldContext_User_fullName(ctx, field)
case "todos":
return ec.fieldContext_User_todos(ctx, field)
+ case "roles":
+ return ec.fieldContext_User_roles(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type User", field.Name)
},
@@ -1625,14 +3257,11 @@ func (ec *executionContext) _User_fullName(ctx context.Context, field graphql.Co
return graphql.Null
}
if resTmp == nil {
- if !graphql.HasFieldError(ctx, fc) {
- ec.Errorf(ctx, "must not be null")
- }
return graphql.Null
}
- res := resTmp.(string)
+ res := resTmp.(*string)
fc.Result = res
- return ec.marshalNString2string(ctx, field.Selections, res)
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_User_fullName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@@ -1702,6 +3331,60 @@ func (ec *executionContext) fieldContext_User_todos(ctx context.Context, field g
return fc, nil
}
+func (ec *executionContext) _User_roles(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_User_roles(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.User().Roles(rctx, obj)
+ })
+ 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.Role)
+ fc.Result = res
+ return ec.marshalNRole2ᚕᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRoleᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_User_roles(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "User",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "id":
+ return ec.fieldContext_Role_id(ctx, field)
+ case "roleName":
+ return ec.fieldContext_Role_roleName(ctx, field)
+ case "isAdmin":
+ return ec.fieldContext_Role_isAdmin(ctx, field)
+ case "isUserCreator":
+ return ec.fieldContext_Role_isUserCreator(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type Role", field.Name)
+ },
+ }
+ return fc, nil
+}
+
func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {
fc, err := ec.fieldContext___Directive_name(ctx, field)
if err != nil {
@@ -3475,6 +5158,82 @@ func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Conte
// region **************************** input.gotpl *****************************
+func (ec *executionContext) unmarshalInputNewRefreshToken(ctx context.Context, obj interface{}) (model.NewRefreshToken, error) {
+ var it model.NewRefreshToken
+ asMap := map[string]interface{}{}
+ for k, v := range obj.(map[string]interface{}) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"tokenName"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "tokenName":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tokenName"))
+ data, err := ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.TokenName = data
+ }
+ }
+
+ return it, nil
+}
+
+func (ec *executionContext) unmarshalInputNewRole(ctx context.Context, obj interface{}) (model.NewRole, error) {
+ var it model.NewRole
+ asMap := map[string]interface{}{}
+ for k, v := range obj.(map[string]interface{}) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"roleName", "isAdmin", "isUserCreator"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "roleName":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("roleName"))
+ data, err := ec.unmarshalNString2string(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.RoleName = data
+ case "isAdmin":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isAdmin"))
+ data, err := ec.unmarshalNBoolean2bool(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.IsAdmin = data
+ case "isUserCreator":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isUserCreator"))
+ data, err := ec.unmarshalNBoolean2bool(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.IsUserCreator = data
+ }
+ }
+
+ return it, nil
+}
+
func (ec *executionContext) unmarshalInputNewTodo(ctx context.Context, obj interface{}) (model.NewTodo, error) {
var it model.NewTodo
asMap := map[string]interface{}{}
@@ -3520,7 +5279,7 @@ func (ec *executionContext) unmarshalInputNewUser(ctx context.Context, obj inter
asMap[k] = v
}
- fieldsInOrder := [...]string{"userName", "fullName"}
+ fieldsInOrder := [...]string{"userName", "fullName", "password"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
@@ -3540,18 +5299,103 @@ func (ec *executionContext) unmarshalInputNewUser(ctx context.Context, obj inter
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("fullName"))
- data, err := ec.unmarshalNString2string(ctx, v)
+ data, err := ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
it.FullName = data
+ case "password":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password"))
+ data, err := ec.unmarshalNString2string(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.Password = data
}
}
return it, nil
}
-func (ec *executionContext) unmarshalInputupdateTodo(ctx context.Context, obj interface{}) (model.UpdateTodo, error) {
+func (ec *executionContext) unmarshalInputUpdateRefreshToken(ctx context.Context, obj interface{}) (model.UpdateRefreshToken, error) {
+ var it model.UpdateRefreshToken
+ asMap := map[string]interface{}{}
+ for k, v := range obj.(map[string]interface{}) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"tokenName"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "tokenName":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tokenName"))
+ data, err := ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.TokenName = data
+ }
+ }
+
+ return it, nil
+}
+
+func (ec *executionContext) unmarshalInputUpdateRole(ctx context.Context, obj interface{}) (model.UpdateRole, error) {
+ var it model.UpdateRole
+ asMap := map[string]interface{}{}
+ for k, v := range obj.(map[string]interface{}) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"roleName", "isAdmin", "isUserCreator"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "roleName":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("roleName"))
+ data, err := ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.RoleName = data
+ case "isAdmin":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isAdmin"))
+ data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.IsAdmin = data
+ case "isUserCreator":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isUserCreator"))
+ data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.IsUserCreator = data
+ }
+ }
+
+ return it, nil
+}
+
+func (ec *executionContext) unmarshalInputUpdateTodo(ctx context.Context, obj interface{}) (model.UpdateTodo, error) {
var it model.UpdateTodo
asMap := map[string]interface{}{}
for k, v := range obj.(map[string]interface{}) {
@@ -3589,14 +5433,14 @@ func (ec *executionContext) unmarshalInputupdateTodo(ctx context.Context, obj in
return it, nil
}
-func (ec *executionContext) unmarshalInputupdateUser(ctx context.Context, obj interface{}) (model.UpdateUser, error) {
+func (ec *executionContext) unmarshalInputUpdateUser(ctx context.Context, obj interface{}) (model.UpdateUser, error) {
var it model.UpdateUser
asMap := map[string]interface{}{}
for k, v := range obj.(map[string]interface{}) {
asMap[k] = v
}
- fieldsInOrder := [...]string{"userName", "fullName"}
+ fieldsInOrder := [...]string{"userName", "fullName", "password"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
@@ -3621,6 +5465,15 @@ func (ec *executionContext) unmarshalInputupdateUser(ctx context.Context, obj in
return it, err
}
it.FullName = data
+ case "password":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password"))
+ data, err := ec.unmarshalOString2ᚖstring(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.Password = data
}
}
@@ -3668,6 +5521,20 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
out.Invalids++
}
+ case "createRole":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Mutation_createRole(ctx, field)
+ })
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "createRefreshToken":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Mutation_createRefreshToken(ctx, field)
+ })
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
case "updateTodo":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_updateTodo(ctx, field)
@@ -3682,6 +5549,20 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
out.Invalids++
}
+ case "updateRole":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Mutation_updateRole(ctx, field)
+ })
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "updateRefreshToken":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Mutation_updateRefreshToken(ctx, field)
+ })
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
case "deleteUser":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_deleteUser(ctx, field)
@@ -3690,6 +5571,28 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_deleteTodo(ctx, field)
})
+ case "deleteRole":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Mutation_deleteRole(ctx, field)
+ })
+ case "deleteRefreshToken":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Mutation_deleteRefreshToken(ctx, field)
+ })
+ case "addRole":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Mutation_addRole(ctx, field)
+ })
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "removeRole":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Mutation_removeRole(ctx, field)
+ })
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
default:
panic("unknown field " + strconv.Quote(field.Name))
}
@@ -3775,6 +5678,50 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
}
+ out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
+ case "roles":
+ field := field
+
+ innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ }
+ }()
+ res = ec._Query_roles(ctx, field)
+ if res == graphql.Null {
+ atomic.AddUint32(&fs.Invalids, 1)
+ }
+ return res
+ }
+
+ rrm := func(ctx context.Context) graphql.Marshaler {
+ return ec.OperationContext.RootResolverMiddleware(ctx,
+ func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
+ }
+
+ out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
+ case "refreshTokens":
+ field := field
+
+ innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ }
+ }()
+ res = ec._Query_refreshTokens(ctx, field)
+ if res == graphql.Null {
+ atomic.AddUint32(&fs.Invalids, 1)
+ }
+ return res
+ }
+
+ rrm := func(ctx context.Context) graphql.Marshaler {
+ return ec.OperationContext.RootResolverMiddleware(ctx,
+ func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
+ }
+
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
case "user":
field := field
@@ -3819,6 +5766,50 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
}
+ out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
+ case "role":
+ field := field
+
+ innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ }
+ }()
+ res = ec._Query_role(ctx, field)
+ if res == graphql.Null {
+ atomic.AddUint32(&fs.Invalids, 1)
+ }
+ return res
+ }
+
+ rrm := func(ctx context.Context) graphql.Marshaler {
+ return ec.OperationContext.RootResolverMiddleware(ctx,
+ func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
+ }
+
+ out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
+ case "refreshToken":
+ field := field
+
+ innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ }
+ }()
+ res = ec._Query_refreshToken(ctx, field)
+ if res == graphql.Null {
+ atomic.AddUint32(&fs.Invalids, 1)
+ }
+ return res
+ }
+
+ rrm := func(ctx context.Context) graphql.Marshaler {
+ return ec.OperationContext.RootResolverMiddleware(ctx,
+ func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
+ }
+
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
case "__type":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
@@ -3851,6 +5842,115 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
return out
}
+var refreshTokenImplementors = []string{"RefreshToken"}
+
+func (ec *executionContext) _RefreshToken(ctx context.Context, sel ast.SelectionSet, obj *model.RefreshToken) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, refreshTokenImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ deferred := make(map[string]*graphql.FieldSet)
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("RefreshToken")
+ case "id":
+ out.Values[i] = ec._RefreshToken_id(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "expiryDate":
+ out.Values[i] = ec._RefreshToken_expiryDate(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "tokenName":
+ out.Values[i] = ec._RefreshToken_tokenName(ctx, field, obj)
+ case "selector":
+ out.Values[i] = ec._RefreshToken_selector(ctx, field, obj)
+ case "token":
+ out.Values[i] = ec._RefreshToken_token(ctx, field, obj)
+ case "userId":
+ out.Values[i] = ec._RefreshToken_userId(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch(ctx)
+ if out.Invalids > 0 {
+ return graphql.Null
+ }
+
+ atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+ for label, dfs := range deferred {
+ ec.processDeferredGroup(graphql.DeferredGroup{
+ Label: label,
+ Path: graphql.GetPath(ctx),
+ FieldSet: dfs,
+ Context: ctx,
+ })
+ }
+
+ return out
+}
+
+var roleImplementors = []string{"Role"}
+
+func (ec *executionContext) _Role(ctx context.Context, sel ast.SelectionSet, obj *model.Role) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, roleImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ deferred := make(map[string]*graphql.FieldSet)
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("Role")
+ case "id":
+ out.Values[i] = ec._Role_id(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "roleName":
+ out.Values[i] = ec._Role_roleName(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "isAdmin":
+ out.Values[i] = ec._Role_isAdmin(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "isUserCreator":
+ out.Values[i] = ec._Role_isUserCreator(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch(ctx)
+ if out.Invalids > 0 {
+ return graphql.Null
+ }
+
+ atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+ for label, dfs := range deferred {
+ ec.processDeferredGroup(graphql.DeferredGroup{
+ Label: label,
+ Path: graphql.GetPath(ctx),
+ FieldSet: dfs,
+ Context: ctx,
+ })
+ }
+
+ return out
+}
+
var todoImplementors = []string{"Todo"}
func (ec *executionContext) _Todo(ctx context.Context, sel ast.SelectionSet, obj *model.Todo) graphql.Marshaler {
@@ -3959,9 +6059,6 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj
}
case "fullName":
out.Values[i] = ec._User_fullName(ctx, field, obj)
- if out.Values[i] == graphql.Null {
- atomic.AddUint32(&out.Invalids, 1)
- }
case "todos":
field := field
@@ -3997,6 +6094,42 @@ func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj
continue
}
+ out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
+ case "roles":
+ field := field
+
+ innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ }
+ }()
+ res = ec._User_roles(ctx, field, obj)
+ if res == graphql.Null {
+ atomic.AddUint32(&fs.Invalids, 1)
+ }
+ return res
+ }
+
+ if field.Deferrable != nil {
+ dfs, ok := deferred[field.Deferrable.Label]
+ di := 0
+ if ok {
+ dfs.AddField(field)
+ di = len(dfs.Values) - 1
+ } else {
+ dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
+ deferred[field.Deferrable.Label] = dfs
+ }
+ dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
+ return innerFunc(ctx, dfs)
+ })
+
+ // don't run the out.Concurrently() call below
+ out.Values[i] = graphql.Null
+ continue
+ }
+
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
default:
panic("unknown field " + strconv.Quote(field.Name))
@@ -4377,6 +6510,31 @@ func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.Selec
return res
}
+func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v interface{}) (int, error) {
+ res, err := graphql.UnmarshalInt(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler {
+ res := graphql.MarshalInt(v)
+ if res == graphql.Null {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "the requested element is null which the schema does not allow")
+ }
+ }
+ return res
+}
+
+func (ec *executionContext) unmarshalNNewRefreshToken2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐNewRefreshToken(ctx context.Context, v interface{}) (model.NewRefreshToken, error) {
+ res, err := ec.unmarshalInputNewRefreshToken(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) unmarshalNNewRole2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐNewRole(ctx context.Context, v interface{}) (model.NewRole, error) {
+ res, err := ec.unmarshalInputNewRole(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
func (ec *executionContext) unmarshalNNewTodo2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐNewTodo(ctx context.Context, v interface{}) (model.NewTodo, error) {
res, err := ec.unmarshalInputNewTodo(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
@@ -4387,6 +6545,122 @@ func (ec *executionContext) unmarshalNNewUser2somepiᚗddnsᚗnetᚋgiteaᚋgile
return res, graphql.ErrorOnPath(ctx, err)
}
+func (ec *executionContext) marshalNRefreshToken2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRefreshToken(ctx context.Context, sel ast.SelectionSet, v model.RefreshToken) graphql.Marshaler {
+ return ec._RefreshToken(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalNRefreshToken2ᚕᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRefreshTokenᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.RefreshToken) graphql.Marshaler {
+ 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.marshalNRefreshToken2ᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRefreshToken(ctx, sel, v[i])
+ }
+ if isLen1 {
+ f(i)
+ } else {
+ go f(i)
+ }
+
+ }
+ wg.Wait()
+
+ for _, e := range ret {
+ if e == graphql.Null {
+ return graphql.Null
+ }
+ }
+
+ return ret
+}
+
+func (ec *executionContext) marshalNRefreshToken2ᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRefreshToken(ctx context.Context, sel ast.SelectionSet, v *model.RefreshToken) graphql.Marshaler {
+ if v == nil {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "the requested element is null which the schema does not allow")
+ }
+ return graphql.Null
+ }
+ return ec._RefreshToken(ctx, sel, v)
+}
+
+func (ec *executionContext) marshalNRole2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRole(ctx context.Context, sel ast.SelectionSet, v model.Role) graphql.Marshaler {
+ return ec._Role(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalNRole2ᚕᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRoleᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Role) graphql.Marshaler {
+ 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.marshalNRole2ᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRole(ctx, sel, v[i])
+ }
+ if isLen1 {
+ f(i)
+ } else {
+ go f(i)
+ }
+
+ }
+ wg.Wait()
+
+ for _, e := range ret {
+ if e == graphql.Null {
+ return graphql.Null
+ }
+ }
+
+ return ret
+}
+
+func (ec *executionContext) marshalNRole2ᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐRole(ctx context.Context, sel ast.SelectionSet, v *model.Role) graphql.Marshaler {
+ if v == nil {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "the requested element is null which the schema does not allow")
+ }
+ return graphql.Null
+ }
+ return ec._Role(ctx, sel, v)
+}
+
func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) {
res, err := graphql.UnmarshalString(v)
return res, graphql.ErrorOnPath(ctx, err)
@@ -4460,6 +6734,26 @@ func (ec *executionContext) marshalNTodo2ᚖsomepiᚗddnsᚗnetᚋgiteaᚋgilex
return ec._Todo(ctx, sel, v)
}
+func (ec *executionContext) unmarshalNUpdateRefreshToken2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐUpdateRefreshToken(ctx context.Context, v interface{}) (model.UpdateRefreshToken, error) {
+ res, err := ec.unmarshalInputUpdateRefreshToken(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) unmarshalNUpdateRole2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐUpdateRole(ctx context.Context, v interface{}) (model.UpdateRole, error) {
+ res, err := ec.unmarshalInputUpdateRole(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) unmarshalNUpdateTodo2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐUpdateTodo(ctx context.Context, v interface{}) (model.UpdateTodo, error) {
+ res, err := ec.unmarshalInputUpdateTodo(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) unmarshalNUpdateUser2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐUpdateUser(ctx context.Context, v interface{}) (model.UpdateUser, error) {
+ res, err := ec.unmarshalInputUpdateUser(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
func (ec *executionContext) marshalNUser2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v model.User) graphql.Marshaler {
return ec._User(ctx, sel, &v)
}
@@ -4771,16 +7065,6 @@ func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel a
return res
}
-func (ec *executionContext) unmarshalNupdateTodo2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐUpdateTodo(ctx context.Context, v interface{}) (model.UpdateTodo, error) {
- res, err := ec.unmarshalInputupdateTodo(ctx, v)
- return res, graphql.ErrorOnPath(ctx, err)
-}
-
-func (ec *executionContext) unmarshalNupdateUser2somepiᚗddnsᚗnetᚋgiteaᚋgilexᚑdevᚋYetAnotherToDoListᚋgraphᚋmodelᚐUpdateUser(ctx context.Context, v interface{}) (model.UpdateUser, error) {
- res, err := ec.unmarshalInputupdateUser(ctx, v)
- return res, graphql.ErrorOnPath(ctx, err)
-}
-
func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) {
res, err := graphql.UnmarshalBoolean(v)
return res, graphql.ErrorOnPath(ctx, err)
diff --git a/graph/model/models_gen.go b/graph/model/models_gen.go
index 54d59ab..7c27260 100644
--- a/graph/model/models_gen.go
+++ b/graph/model/models_gen.go
@@ -2,21 +2,51 @@
package model
+type NewRefreshToken struct {
+ TokenName *string `json:"tokenName,omitempty"`
+}
+
+type NewRole struct {
+ RoleName string `json:"roleName"`
+ IsAdmin bool `json:"isAdmin"`
+ IsUserCreator bool `json:"isUserCreator"`
+}
+
type NewTodo struct {
Text string `json:"text"`
UserID string `json:"userId"`
}
type NewUser struct {
- UserName string `json:"userName"`
- FullName string `json:"fullName"`
+ UserName string `json:"userName"`
+ FullName *string `json:"fullName,omitempty"`
+ Password string `json:"password"`
}
-type User struct {
- ID string `json:"id"`
- UserName string `json:"userName"`
- FullName string `json:"fullName"`
- Todos []*Todo `json:"todos"`
+type RefreshToken struct {
+ ID string `json:"id"`
+ ExpiryDate int `json:"expiryDate"`
+ TokenName *string `json:"tokenName,omitempty"`
+ Selector *string `json:"selector,omitempty"`
+ Token *string `json:"token,omitempty"`
+ UserID string `json:"userId"`
+}
+
+type Role struct {
+ ID string `json:"id"`
+ RoleName string `json:"roleName"`
+ IsAdmin bool `json:"isAdmin"`
+ IsUserCreator bool `json:"isUserCreator"`
+}
+
+type UpdateRefreshToken struct {
+ TokenName *string `json:"tokenName,omitempty"`
+}
+
+type UpdateRole struct {
+ RoleName *string `json:"roleName,omitempty"`
+ IsAdmin *bool `json:"isAdmin,omitempty"`
+ IsUserCreator *bool `json:"isUserCreator,omitempty"`
}
type UpdateTodo struct {
@@ -27,4 +57,13 @@ type UpdateTodo struct {
type UpdateUser struct {
UserName *string `json:"userName,omitempty"`
FullName *string `json:"fullName,omitempty"`
+ Password *string `json:"password,omitempty"`
+}
+
+type User struct {
+ ID string `json:"id"`
+ UserName string `json:"userName"`
+ FullName *string `json:"fullName,omitempty"`
+ Todos []*Todo `json:"todos"`
+ Roles []*Role `json:"roles"`
}
diff --git a/graph/schema.graphqls b/graph/schema.graphqls
index b4e702b..5ecdbc6 100644
--- a/graph/schema.graphqls
+++ b/graph/schema.graphqls
@@ -27,20 +27,42 @@ type Todo {
type User {
id: ID!
userName: String!
- fullName: String!
+ fullName: String
todos: [Todo!]!
+ roles: [Role!]!
+}
+
+type Role {
+ id: ID!
+ roleName: String!
+ isAdmin: Boolean!
+ isUserCreator: Boolean!
+}
+
+type RefreshToken {
+ id: ID!
+ expiryDate: Int!
+ tokenName: String
+ selector: String
+ token: String
+ userId: String!
}
type Query {
todos: [Todo!]!
users: [User!]!
+ roles: [Role!]!
+ refreshTokens: [RefreshToken!]!
user(id: ID!): User!
todo(id: ID!): Todo!
+ role(id: ID!): Role!
+ refreshToken(id: ID!): RefreshToken!
}
input NewUser {
userName: String!
- fullName: String!
+ fullName: String
+ password: String!
}
input NewTodo {
@@ -48,21 +70,50 @@ input NewTodo {
userId: ID!
}
-input updateTodo {
+input NewRole {
+ roleName: String!
+ isAdmin: Boolean!
+ isUserCreator: Boolean!
+}
+
+input NewRefreshToken {
+ tokenName: String
+}
+
+input UpdateTodo {
text: String
done: Boolean
}
-input updateUser {
+input UpdateUser {
userName: String
fullName: String
+ password: String
+}
+
+input UpdateRole {
+ roleName: String
+ isAdmin: Boolean
+ isUserCreator: Boolean
+}
+
+input UpdateRefreshToken {
+ tokenName: String
}
type Mutation {
createUser(input: NewUser!): User!
createTodo(input: NewTodo!): Todo!
- updateTodo(id: ID!, changes: updateTodo!): Todo!
- updateUser(id: ID!, changes: updateUser!): User!
+ createRole(input: NewRole!): Role!
+ createRefreshToken(input: NewRefreshToken!): RefreshToken!
+ updateTodo(id: ID!, changes: UpdateTodo!): Todo!
+ updateUser(id: ID!, changes: UpdateUser!): User!
+ updateRole(id: ID!, changes: UpdateRole!): Role!
+ updateRefreshToken(id: ID!, changes: UpdateRefreshToken!): RefreshToken!
deleteUser(id: ID!): ID
deleteTodo(id: ID!): ID
+ deleteRole(id: ID!): ID
+ deleteRefreshToken(id: ID!): ID
+ addRole(userId: ID!, roleId: ID!): [Role!]!
+ removeRole(userId: ID!, roleId: ID!): [Role!]!
}
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index 706461b..7449598 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -10,11 +10,12 @@ import (
"somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/globals"
"somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/graph/model"
+ "somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/server/auth"
)
// CreateUser is the resolver for the createUser field.
func (r *mutationResolver) CreateUser(ctx context.Context, input model.NewUser) (*model.User, error) {
- todo, err := globals.DB.AddUser(input)
+ todo, err := globals.DB.CreateUser(input)
if err != nil {
globals.Logger.Println("Failed to add new user:", err)
return nil, errors.New("failed to add new user")
@@ -32,6 +33,28 @@ func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo)
return todo, nil
}
+// CreateRole is the resolver for the createRole field.
+func (r *mutationResolver) CreateRole(ctx context.Context, input model.NewRole) (*model.Role, error) {
+ role, err := globals.DB.CreateRole(&input)
+ if err != nil {
+ globals.Logger.Println("Failed to add new role:", err)
+ return nil, errors.New("failed to add new role")
+ }
+ return role, nil
+}
+
+// CreateRefreshToken is the resolver for the createRefreshToken field.
+func (r *mutationResolver) CreateRefreshToken(ctx context.Context, input model.NewRefreshToken) (*model.RefreshToken, error) {
+ // TODO: unify model.RefreshToken & auth.RefreshToken
+ userToken := auth.ForContext(ctx)
+ refreshToken, tokenId, err := globals.DB.IssueRefreshToken(userToken.UserId, input.TokenName)
+ if err != nil {
+ globals.Logger.Println("Failed to create refresh token:", err)
+ return nil, errors.New("failed to create refresh token")
+ }
+ return &model.RefreshToken{ID: tokenId, ExpiryDate: refreshToken.ExpiryDate, TokenName: input.TokenName, Selector: &refreshToken.Selector, Token: &refreshToken.Token, UserID: userToken.UserId}, nil
+}
+
// UpdateTodo is the resolver for the updateTodo field.
func (r *mutationResolver) UpdateTodo(ctx context.Context, id string, changes model.UpdateTodo) (*model.Todo, error) {
return globals.DB.UpdateTodo(id, &changes)
@@ -42,6 +65,16 @@ func (r *mutationResolver) UpdateUser(ctx context.Context, id string, changes mo
return globals.DB.UpdateUser(id, &changes)
}
+// UpdateRole is the resolver for the updateRole field.
+func (r *mutationResolver) UpdateRole(ctx context.Context, id string, changes model.UpdateRole) (*model.Role, error) {
+ return globals.DB.UpdateRole(id, &changes)
+}
+
+// UpdateRefreshToken is the resolver for the updateRefreshToken field.
+func (r *mutationResolver) UpdateRefreshToken(ctx context.Context, id string, changes model.UpdateRefreshToken) (*model.RefreshToken, error) {
+ return globals.DB.UpdateRefreshToken(id, &changes)
+}
+
// DeleteUser is the resolver for the deleteUser field.
func (r *mutationResolver) DeleteUser(ctx context.Context, id string) (*string, error) {
return globals.DB.DeleteUser(id)
@@ -52,6 +85,32 @@ func (r *mutationResolver) DeleteTodo(ctx context.Context, id string) (*string,
return globals.DB.DeleteTodo(id)
}
+// DeleteRole is the resolver for the deleteRole field.
+func (r *mutationResolver) DeleteRole(ctx context.Context, id string) (*string, error) {
+ return globals.DB.DeleteRole(id)
+}
+
+// DeleteRefreshToken is the resolver for the deleteRefreshToken field.
+func (r *mutationResolver) DeleteRefreshToken(ctx context.Context, id string) (*string, error) {
+ return globals.DB.RevokeRefreshToken(id)
+}
+
+// AddRole is the resolver for the addRole field.
+func (r *mutationResolver) AddRole(ctx context.Context, userID string, roleID string) ([]*model.Role, error) {
+ if _, err := globals.DB.AddRole(userID, roleID); err != nil {
+ return nil, err
+ }
+ return globals.DB.GetRolesFrom(userID)
+}
+
+// RemoveRole is the resolver for the removeRole field.
+func (r *mutationResolver) RemoveRole(ctx context.Context, userID string, roleID string) ([]*model.Role, error) {
+ if _, err := globals.DB.RemoveRole(userID, roleID); err != nil {
+ return nil, err
+ }
+ return globals.DB.GetRolesFrom(userID)
+}
+
// Todos is the resolver for the todos field.
func (r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error) {
return globals.DB.GetAllTodos()
@@ -62,6 +121,16 @@ func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) {
return globals.DB.GetAllUsers()
}
+// Roles is the resolver for the roles field.
+func (r *queryResolver) Roles(ctx context.Context) ([]*model.Role, error) {
+ return globals.DB.GetAllRoles()
+}
+
+// RefreshTokens is the resolver for the refreshTokens field.
+func (r *queryResolver) RefreshTokens(ctx context.Context) ([]*model.RefreshToken, error) {
+ return globals.DB.GetAllRefreshTokens()
+}
+
// User is the resolver for the user field.
func (r *queryResolver) User(ctx context.Context, id string) (*model.User, error) {
return globals.DB.GetUser(&model.User{ID: id})
@@ -72,6 +141,16 @@ func (r *queryResolver) Todo(ctx context.Context, id string) (*model.Todo, error
return globals.DB.GetTodo(&model.Todo{ID: id})
}
+// Role is the resolver for the role field.
+func (r *queryResolver) Role(ctx context.Context, id string) (*model.Role, error) {
+ return globals.DB.GetRole(&model.Role{ID: id})
+}
+
+// RefreshToken is the resolver for the refreshToken field.
+func (r *queryResolver) RefreshToken(ctx context.Context, id string) (*model.RefreshToken, error) {
+ return globals.DB.GetRefreshToken(&model.RefreshToken{ID: id})
+}
+
// User is the resolver for the user field.
func (r *todoResolver) User(ctx context.Context, obj *model.Todo) (*model.User, error) {
// TODO: implement dataloader
@@ -83,6 +162,11 @@ func (r *userResolver) Todos(ctx context.Context, obj *model.User) ([]*model.Tod
return globals.DB.GetTodosFrom(obj)
}
+// Roles is the resolver for the roles field.
+func (r *userResolver) Roles(ctx context.Context, obj *model.User) ([]*model.Role, error) {
+ return globals.DB.GetRolesFrom(obj.ID)
+}
+
// Mutation returns MutationResolver implementation.
func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} }
diff --git a/server/auth/README.md b/server/auth/README.md
new file mode 100644
index 0000000..f79463a
--- /dev/null
+++ b/server/auth/README.md
@@ -0,0 +1,91 @@
+# Authentication in Golang
+
+## Use header
+
+Use the http header or the body, but avoid using cookies to transport tokens etc
+(because of CSRF)
+
+## Implementation
+
+```
+# create password/user
+update_password(password):
+ generate salt
+ db.store(hash(salt + password))
+
+#login
+get_token(userId, password):
+ if not hash(salt + password) == db.get(salted_hash_of_password): # use timing-attack resistant compare here
+ return FAILED
+ generate selector
+ db.store(selector)
+ generate salt
+ generate auth_token
+ db.store(salt, hash(salt+auth_token))
+ return selector:auth_token
+
+#authenticate
+validate_token(selector, auth_token):
+ if not hash(salt+auth_token) == db.get(salt, salted_hash_of_auth_token WHERE selector): # use timing-attack resistant compare here
+ return UNKNOWN_TOKEN
+ return AUTHENTICATED
+```
+
+idea: replace selector with userId?
+
+## JWT
+
+```json
+{
+ "userId": "id",
+ "userRole": "role",
+ "expiryTime": "now+10min"
+}
+```
+
+We use JWT with a lifespan of 10min and an in-memory db to blacklist revoked
+tokens. So if for e.g. a user changes it's password, we would add the userId and
+the time of the change to the blacklist, filtering out all tokens that have been
+issued before.
+
+After a server restart, all tokens will become invalid as well, since we can not
+be sure which ones were 'on the blacklist'. This could be mitigated by making
+the blacklist persistent during restarts.
+
+If a token has expired (either by a server restart or after 10min), a new token
+is requested with a 'long lived' refresh-token (lifetime of ~1 week) that is
+stored in a database.
+
+### Pros:
+
+- less DB lookups in general
+
+### Cons:
+
+- timestamps of blacklisting could become a problem (maybe add 1 second or use
+ timestamp returned by n-th node when it has received the update).
+- increased load on db + service since we need to issue new jwt for everybody.
+
+## SSL/TLS
+
+```bash
+openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout keyFile.key -out certFile.crt
+```
+
+## CRIME/BREACH http compression attack
+
+While we do not use a CSRF token, headers sent to the `/api` still contain
+private data.
+
+If you are using http/1.1 or lower and have compression enabled on your proxy,
+you would be .
+
+## CRSF
+
+We check for a http header like this `X-YOURSITE-CSRF-PROTECTION=1`. This should
+be enough, according to
+[cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#custom-request-headers)
+
+## XSS
+
+We rely on Vue.js's ability to escape user-input in templates.
diff --git a/server/auth/main.go b/server/auth/main.go
new file mode 100644
index 0000000..2398cd6
--- /dev/null
+++ b/server/auth/main.go
@@ -0,0 +1,139 @@
+/*
+YetAnotherToDoList
+Copyright © 2023 gilex-dev gilex-dev@proton.me
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 3.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+package auth
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+
+ "somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/database"
+ "somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/globals"
+)
+
+var userCtxKey = &contextKey{"user"}
+
+type contextKey struct {
+ name string
+}
+
+func Middleware() func(http.Handler) http.Handler {
+ return func(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ const headerPrefix = "Bearer "
+ authField := r.Header.Get("Authorization")
+ if !strings.HasPrefix(authField, headerPrefix) {
+ http.Error(w, fmt.Sprintf(`{"error":"wrong token type, expect '%s'"}`, headerPrefix), http.StatusBadRequest)
+ return
+ }
+
+ // get the user from the database
+ user, err := globals.DB.CheckAccessToken(strings.TrimPrefix(authField, headerPrefix))
+ if err != nil {
+ http.Error(w, strings.ReplaceAll(fmt.Sprintf(`{"error":"failed token check: '%s'"}`, err), "\\", "\\\\"), http.StatusInternalServerError)
+ return
+ }
+
+ // put it in context
+ ctx := context.WithValue(r.Context(), userCtxKey, user)
+ // and call the next with our new context
+ r = r.WithContext(ctx)
+ next.ServeHTTP(w, r)
+ })
+ }
+}
+
+func ForContext(ctx context.Context) *database.AccessToken {
+ raw, _ := ctx.Value(userCtxKey).(*database.AccessToken)
+ return raw
+}
+
+type userAuth struct {
+ UserId *string `json:"userId"`
+ UserName *string `json:"userName"`
+ Password string `json:"password"`
+}
+
+func IssueRefreshTokenHandler(w http.ResponseWriter, r *http.Request) {
+ const headerPrefix = "Login "
+ authField := r.Header.Get("Authorization")
+ if !strings.HasPrefix(authField, headerPrefix) {
+ http.Error(w, fmt.Sprintf("wrong token type, expect %q", headerPrefix), http.StatusBadRequest)
+ return
+ }
+
+ userCredentials := userAuth{}
+
+ err := json.Unmarshal([]byte(strings.TrimPrefix(authField, headerPrefix)), &userCredentials)
+ if err != nil {
+ http.Error(w, "malformed or missing user credentials", http.StatusBadRequest)
+ return
+ }
+
+ userId, err := globals.DB.ValidateUserCredentials(userCredentials.UserId, userCredentials.UserName, userCredentials.Password)
+ if err != nil {
+ http.Error(w, "invalid credentials", http.StatusUnauthorized)
+ return
+ }
+
+ refreshToken, _, err := globals.DB.IssueRefreshToken(userId, nil)
+ if err != nil {
+ http.Error(w, "failed to issue refresh token", http.StatusInternalServerError)
+ return
+ }
+
+ jsonRefreshToken, err := json.Marshal(refreshToken)
+ if err != nil {
+ http.Error(w, "internal server error", http.StatusInternalServerError)
+ return
+ }
+
+ w.Write([]byte(jsonRefreshToken))
+}
+
+func IssueAccessTokenHandler(w http.ResponseWriter, r *http.Request) {
+ const headerPrefix = "Refresh "
+ authField := r.Header.Get("Authorization")
+ if !strings.HasPrefix(authField, headerPrefix) {
+ http.Error(w, fmt.Sprintf("wrong token type, expect %q", headerPrefix), http.StatusBadRequest)
+ return
+ }
+
+ refreshToken := database.RefreshToken{}
+
+ err := json.Unmarshal([]byte(strings.TrimPrefix(authField, headerPrefix)), &refreshToken)
+ if err != nil {
+ http.Error(w, "malformed or missing refresh token", http.StatusBadRequest)
+ return
+ }
+
+ accessToken, err := globals.DB.IssueAccessToken(&refreshToken)
+ if err != nil {
+ http.Error(w, "invalid access token", http.StatusUnauthorized)
+ return
+ }
+
+ encAccessToken, err := globals.DB.SignAccessToken(*accessToken)
+ if err != nil {
+ http.Error(w, "internal server error", http.StatusInternalServerError)
+ return
+ }
+
+ w.Write([]byte(encAccessToken))
+}
diff --git a/server/handleDevTools.go b/server/handleDevTools.go
index 27eb79b..68004fc 100644
--- a/server/handleDevTools.go
+++ b/server/handleDevTools.go
@@ -20,11 +20,24 @@ along with this program. If not, see .
package server
import (
+ "fmt"
+
"github.com/99designs/gqlgen/graphql/playground"
+ "github.com/go-chi/chi"
"somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/globals"
)
-func handleDevTools(port int) {
- mux.Handle("/playground", playground.Handler("GraphQL playground", "/api"))
- globals.Logger.Printf("connect to http://localhost:%v/ for GraphQL playground", port)
+func handleDevTools(router *chi.Mux, portHTTP int, portHTTPS int) {
+ router.Handle("/playground", playground.Handler("GraphQL playground", "/api"))
+ url := "connect to "
+ if portHTTP != -1 && portHTTPS != -1 {
+ url += fmt.Sprintf("http://localhost:%v/ or https://localhost:%v/", portHTTP, portHTTPS)
+ } else if portHTTP != -1 {
+ url += fmt.Sprintf("http://localhost:%v/", portHTTP)
+ } else if portHTTPS != -1 {
+ url += fmt.Sprintf("https://localhost:%v/", portHTTPS)
+ } else {
+ return
+ }
+ globals.Logger.Println(url + " for GraphQL playground")
}
diff --git a/server/handleDevTools.mock.go b/server/handleDevTools.mock.go
index 7548ddf..d21ed95 100644
--- a/server/handleDevTools.mock.go
+++ b/server/handleDevTools.mock.go
@@ -19,5 +19,7 @@ along with this program. If not, see .
*/
package server
-func handleDevTools(_ int) {
+import "github.com/go-chi/chi"
+
+func handleDevTools(router *chi.Mux, _ int, _ int) {
}
diff --git a/server/handleFrontend.go b/server/handleFrontend.go
index 756d04a..7a30cd9 100644
--- a/server/handleFrontend.go
+++ b/server/handleFrontend.go
@@ -24,19 +24,21 @@ import (
"io/fs"
"log"
"net/http"
+
+ "github.com/go-chi/chi"
)
//go:embed dist/*
var frontend embed.FS
-func handleFrontend() {
+func handleFrontend(router *chi.Mux) {
stripped, err := fs.Sub(frontend, "dist")
if err != nil {
log.Fatalln(err)
}
frontendFS := http.FileServer(http.FS(stripped))
- mux.Handle("/assets/", frontendFS)
- mux.HandleFunc("/", indexHandler)
+ router.Handle("/assets/*", frontendFS)
+ router.HandleFunc("/", indexHandler)
// TODO: redirect from vue to 404 page (on go/proxy server)
}
diff --git a/server/handleFrontend.mock.go b/server/handleFrontend.mock.go
index fdbc189..9bfeba1 100644
--- a/server/handleFrontend.mock.go
+++ b/server/handleFrontend.mock.go
@@ -19,5 +19,7 @@ along with this program. If not, see .
*/
package server
-func handleFrontend() {
+import "github.com/go-chi/chi"
+
+func handleFrontend(router *chi.Mux) {
}
diff --git a/server/main.go b/server/main.go
index 9709244..6a0f055 100644
--- a/server/main.go
+++ b/server/main.go
@@ -22,24 +22,68 @@ import (
"strconv"
"github.com/99designs/gqlgen/graphql/handler"
+ "github.com/go-chi/chi"
+ "github.com/go-chi/chi/middleware"
"somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/globals"
"somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/graph"
+ "somepi.ddns.net/gitea/gilex-dev/YetAnotherToDoList/server/auth"
)
-var mux *http.ServeMux
+func StartServer(portHTTP int, portHTTPS int, certFile string, keyFile string) {
+ router := chi.NewRouter()
+ router.Use(middleware.StripSlashes)
-func StartServer(port int) {
- mux = http.NewServeMux()
-
- handleDevTools(port) // controlled by 'dev' tag
- handleFrontend() // controlled by 'headless' tag
-
- mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
+ handleDevTools(router, portHTTP, portHTTPS) // controlled by 'dev' tag
+ handleFrontend(router) // controlled by 'headless' tag
+ router.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s %s", globals.Version, globals.CommitHash)
})
srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))
- mux.Handle("/api", srv)
+ router.HandleFunc("/auth/login", auth.IssueRefreshTokenHandler)
+ router.HandleFunc("/auth", auth.IssueAccessTokenHandler)
+
+ router.Group(func(r chi.Router) {
+ r.Use(auth.Middleware())
+ r.Handle("/api", srv)
+ r.HandleFunc("/protected", func(w http.ResponseWriter, r *http.Request) {
+ fmt.Printf("user is %+v\n", auth.ForContext(r.Context()))
+ })
+ })
+ // router.HandleFunc("/auth/", func(w http.ResponseWriter, r *http.Request) {
+ // http.Redirect(w, r, "/auth", http.StatusMovedPermanently)
+ // })
+
+ err := <-listen(portHTTP, portHTTPS, certFile, keyFile, router)
+ globals.Logger.Fatalf("Could not start serving service due to (error: %s)", err)
- globals.Logger.Fatal(http.ListenAndServe(":"+strconv.FormatInt(int64(port), 10), mux))
+}
+
+func listen(portHTTP int, portHTTPS int, certFile string, keyFile string, router *chi.Mux) chan error {
+
+ errs := make(chan error)
+
+ // Starting HTTP server
+ if portHTTP != -1 {
+ go func() {
+ globals.Logger.Printf("Staring HTTP service on %d ...", portHTTP)
+
+ if err := http.ListenAndServe(":"+strconv.FormatInt(int64(portHTTP), 10), router); err != nil {
+ errs <- err
+ }
+
+ }()
+ }
+
+ // Starting HTTPS server
+ if portHTTPS != -1 && certFile != "" && keyFile != "" {
+ go func() {
+ globals.Logger.Printf("Staring HTTPS service on %d ...", portHTTPS)
+ if err := http.ListenAndServeTLS(":"+strconv.FormatInt(int64(portHTTPS), 10), certFile, keyFile, router); err != nil {
+ errs <- err
+ }
+ }()
+ }
+
+ return errs
}