redesign
This commit is contained in:
78
internal/api/api.go
Normal file
78
internal/api/api.go
Normal file
@ -0,0 +1,78 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
"github.com/go-chi/cors"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type TaskcafeApi struct {
|
||||
Data db.Repository
|
||||
}
|
||||
|
||||
func NewRouter(dbConnection *sql.DB) (chi.Router, error) {
|
||||
|
||||
formatter := new(logrus.TextFormatter)
|
||||
formatter.TimestampFormat = "02-01-2006 15:04:05"
|
||||
formatter.FullTimestamp = true
|
||||
|
||||
routerLogger := logrus.New()
|
||||
routerLogger.SetLevel(logrus.InfoLevel)
|
||||
routerLogger.Formatter = formatter
|
||||
r := chi.NewRouter()
|
||||
r.Use(middleware.RequestID)
|
||||
r.Use(middleware.RealIP)
|
||||
// r.Use(logger.NewStructuredLogger(routerLogger))
|
||||
r.Use(middleware.Recoverer)
|
||||
r.Use(middleware.Timeout(60 * time.Second))
|
||||
|
||||
r.Use(cors.Handler(cors.Options{
|
||||
AllowedOrigins: []string{"https://*", "http://*"},
|
||||
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
||||
AllowedHeaders: []string{"Accept", "Authorization", "Cookie", "Content-Type", "X-CSRF-Token"},
|
||||
ExposedHeaders: []string{"Link"},
|
||||
AllowCredentials: true,
|
||||
MaxAge: 300,
|
||||
}))
|
||||
|
||||
repository := db.NewRepository(dbConnection)
|
||||
taskcafeApi := TaskcafeApi{*repository}
|
||||
|
||||
r.Group(func(mux chi.Router) {
|
||||
mux.Post("/auth/login", taskcafeApi.AuthLogin)
|
||||
mux.Post("/public_settings", taskcafeApi.PublicSettings)
|
||||
// mux.Post("/auth/logout", taskcafeApi.AuthLogout)
|
||||
// mux.Post("/auth/me", taskcafeApi.AuthMe)
|
||||
/*
|
||||
mux.Handle("/__graphql", graph.NewPlaygroundHandler("/graphql"))
|
||||
mux.Mount("/uploads/", http.StripPrefix("/uploads/", imgServer))
|
||||
mux.Post("/auth/confirm", taskcafeHandler.ConfirmUser)
|
||||
mux.Post("/auth/register", taskcafeHandler.RegisterUser)
|
||||
mux.Get("/settings", taskcafeHandler.PublicSettings)
|
||||
mux.Post("/logger", taskcafeHandler.HandleClientLog)
|
||||
*/
|
||||
})
|
||||
/*
|
||||
auth := AuthenticationMiddleware{*repository}
|
||||
jobQueue := jobs.JobQueue{
|
||||
Repository: *repository,
|
||||
AppConfig: appConfig,
|
||||
Server: jobServer,
|
||||
}
|
||||
r.Group(func(mux chi.Router) {
|
||||
mux.Use(auth.Middleware)
|
||||
mux.Post("/users/me/avatar", taskcafeHandler.ProfileImageUpload)
|
||||
mux.Mount("/graphql", graph.NewHandler(*repository, appConfig, jobQueue, redisClient))
|
||||
})
|
||||
*/
|
||||
|
||||
// frontend := FrontendHandler{staticPath: "build", indexPath: "index.html"}
|
||||
// r.Handle("/*", frontend)
|
||||
|
||||
return r, nil
|
||||
}
|
62
internal/api/auth_login.go
Normal file
62
internal/api/auth_login.go
Normal file
@ -0,0 +1,62 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/jordanknott/taskcafe/internal/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
type AuthLoginRequestData struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type AuthLoginResponseData struct {
|
||||
UserID string `json:"userId`
|
||||
}
|
||||
|
||||
func (api *TaskcafeApi) AuthLogin(w http.ResponseWriter, r *http.Request) {
|
||||
var request AuthLoginRequestData
|
||||
ctx := r.Context()
|
||||
err := json.NewDecoder(r.Body).Decode(&request)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
logrus.WithError(err).Warn("bad request body")
|
||||
return
|
||||
}
|
||||
|
||||
userAccount, err := api.Data.GetUserAccountByUsername(ctx, request.Username)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
logrus.WithError(err).Debug("error while getting user account by username")
|
||||
return
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword([]byte(userAccount.PasswordHash), []byte(request.Password))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
logrus.WithError(err).Debug("error while hashing and comparing passwords")
|
||||
}
|
||||
|
||||
createdAt := time.Now().UTC()
|
||||
expiresAt := createdAt.AddDate(0, 0, 7)
|
||||
token, err := util.GenerateAccessToken()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
logrus.WithError(err).Error("error while creating new access token")
|
||||
}
|
||||
|
||||
w.Header().Set("Content-type", "application/json")
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "accessToken",
|
||||
Value: token,
|
||||
Expires: expiresAt,
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
})
|
||||
json.NewEncoder(w).Encode(AuthLoginResponseData{UserID: userAccount.UserID.String()})
|
||||
}
|
56
internal/api/auth_me.go
Normal file
56
internal/api/auth_me.go
Normal file
@ -0,0 +1,56 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/jordanknott/taskcafe/internal/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type AuthMeResponseData struct {
|
||||
UserID string `json:"userId`
|
||||
}
|
||||
|
||||
func (api *TaskcafeApi) AuthMe(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
c, err := r.Cookie("Authorization")
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("error while getting cookie")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
token, err := api.Data.GetAccessToken(ctx, c.Value)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("error while getting access cookie")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
userAccount, err := api.Data.GetUserAccountByID(ctx, token.UserID)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
logrus.WithError(err).Debug("error while getting user account by username")
|
||||
return
|
||||
}
|
||||
|
||||
createdAt := time.Now().UTC()
|
||||
expiresAt := createdAt.AddDate(0, 0, 7)
|
||||
nextToken, err := util.GenerateAccessToken()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
logrus.WithError(err).Error("error while creating new access token")
|
||||
}
|
||||
|
||||
w.Header().Set("Content-type", "application/json")
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "accessToken",
|
||||
Value: nextToken,
|
||||
Expires: expiresAt,
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
})
|
||||
json.NewEncoder(w).Encode(AuthLoginResponseData{UserID: userAccount.UserID.String()})
|
||||
}
|
23
internal/api/settings.go
Normal file
23
internal/api/settings.go
Normal file
@ -0,0 +1,23 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type PublicSettingsResponseData struct {
|
||||
IsInstalled bool `json:"isInstalled"`
|
||||
AllowPublicRegistration bool `json:"allowPublicRegistration`
|
||||
}
|
||||
|
||||
func (api *TaskcafeApi) PublicSettings(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
isInstalled, err := api.Data.HasAnyUserAccount(ctx)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
logrus.WithError(err).Error()
|
||||
}
|
||||
json.NewEncoder(w).Encode(PublicSettingsResponseData{IsInstalled: isInstalled, AllowPublicRegistration: false})
|
||||
}
|
@ -1,12 +1,14 @@
|
||||
package commands
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/jordanknott/taskcafe/internal/utils"
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
// "github.com/jordanknott/taskcafe/internal/config"
|
||||
// "github.com/jordanknott/taskcafe/internal/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
@ -15,10 +17,13 @@ const mainDescription = `Taskcafé is an open soure project management
|
||||
system written in Golang & React.`
|
||||
|
||||
func VersionTemplate() string {
|
||||
info := utils.Version()
|
||||
return fmt.Sprintf(`Version: %s
|
||||
Commit: %s
|
||||
Built: %s`, info.Version, info.CommitHash, info.BuildDate+"\n")
|
||||
/*
|
||||
info := utils.Version()
|
||||
return fmt.Sprintf(`Version: %s
|
||||
Commit: %s
|
||||
Built: %s`, info.Version, info.CommitHash, info.BuildDate+"\n")
|
||||
*/
|
||||
return ""
|
||||
}
|
||||
|
||||
var cfgFile string
|
||||
@ -34,6 +39,12 @@ var migration http.FileSystem
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
|
||||
Formatter := new(logrus.TextFormatter)
|
||||
Formatter.TimestampFormat = "02-01-2006 15:04:05"
|
||||
Formatter.FullTimestamp = true
|
||||
logrus.SetFormatter(Formatter)
|
||||
logrus.SetLevel(logrus.InfoLevel)
|
||||
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file path")
|
||||
migration = http.Dir("./migrations")
|
||||
}
|
||||
@ -53,7 +64,7 @@ func initConfig() {
|
||||
viper.SetEnvPrefix("TASKCAFE")
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
viper.AutomaticEnv()
|
||||
config.InitDefaults()
|
||||
// config.InitDefaults()
|
||||
|
||||
err := viper.ReadInConfig()
|
||||
if err == nil {
|
||||
@ -68,6 +79,6 @@ func initConfig() {
|
||||
// Execute the root cobra command
|
||||
func Execute() {
|
||||
rootCmd.SetVersionTemplate(VersionTemplate())
|
||||
rootCmd.AddCommand(newJobCmd(), newTokenCmd(), newWebCmd(), newMigrateCmd(), newWorkerCmd(), newResetPasswordCmd(), newSeedCmd())
|
||||
rootCmd.AddCommand(newMigrateCmd(), newUserCmd(), newWebCmd())
|
||||
rootCmd.Execute()
|
||||
}
|
33
internal/command/migrate.go
Normal file
33
internal/command/migrate.go
Normal file
@ -0,0 +1,33 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/pressly/goose/v3"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newMigrateCmd() *cobra.Command {
|
||||
cc := &cobra.Command{
|
||||
Use: "migrate",
|
||||
Short: "run the migrations",
|
||||
Long: "Run the migrations",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(appConfig.Database.GetDatabaseConnectionUri())
|
||||
db, err := sql.Open("postgres", appConfig.Database.GetDatabaseConnectionUri())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return goose.Up(db, "migrations")
|
||||
},
|
||||
}
|
||||
cc.AddCommand(newMigrateCreateCmd())
|
||||
return cc
|
||||
}
|
29
internal/command/migrate_create.go
Normal file
29
internal/command/migrate_create.go
Normal file
@ -0,0 +1,29 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/pressly/goose/v3"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newMigrateCreateCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "create name type",
|
||||
Short: "Create a new migration file",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
db, err := sql.Open("postgres", appConfig.Database.GetDatabaseConnectionUri())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return goose.Create(db, "migrations", args[0], args[1])
|
||||
},
|
||||
}
|
||||
}
|
9
internal/command/user.go
Normal file
9
internal/command/user.go
Normal file
@ -0,0 +1,9 @@
|
||||
package command
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
|
||||
func newUserCmd() *cobra.Command {
|
||||
cc := cobra.Command{Use: "user"}
|
||||
cc.AddCommand(newUserListCmd(), newUserCreateCmd())
|
||||
return &cc
|
||||
}
|
57
internal/command/user_create.go
Normal file
57
internal/command/user_create.go
Normal file
@ -0,0 +1,57 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/manifoldco/promptui"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func newUserCreateCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "create <username> <email>",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dbConn, err := sql.Open("postgres", appConfig.Database.GetDatabaseConnectionUri())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prompt := promptui.Prompt{
|
||||
Label: "User's fullname",
|
||||
}
|
||||
fullname, err := prompt.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prompt = promptui.Prompt{
|
||||
Label: "User's password",
|
||||
Mask: '*',
|
||||
}
|
||||
password, err := prompt.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repo := db.NewRepository(dbConn)
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), 10)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
createdAt := time.Now().UTC()
|
||||
account, err := repo.CreateUserAccount(context.Background(), db.CreateUserAccountParams{Username: args[0], Email: args[1], Fullname: fullname, PasswordHash: string(hash), CreatedAt: createdAt})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Created account: " + account.UserID.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
41
internal/command/user_list.go
Normal file
41
internal/command/user_list.go
Normal file
@ -0,0 +1,41 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"os"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newUserListCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "list",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dbConn, err := sql.Open("postgres", appConfig.Database.GetDatabaseConnectionUri())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t := table.NewWriter()
|
||||
t.SetOutputMirror(os.Stdout)
|
||||
t.AppendHeader(table.Row{"#", "Full Name", "Username", "Email"})
|
||||
repo := db.NewRepository(dbConn)
|
||||
accounts, err := repo.GetUserAccounts(context.Background())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for _, account := range accounts {
|
||||
t.AppendRow(table.Row{account.UserID.String(), account.Fullname, account.Username, account.Email})
|
||||
}
|
||||
t.Render()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
75
internal/command/web.go
Normal file
75
internal/command/web.go
Normal file
@ -0,0 +1,75 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/jordanknott/taskcafe/internal/api"
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func newWebCmd() *cobra.Command{
|
||||
cc := &cobra.Command{
|
||||
Use: "web",
|
||||
Short: "Run the web server",
|
||||
Long: "Run the web & api server",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Formatter := new(logrus.TextFormatter)
|
||||
Formatter.TimestampFormat = "02-01-2006 15:04:05"
|
||||
Formatter.FullTimestamp = true
|
||||
logrus.SetFormatter(Formatter)
|
||||
logrus.SetLevel(logrus.InfoLevel)
|
||||
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var db *sql.DB
|
||||
var retryDuration time.Duration
|
||||
maxRetryNumber := 4
|
||||
for i := 0; i < maxRetryNumber; i++ {
|
||||
db, err = sql.Open("postgres", appConfig.Database.GetDatabaseConnectionUri())
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
retryDuration = time.Duration(i*2) * time.Second
|
||||
logrus.WithFields(logrus.Fields{"retryNumber": i, "retryDuration": retryDuration}).WithError(err).Error("issue connecting to database, retrying")
|
||||
if i != maxRetryNumber-1 {
|
||||
time.Sleep(retryDuration)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db.SetMaxOpenConns(25)
|
||||
db.SetMaxIdleConns(25)
|
||||
db.SetConnMaxLifetime(5 * time.Minute)
|
||||
defer db.Close()
|
||||
|
||||
if viper.GetBool("migrate") {
|
||||
logrus.Info("running auto schema migrations")
|
||||
/*
|
||||
if err = runMigration(db); err != nil {
|
||||
return err
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
r, _ := api.NewRouter(db)
|
||||
|
||||
logrus.WithFields(logrus.Fields{"url": viper.GetString("server.hostname")}).Info("starting server")
|
||||
return http.ListenAndServe(viper.GetString("server.hostname"), r)
|
||||
},
|
||||
}
|
||||
|
||||
cc.Flags().Bool("migrate", false, "if true, auto run's schema migrations before starting the web server")
|
||||
|
||||
viper.BindPFlag("migrate", cc.Flags().Lookup("migrate"))
|
||||
viper.SetDefault("migrate", false)
|
||||
return cc
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
// +build prod
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/jordanknott/taskcafe/internal/migrations"
|
||||
)
|
||||
|
||||
func init() {
|
||||
migration = migrations.Migrations
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/RichardKnop/machinery/v1"
|
||||
mTasks "github.com/RichardKnop/machinery/v1/tasks"
|
||||
|
||||
queueLog "github.com/RichardKnop/machinery/v1/log"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/jordanknott/taskcafe/internal/jobs"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func newJobCmd() *cobra.Command {
|
||||
cc := &cobra.Command{
|
||||
Use: "job",
|
||||
Short: "Run a task manually",
|
||||
Long: "Run a task manually",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Formatter := new(log.TextFormatter)
|
||||
Formatter.TimestampFormat = "02-01-2006 15:04:05"
|
||||
Formatter.FullTimestamp = true
|
||||
log.SetFormatter(Formatter)
|
||||
log.SetLevel(log.InfoLevel)
|
||||
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
db, err := sqlx.Connect("postgres", config.GetDatabaseConfig().GetDatabaseConnectionUri())
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
db.SetMaxOpenConns(25)
|
||||
db.SetMaxIdleConns(25)
|
||||
db.SetConnMaxLifetime(5 * time.Minute)
|
||||
defer db.Close()
|
||||
|
||||
log.Info("starting task queue server instance")
|
||||
jobConfig := appConfig.Job.GetJobConfig()
|
||||
server, err := machinery.NewServer(&jobConfig)
|
||||
if err != nil {
|
||||
// do something with the error
|
||||
}
|
||||
queueLog.Set(&jobs.MachineryLogger{})
|
||||
|
||||
signature := &mTasks.Signature{
|
||||
Name: "scheduleDueDateNotifications",
|
||||
}
|
||||
server.SendTask(signature)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return cc
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database/postgres"
|
||||
"github.com/golang-migrate/migrate/v4/source/httpfs"
|
||||
"github.com/jmoiron/sqlx"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// MigrateLog is a logger for go migrate
|
||||
type MigrateLog struct {
|
||||
verbose bool
|
||||
}
|
||||
|
||||
// Printf logs to logrus
|
||||
func (l *MigrateLog) Printf(format string, v ...interface{}) {
|
||||
log.Printf("%s", v)
|
||||
}
|
||||
|
||||
// Verbose shows if verbose print enabled
|
||||
func (l *MigrateLog) Verbose() bool {
|
||||
return l.verbose
|
||||
}
|
||||
|
||||
func newMigrateCmd() *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "migrate",
|
||||
Short: "Run the database schema migrations",
|
||||
Long: "Run the database schema migrations",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
connection := fmt.Sprintf("user=%s password=%s host=%s dbname=%s port=%s sslmode=disable",
|
||||
viper.GetString("database.user"),
|
||||
viper.GetString("database.password"),
|
||||
viper.GetString("database.host"),
|
||||
viper.GetString("database.name"),
|
||||
viper.GetString("database.port"),
|
||||
)
|
||||
db, err := sqlx.Connect("postgres", connection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
driver, err := postgres.WithInstance(db.DB, &postgres.Config{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
src, err := httpfs.New(migration, "./")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := migrate.NewWithInstance("httpfs", src, "postgres", driver)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger := &MigrateLog{}
|
||||
m.Log = logger
|
||||
err = m.Up()
|
||||
if err != nil && err != migrate.ErrNoChange {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return c
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func newResetPasswordCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "reset-password",
|
||||
Short: "Resets password of the specified user",
|
||||
Long: "If the user forgets its password you can reset it with this command.",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
connection := fmt.Sprintf("user=%s password=%s host=%s dbname=%s sslmode=disable",
|
||||
viper.GetString("database.user"),
|
||||
viper.GetString("database.password"),
|
||||
viper.GetString("database.host"),
|
||||
viper.GetString("database.name"),
|
||||
)
|
||||
var database *sqlx.DB
|
||||
var err error
|
||||
var retryDuration time.Duration
|
||||
maxRetryNumber := 4
|
||||
for i := 0; i < maxRetryNumber; i++ {
|
||||
database, err = sqlx.Connect("postgres", connection)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
retryDuration = time.Duration(i*2) * time.Second
|
||||
log.WithFields(log.Fields{"retryNumber": i, "retryDuration": retryDuration}).WithError(err).Error("issue connecting to database, retrying")
|
||||
if i != maxRetryNumber-1 {
|
||||
time.Sleep(retryDuration)
|
||||
}
|
||||
}
|
||||
database.SetMaxOpenConns(25)
|
||||
database.SetMaxIdleConns(25)
|
||||
database.SetConnMaxLifetime(5 * time.Minute)
|
||||
repo := *db.NewRepository(database)
|
||||
|
||||
username := args[0]
|
||||
password := args[1]
|
||||
|
||||
user, err := repo.GetUserAccountByUsername(context.TODO(), username)
|
||||
if err != nil {
|
||||
fmt.Println("There is no user with that username. :/")
|
||||
return nil
|
||||
}
|
||||
|
||||
hashedPwd, err := bcrypt.GenerateFromPassword([]byte(password), 14)
|
||||
|
||||
if _, err := repo.SetUserPassword(context.TODO(), db.SetUserPasswordParams{UserID: user.UserID, PasswordHash: string(hashedPwd)}); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Updated user \"" + username + "\" password.")
|
||||
defer database.Close()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/brianvoe/gofakeit/v5"
|
||||
"github.com/manifoldco/promptui"
|
||||
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
teams int
|
||||
projects int
|
||||
taskGroups int
|
||||
tasks int
|
||||
)
|
||||
|
||||
func newSeedCmd() *cobra.Command {
|
||||
cc := &cobra.Command{
|
||||
Use: "seed",
|
||||
Short: "Seeds the database with random data for testing",
|
||||
Long: "Seeds the database with random data for testing. CAN NOT BE UNDONE.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Formatter := new(log.TextFormatter)
|
||||
Formatter.TimestampFormat = "02-01-2006 15:04:05"
|
||||
Formatter.FullTimestamp = true
|
||||
log.SetFormatter(Formatter)
|
||||
log.SetLevel(log.InfoLevel)
|
||||
|
||||
connection := fmt.Sprintf("user=%s password=%s host=%s dbname=%s port=%s sslmode=disable",
|
||||
viper.GetString("database.user"),
|
||||
viper.GetString("database.password"),
|
||||
viper.GetString("database.host"),
|
||||
viper.GetString("database.name"),
|
||||
viper.GetString("database.port"),
|
||||
)
|
||||
var dbConnection *sqlx.DB
|
||||
var err error
|
||||
var retryDuration time.Duration
|
||||
maxRetryNumber := 4
|
||||
for i := 0; i < maxRetryNumber; i++ {
|
||||
dbConnection, err = sqlx.Connect("postgres", connection)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
retryDuration = time.Duration(i*2) * time.Second
|
||||
log.WithFields(log.Fields{"retryNumber": i, "retryDuration": retryDuration}).WithError(err).Error("issue connecting to database, retrying")
|
||||
if i != maxRetryNumber-1 {
|
||||
time.Sleep(retryDuration)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dbConnection.SetMaxOpenConns(25)
|
||||
dbConnection.SetMaxIdleConns(25)
|
||||
dbConnection.SetConnMaxLifetime(5 * time.Minute)
|
||||
defer dbConnection.Close()
|
||||
|
||||
if viper.GetBool("migrate") {
|
||||
log.Info("running auto schema migrations")
|
||||
if err = runMigration(dbConnection); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Seed database",
|
||||
IsConfirm: true,
|
||||
}
|
||||
|
||||
_, err = prompt.Run()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
repository := db.NewRepository(dbConnection)
|
||||
now := time.Now().UTC()
|
||||
organizations, err := repository.GetAllOrganizations(ctx)
|
||||
organizationId := organizations[0].OrganizationID
|
||||
for teamIdx := 0; teamIdx <= teams; teamIdx++ {
|
||||
teamName := gofakeit.Company()
|
||||
team, err := repository.CreateTeam(ctx, db.CreateTeamParams{
|
||||
Name: teamName,
|
||||
CreatedAt: now,
|
||||
OrganizationID: organizationId,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for projectIdx := 0; projectIdx <= projects; projectIdx++ {
|
||||
projectName := gofakeit.Dessert()
|
||||
project, err := repository.CreateTeamProject(ctx, db.CreateTeamProjectParams{
|
||||
TeamID: team.TeamID,
|
||||
Name: projectName,
|
||||
CreatedAt: now,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for taskGroupIdx := 0; taskGroupIdx <= taskGroups; taskGroupIdx++ {
|
||||
taskGroupName := gofakeit.LoremIpsumSentence(8)
|
||||
taskGroup, err := repository.CreateTaskGroup(ctx, db.CreateTaskGroupParams{
|
||||
Name: taskGroupName,
|
||||
ProjectID: project.ProjectID,
|
||||
CreatedAt: now,
|
||||
Position: float64(65535 * (taskGroupIdx + 1)),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for taskIdx := 0; taskIdx <= tasks; taskIdx++ {
|
||||
taskName := gofakeit.Sentence(8)
|
||||
task, err := repository.CreateTask(ctx, db.CreateTaskParams{
|
||||
Name: taskName,
|
||||
TaskGroupID: taskGroup.TaskGroupID,
|
||||
CreatedAt: now,
|
||||
Position: float64(65535 * (taskIdx + 1)),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Creating %d / %d / %d / %d - %d\n", teamIdx, projectIdx, taskGroupIdx, taskIdx, task.TaskID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cc.Flags().Bool("migrate", false, "if true, auto run's schema migrations before starting the web server")
|
||||
cc.Flags().IntVar(&teams, "teams", 5, "number of teams to generate")
|
||||
cc.Flags().IntVar(&projects, "projects", 10, "number of projects to create per team (personal projects are included)")
|
||||
cc.Flags().IntVar(&taskGroups, "task_groups", 5, "number of task groups to generate per project")
|
||||
cc.Flags().IntVar(&tasks, "tasks", 25, "number of tasks to generate per task group")
|
||||
|
||||
viper.SetDefault("migrate", false)
|
||||
return cc
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func newTokenCmd() *cobra.Command {
|
||||
cc := &cobra.Command{
|
||||
Use: "token [username]",
|
||||
Short: "Creates an access token for a user",
|
||||
Long: "Creates an access token for a user",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Formatter := new(log.TextFormatter)
|
||||
Formatter.TimestampFormat = "02-01-2006 15:04:05"
|
||||
Formatter.FullTimestamp = true
|
||||
log.SetFormatter(Formatter)
|
||||
log.SetLevel(log.InfoLevel)
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var dbConnection *sqlx.DB
|
||||
var retryDuration time.Duration
|
||||
maxRetryNumber := 4
|
||||
for i := 0; i < maxRetryNumber; i++ {
|
||||
dbConnection, err = sqlx.Connect("postgres", appConfig.Database.GetDatabaseConnectionUri())
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
retryDuration = time.Duration(i*2) * time.Second
|
||||
log.WithFields(log.Fields{"retryNumber": i, "retryDuration": retryDuration}).WithError(err).Error("issue connecting to database, retrying")
|
||||
if i != maxRetryNumber-1 {
|
||||
time.Sleep(retryDuration)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dbConnection.SetMaxOpenConns(25)
|
||||
dbConnection.SetMaxIdleConns(25)
|
||||
dbConnection.SetConnMaxLifetime(5 * time.Minute)
|
||||
defer dbConnection.Close()
|
||||
|
||||
if viper.GetBool("migrate") {
|
||||
log.Info("running auto schema migrations")
|
||||
if err = runMigration(dbConnection); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
repository := db.NewRepository(dbConnection)
|
||||
user, err := repository.GetUserAccountByUsername(ctx, args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
token, err := repository.CreateAuthToken(ctx, db.CreateAuthTokenParams{
|
||||
UserID: user.UserID,
|
||||
CreatedAt: time.Now(),
|
||||
ExpiresAt: time.Now().Add(time.Hour * 24 * 7),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Created token: %s\n", token.TokenID.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cc.Flags().Bool("migrate", false, "if true, auto run's schema migrations before starting the web server")
|
||||
cc.Flags().IntVar(&teams, "teams", 5, "number of teams to generate")
|
||||
cc.Flags().IntVar(&projects, "projects", 10, "number of projects to create per team (personal projects are included)")
|
||||
cc.Flags().IntVar(&taskGroups, "task_groups", 5, "number of task groups to generate per project")
|
||||
cc.Flags().IntVar(&tasks, "tasks", 25, "number of tasks to generate per task group")
|
||||
|
||||
viper.SetDefault("migrate", false)
|
||||
return cc
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/RichardKnop/machinery/v1"
|
||||
mTasks "github.com/RichardKnop/machinery/v1/tasks"
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database/postgres"
|
||||
"github.com/golang-migrate/migrate/v4/source/httpfs"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/jordanknott/taskcafe/internal/route"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var autoMigrate bool
|
||||
|
||||
func newWebCmd() *cobra.Command {
|
||||
cc := &cobra.Command{
|
||||
Use: "web",
|
||||
Short: "Run the web server",
|
||||
Long: "Run the web & api server",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Formatter := new(log.TextFormatter)
|
||||
Formatter.TimestampFormat = "02-01-2006 15:04:05"
|
||||
Formatter.FullTimestamp = true
|
||||
log.SetFormatter(Formatter)
|
||||
log.SetLevel(log.InfoLevel)
|
||||
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
redisClient, err := appConfig.MessageQueue.GetMessageQueueClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer redisClient.Close()
|
||||
|
||||
connection := appConfig.Database.GetDatabaseConnectionUri()
|
||||
var db *sqlx.DB
|
||||
var retryDuration time.Duration
|
||||
maxRetryNumber := 4
|
||||
for i := 0; i < maxRetryNumber; i++ {
|
||||
db, err = sqlx.Connect("postgres", connection)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
retryDuration = time.Duration(i*2) * time.Second
|
||||
log.WithFields(log.Fields{"retryNumber": i, "retryDuration": retryDuration}).WithError(err).Error("issue connecting to database, retrying")
|
||||
if i != maxRetryNumber-1 {
|
||||
time.Sleep(retryDuration)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db.SetMaxOpenConns(25)
|
||||
db.SetMaxIdleConns(25)
|
||||
db.SetConnMaxLifetime(5 * time.Minute)
|
||||
defer db.Close()
|
||||
|
||||
if viper.GetBool("migrate") {
|
||||
log.Info("running auto schema migrations")
|
||||
if err = runMigration(db); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var server *machinery.Server
|
||||
jobConfig := appConfig.Job.GetJobConfig()
|
||||
server, err = machinery.NewServer(&jobConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signature := &mTasks.Signature{
|
||||
Name: "scheduleDueDateNotifications",
|
||||
}
|
||||
server.SendTask(signature)
|
||||
|
||||
r, _ := route.NewRouter(db, redisClient, server, appConfig)
|
||||
log.WithFields(log.Fields{"url": viper.GetString("server.hostname")}).Info("starting server")
|
||||
return http.ListenAndServe(viper.GetString("server.hostname"), r)
|
||||
},
|
||||
}
|
||||
|
||||
cc.Flags().Bool("migrate", false, "if true, auto run's schema migrations before starting the web server")
|
||||
|
||||
viper.BindPFlag("migrate", cc.Flags().Lookup("migrate"))
|
||||
viper.SetDefault("migrate", false)
|
||||
return cc
|
||||
}
|
||||
|
||||
func runMigration(db *sqlx.DB) error {
|
||||
driver, err := postgres.WithInstance(db.DB, &postgres.Config{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
src, err := httpfs.New(migration, "./")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := migrate.NewWithInstance("httpfs", src, "postgres", driver)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger := &MigrateLog{}
|
||||
m.Log = logger
|
||||
err = m.Up()
|
||||
if err != nil && err != migrate.ErrNoChange {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/RichardKnop/machinery/v1"
|
||||
queueLog "github.com/RichardKnop/machinery/v1/log"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
repo "github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/jordanknott/taskcafe/internal/jobs"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func newWorkerCmd() *cobra.Command {
|
||||
cc := &cobra.Command{
|
||||
Use: "worker",
|
||||
Short: "Run the task queue worker",
|
||||
Long: "Run the task queue worker",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
Formatter := new(log.TextFormatter)
|
||||
Formatter.TimestampFormat = "02-01-2006 15:04:05"
|
||||
Formatter.FullTimestamp = true
|
||||
log.SetFormatter(Formatter)
|
||||
log.SetLevel(log.InfoLevel)
|
||||
|
||||
appConfig, err := config.GetAppConfig()
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
db, err := sqlx.Connect("postgres", config.GetDatabaseConfig().GetDatabaseConnectionUri())
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
db.SetMaxOpenConns(25)
|
||||
db.SetMaxIdleConns(25)
|
||||
db.SetConnMaxLifetime(5 * time.Minute)
|
||||
defer db.Close()
|
||||
|
||||
log.Info("starting task queue server instance")
|
||||
jobConfig := appConfig.Job.GetJobConfig()
|
||||
server, err := machinery.NewServer(&jobConfig)
|
||||
if err != nil {
|
||||
// do something with the error
|
||||
}
|
||||
queueLog.Set(&jobs.MachineryLogger{})
|
||||
repo := *repo.NewRepository(db)
|
||||
redisClient, err := appConfig.MessageQueue.GetMessageQueueClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
jobs.RegisterTasks(server, repo, appConfig, redisClient)
|
||||
|
||||
worker := server.NewWorker("taskcafe_worker", 10)
|
||||
log.Info("starting task queue worker")
|
||||
err = worker.Launch()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while launching ")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return cc
|
||||
}
|
@ -22,7 +22,7 @@ const (
|
||||
DatabaseUser = "database.user"
|
||||
DatabasePassword = "database.password"
|
||||
DatabasePort = "database.port"
|
||||
DatabaseSslMode = "database.sslmode"
|
||||
DatabaseSslMode = "database.ssl_mode"
|
||||
|
||||
SecurityTokenExpiration = "security.token_expiration"
|
||||
SecuritySecret = "security.secret"
|
||||
@ -132,6 +132,15 @@ type DatabaseConfig struct {
|
||||
SslMode string
|
||||
}
|
||||
|
||||
func (cfg DatabaseConfig) GetDatabaseStandardUri() string {
|
||||
return fmt.Sprintf("postgresql://%s:%s@%s:%s/%s",
|
||||
cfg.Username,
|
||||
cfg.Password,
|
||||
cfg.Host,
|
||||
cfg.Port,
|
||||
cfg.Name,
|
||||
)
|
||||
}
|
||||
func (cfg DatabaseConfig) GetDatabaseConnectionUri() string {
|
||||
connection := fmt.Sprintf("user=%s password=%s host=%s dbname=%s port=%s sslmode=%s",
|
||||
cfg.Username,
|
||||
|
@ -1,81 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: label_color.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const createLabelColor = `-- name: CreateLabelColor :one
|
||||
INSERT INTO label_color (name, color_hex, position) VALUES ($1, $2, $3)
|
||||
RETURNING label_color_id, color_hex, position, name
|
||||
`
|
||||
|
||||
type CreateLabelColorParams struct {
|
||||
Name string `json:"name"`
|
||||
ColorHex string `json:"color_hex"`
|
||||
Position float64 `json:"position"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateLabelColor(ctx context.Context, arg CreateLabelColorParams) (LabelColor, error) {
|
||||
row := q.db.QueryRowContext(ctx, createLabelColor, arg.Name, arg.ColorHex, arg.Position)
|
||||
var i LabelColor
|
||||
err := row.Scan(
|
||||
&i.LabelColorID,
|
||||
&i.ColorHex,
|
||||
&i.Position,
|
||||
&i.Name,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getLabelColorByID = `-- name: GetLabelColorByID :one
|
||||
SELECT label_color_id, color_hex, position, name FROM label_color WHERE label_color_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetLabelColorByID(ctx context.Context, labelColorID uuid.UUID) (LabelColor, error) {
|
||||
row := q.db.QueryRowContext(ctx, getLabelColorByID, labelColorID)
|
||||
var i LabelColor
|
||||
err := row.Scan(
|
||||
&i.LabelColorID,
|
||||
&i.ColorHex,
|
||||
&i.Position,
|
||||
&i.Name,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getLabelColors = `-- name: GetLabelColors :many
|
||||
SELECT label_color_id, color_hex, position, name FROM label_color
|
||||
`
|
||||
|
||||
func (q *Queries) GetLabelColors(ctx context.Context) ([]LabelColor, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getLabelColors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []LabelColor
|
||||
for rows.Next() {
|
||||
var i LabelColor
|
||||
if err := rows.Scan(
|
||||
&i.LabelColorID,
|
||||
&i.ColorHex,
|
||||
&i.Position,
|
||||
&i.Name,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
@ -4,261 +4,24 @@ package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type AccountSetting struct {
|
||||
AccountSettingID string `json:"account_setting_id"`
|
||||
Constrained bool `json:"constrained"`
|
||||
DataType string `json:"data_type"`
|
||||
ConstrainedDefaultValue sql.NullString `json:"constrained_default_value"`
|
||||
UnconstrainedDefaultValue sql.NullString `json:"unconstrained_default_value"`
|
||||
}
|
||||
|
||||
type AccountSettingAllowedValue struct {
|
||||
AllowedValueID uuid.UUID `json:"allowed_value_id"`
|
||||
SettingID int32 `json:"setting_id"`
|
||||
ItemValue string `json:"item_value"`
|
||||
}
|
||||
|
||||
type AccountSettingDataType struct {
|
||||
DataTypeID string `json:"data_type_id"`
|
||||
}
|
||||
|
||||
type AccountSettingValue struct {
|
||||
AccountSettingID uuid.UUID `json:"account_setting_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
SettingID int32 `json:"setting_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
AllowedValueID uuid.UUID `json:"allowed_value_id"`
|
||||
UnconstrainedValue sql.NullString `json:"unconstrained_value"`
|
||||
}
|
||||
|
||||
type AuthToken struct {
|
||||
TokenID uuid.UUID `json:"token_id"`
|
||||
type AccessToken struct {
|
||||
Token string `json:"token"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
}
|
||||
|
||||
type LabelColor struct {
|
||||
LabelColorID uuid.UUID `json:"label_color_id"`
|
||||
ColorHex string `json:"color_hex"`
|
||||
Position float64 `json:"position"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type Notification struct {
|
||||
NotificationID uuid.UUID `json:"notification_id"`
|
||||
CausedBy uuid.UUID `json:"caused_by"`
|
||||
ActionType string `json:"action_type"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
}
|
||||
|
||||
type NotificationNotified struct {
|
||||
NotifiedID uuid.UUID `json:"notified_id"`
|
||||
NotificationID uuid.UUID `json:"notification_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
Read bool `json:"read"`
|
||||
ReadAt sql.NullTime `json:"read_at"`
|
||||
}
|
||||
|
||||
type Organization struct {
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type PersonalProject struct {
|
||||
PersonalProjectID uuid.UUID `json:"personal_project_id"`
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
}
|
||||
|
||||
type Project struct {
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
TeamID uuid.UUID `json:"team_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
PublicOn sql.NullTime `json:"public_on"`
|
||||
ShortID string `json:"short_id"`
|
||||
}
|
||||
|
||||
type ProjectLabel struct {
|
||||
ProjectLabelID uuid.UUID `json:"project_label_id"`
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
LabelColorID uuid.UUID `json:"label_color_id"`
|
||||
CreatedDate time.Time `json:"created_date"`
|
||||
Name sql.NullString `json:"name"`
|
||||
}
|
||||
|
||||
type ProjectMember struct {
|
||||
ProjectMemberID uuid.UUID `json:"project_member_id"`
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
AddedAt time.Time `json:"added_at"`
|
||||
RoleCode string `json:"role_code"`
|
||||
}
|
||||
|
||||
type ProjectMemberInvited struct {
|
||||
ProjectMemberInvitedID uuid.UUID `json:"project_member_invited_id"`
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
UserAccountInvitedID uuid.UUID `json:"user_account_invited_id"`
|
||||
}
|
||||
|
||||
type Role struct {
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type SystemOption struct {
|
||||
OptionID uuid.UUID `json:"option_id"`
|
||||
Key string `json:"key"`
|
||||
Value sql.NullString `json:"value"`
|
||||
}
|
||||
|
||||
type Task struct {
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
TaskGroupID uuid.UUID `json:"task_group_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
Position float64 `json:"position"`
|
||||
Description sql.NullString `json:"description"`
|
||||
DueDate sql.NullTime `json:"due_date"`
|
||||
Complete bool `json:"complete"`
|
||||
CompletedAt sql.NullTime `json:"completed_at"`
|
||||
HasTime bool `json:"has_time"`
|
||||
ShortID string `json:"short_id"`
|
||||
}
|
||||
|
||||
type TaskActivity struct {
|
||||
TaskActivityID uuid.UUID `json:"task_activity_id"`
|
||||
Active bool `json:"active"`
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
CausedBy uuid.UUID `json:"caused_by"`
|
||||
ActivityTypeID int32 `json:"activity_type_id"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
type TaskActivityType struct {
|
||||
TaskActivityTypeID int32 `json:"task_activity_type_id"`
|
||||
Code string `json:"code"`
|
||||
Template string `json:"template"`
|
||||
}
|
||||
|
||||
type TaskAssigned struct {
|
||||
TaskAssignedID uuid.UUID `json:"task_assigned_id"`
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
AssignedDate time.Time `json:"assigned_date"`
|
||||
}
|
||||
|
||||
type TaskChecklist struct {
|
||||
TaskChecklistID uuid.UUID `json:"task_checklist_id"`
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
Position float64 `json:"position"`
|
||||
}
|
||||
|
||||
type TaskChecklistItem struct {
|
||||
TaskChecklistItemID uuid.UUID `json:"task_checklist_item_id"`
|
||||
TaskChecklistID uuid.UUID `json:"task_checklist_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Complete bool `json:"complete"`
|
||||
Name string `json:"name"`
|
||||
Position float64 `json:"position"`
|
||||
DueDate sql.NullTime `json:"due_date"`
|
||||
}
|
||||
|
||||
type TaskComment struct {
|
||||
TaskCommentID uuid.UUID `json:"task_comment_id"`
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt sql.NullTime `json:"updated_at"`
|
||||
CreatedBy uuid.UUID `json:"created_by"`
|
||||
Pinned bool `json:"pinned"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type TaskDueDateReminder struct {
|
||||
DueDateReminderID uuid.UUID `json:"due_date_reminder_id"`
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
Period int32 `json:"period"`
|
||||
Duration string `json:"duration"`
|
||||
RemindAt time.Time `json:"remind_at"`
|
||||
}
|
||||
|
||||
type TaskDueDateReminderDuration struct {
|
||||
Code string `json:"code"`
|
||||
}
|
||||
|
||||
type TaskGroup struct {
|
||||
TaskGroupID uuid.UUID `json:"task_group_id"`
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
Position float64 `json:"position"`
|
||||
}
|
||||
|
||||
type TaskLabel struct {
|
||||
TaskLabelID uuid.UUID `json:"task_label_id"`
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
ProjectLabelID uuid.UUID `json:"project_label_id"`
|
||||
AssignedDate time.Time `json:"assigned_date"`
|
||||
}
|
||||
|
||||
type TaskWatcher struct {
|
||||
TaskWatcherID uuid.UUID `json:"task_watcher_id"`
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
WatchedAt time.Time `json:"watched_at"`
|
||||
}
|
||||
|
||||
type Team struct {
|
||||
TeamID uuid.UUID `json:"team_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
}
|
||||
|
||||
type TeamMember struct {
|
||||
TeamMemberID uuid.UUID `json:"team_member_id"`
|
||||
TeamID uuid.UUID `json:"team_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
Addeddate time.Time `json:"addeddate"`
|
||||
RoleCode string `json:"role_code"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type UserAccount struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Email string `json:"email"`
|
||||
Username string `json:"username"`
|
||||
PasswordHash string `json:"password_hash"`
|
||||
ProfileBgColor string `json:"profile_bg_color"`
|
||||
FullName string `json:"full_name"`
|
||||
Initials string `json:"initials"`
|
||||
ProfileAvatarUrl sql.NullString `json:"profile_avatar_url"`
|
||||
RoleCode string `json:"role_code"`
|
||||
Bio string `json:"bio"`
|
||||
Active bool `json:"active"`
|
||||
}
|
||||
|
||||
type UserAccountConfirmToken struct {
|
||||
ConfirmTokenID uuid.UUID `json:"confirm_token_id"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
type UserAccountInvited struct {
|
||||
UserAccountInvitedID uuid.UUID `json:"user_account_invited_id"`
|
||||
Email string `json:"email"`
|
||||
InvitedOn time.Time `json:"invited_on"`
|
||||
HasJoined bool `json:"has_joined"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Fullname string `json:"fullname"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
PasswordHash string `json:"password_hash"`
|
||||
AvatarUrl sql.NullString `json:"avatar_url"`
|
||||
}
|
||||
|
@ -1,383 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: notification.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
const createNotification = `-- name: CreateNotification :one
|
||||
INSERT INTO notification (caused_by, data, action_type, created_on)
|
||||
VALUES ($1, $2, $3, $4) RETURNING notification_id, caused_by, action_type, data, created_on
|
||||
`
|
||||
|
||||
type CreateNotificationParams struct {
|
||||
CausedBy uuid.UUID `json:"caused_by"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
ActionType string `json:"action_type"`
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateNotification(ctx context.Context, arg CreateNotificationParams) (Notification, error) {
|
||||
row := q.db.QueryRowContext(ctx, createNotification,
|
||||
arg.CausedBy,
|
||||
arg.Data,
|
||||
arg.ActionType,
|
||||
arg.CreatedOn,
|
||||
)
|
||||
var i Notification
|
||||
err := row.Scan(
|
||||
&i.NotificationID,
|
||||
&i.CausedBy,
|
||||
&i.ActionType,
|
||||
&i.Data,
|
||||
&i.CreatedOn,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createNotificationNotifed = `-- name: CreateNotificationNotifed :one
|
||||
INSERT INTO notification_notified (notification_id, user_id) VALUES ($1, $2) RETURNING notified_id, notification_id, user_id, read, read_at
|
||||
`
|
||||
|
||||
type CreateNotificationNotifedParams struct {
|
||||
NotificationID uuid.UUID `json:"notification_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateNotificationNotifed(ctx context.Context, arg CreateNotificationNotifedParams) (NotificationNotified, error) {
|
||||
row := q.db.QueryRowContext(ctx, createNotificationNotifed, arg.NotificationID, arg.UserID)
|
||||
var i NotificationNotified
|
||||
err := row.Scan(
|
||||
&i.NotifiedID,
|
||||
&i.NotificationID,
|
||||
&i.UserID,
|
||||
&i.Read,
|
||||
&i.ReadAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getAllNotificationsForUserID = `-- name: GetAllNotificationsForUserID :many
|
||||
SELECT notified_id, nn.notification_id, user_id, read, read_at, n.notification_id, caused_by, action_type, data, created_on FROM notification_notified AS nn
|
||||
INNER JOIN notification AS n ON n.notification_id = nn.notification_id
|
||||
WHERE nn.user_id = $1
|
||||
`
|
||||
|
||||
type GetAllNotificationsForUserIDRow struct {
|
||||
NotifiedID uuid.UUID `json:"notified_id"`
|
||||
NotificationID uuid.UUID `json:"notification_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
Read bool `json:"read"`
|
||||
ReadAt sql.NullTime `json:"read_at"`
|
||||
NotificationID_2 uuid.UUID `json:"notification_id_2"`
|
||||
CausedBy uuid.UUID `json:"caused_by"`
|
||||
ActionType string `json:"action_type"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetAllNotificationsForUserID(ctx context.Context, userID uuid.UUID) ([]GetAllNotificationsForUserIDRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getAllNotificationsForUserID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetAllNotificationsForUserIDRow
|
||||
for rows.Next() {
|
||||
var i GetAllNotificationsForUserIDRow
|
||||
if err := rows.Scan(
|
||||
&i.NotifiedID,
|
||||
&i.NotificationID,
|
||||
&i.UserID,
|
||||
&i.Read,
|
||||
&i.ReadAt,
|
||||
&i.NotificationID_2,
|
||||
&i.CausedBy,
|
||||
&i.ActionType,
|
||||
&i.Data,
|
||||
&i.CreatedOn,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getNotificationByID = `-- name: GetNotificationByID :one
|
||||
SELECT notification_id, caused_by, action_type, data, created_on FROM notification WHERE notification_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetNotificationByID(ctx context.Context, notificationID uuid.UUID) (Notification, error) {
|
||||
row := q.db.QueryRowContext(ctx, getNotificationByID, notificationID)
|
||||
var i Notification
|
||||
err := row.Scan(
|
||||
&i.NotificationID,
|
||||
&i.CausedBy,
|
||||
&i.ActionType,
|
||||
&i.Data,
|
||||
&i.CreatedOn,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getNotificationsForUserIDCursor = `-- name: GetNotificationsForUserIDCursor :many
|
||||
SELECT n.notification_id, n.caused_by, n.action_type, n.data, n.created_on, nn.notified_id, nn.notification_id, nn.user_id, nn.read, nn.read_at FROM notification_notified AS nn
|
||||
INNER JOIN notification AS n ON n.notification_id = nn.notification_id
|
||||
WHERE (n.created_on, n.notification_id) < ($1::timestamptz, $2::uuid)
|
||||
AND nn.user_id = $3::uuid
|
||||
AND ($4::boolean = false OR nn.read = false)
|
||||
AND ($5::boolean = false OR n.action_type = ANY($6::text[]))
|
||||
ORDER BY n.created_on DESC
|
||||
LIMIT $7::int
|
||||
`
|
||||
|
||||
type GetNotificationsForUserIDCursorParams struct {
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
NotificationID uuid.UUID `json:"notification_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
EnableUnread bool `json:"enable_unread"`
|
||||
EnableActionType bool `json:"enable_action_type"`
|
||||
ActionType []string `json:"action_type"`
|
||||
LimitRows int32 `json:"limit_rows"`
|
||||
}
|
||||
|
||||
type GetNotificationsForUserIDCursorRow struct {
|
||||
NotificationID uuid.UUID `json:"notification_id"`
|
||||
CausedBy uuid.UUID `json:"caused_by"`
|
||||
ActionType string `json:"action_type"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
NotifiedID uuid.UUID `json:"notified_id"`
|
||||
NotificationID_2 uuid.UUID `json:"notification_id_2"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
Read bool `json:"read"`
|
||||
ReadAt sql.NullTime `json:"read_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetNotificationsForUserIDCursor(ctx context.Context, arg GetNotificationsForUserIDCursorParams) ([]GetNotificationsForUserIDCursorRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getNotificationsForUserIDCursor,
|
||||
arg.CreatedOn,
|
||||
arg.NotificationID,
|
||||
arg.UserID,
|
||||
arg.EnableUnread,
|
||||
arg.EnableActionType,
|
||||
pq.Array(arg.ActionType),
|
||||
arg.LimitRows,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetNotificationsForUserIDCursorRow
|
||||
for rows.Next() {
|
||||
var i GetNotificationsForUserIDCursorRow
|
||||
if err := rows.Scan(
|
||||
&i.NotificationID,
|
||||
&i.CausedBy,
|
||||
&i.ActionType,
|
||||
&i.Data,
|
||||
&i.CreatedOn,
|
||||
&i.NotifiedID,
|
||||
&i.NotificationID_2,
|
||||
&i.UserID,
|
||||
&i.Read,
|
||||
&i.ReadAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getNotificationsForUserIDPaged = `-- name: GetNotificationsForUserIDPaged :many
|
||||
SELECT n.notification_id, n.caused_by, n.action_type, n.data, n.created_on, nn.notified_id, nn.notification_id, nn.user_id, nn.read, nn.read_at FROM notification_notified AS nn
|
||||
INNER JOIN notification AS n ON n.notification_id = nn.notification_id
|
||||
WHERE nn.user_id = $1::uuid
|
||||
AND ($2::boolean = false OR nn.read = false)
|
||||
AND ($3::boolean = false OR n.action_type = ANY($4::text[]))
|
||||
ORDER BY n.created_on DESC
|
||||
LIMIT $5::int
|
||||
`
|
||||
|
||||
type GetNotificationsForUserIDPagedParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
EnableUnread bool `json:"enable_unread"`
|
||||
EnableActionType bool `json:"enable_action_type"`
|
||||
ActionType []string `json:"action_type"`
|
||||
LimitRows int32 `json:"limit_rows"`
|
||||
}
|
||||
|
||||
type GetNotificationsForUserIDPagedRow struct {
|
||||
NotificationID uuid.UUID `json:"notification_id"`
|
||||
CausedBy uuid.UUID `json:"caused_by"`
|
||||
ActionType string `json:"action_type"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
NotifiedID uuid.UUID `json:"notified_id"`
|
||||
NotificationID_2 uuid.UUID `json:"notification_id_2"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
Read bool `json:"read"`
|
||||
ReadAt sql.NullTime `json:"read_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetNotificationsForUserIDPaged(ctx context.Context, arg GetNotificationsForUserIDPagedParams) ([]GetNotificationsForUserIDPagedRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getNotificationsForUserIDPaged,
|
||||
arg.UserID,
|
||||
arg.EnableUnread,
|
||||
arg.EnableActionType,
|
||||
pq.Array(arg.ActionType),
|
||||
arg.LimitRows,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetNotificationsForUserIDPagedRow
|
||||
for rows.Next() {
|
||||
var i GetNotificationsForUserIDPagedRow
|
||||
if err := rows.Scan(
|
||||
&i.NotificationID,
|
||||
&i.CausedBy,
|
||||
&i.ActionType,
|
||||
&i.Data,
|
||||
&i.CreatedOn,
|
||||
&i.NotifiedID,
|
||||
&i.NotificationID_2,
|
||||
&i.UserID,
|
||||
&i.Read,
|
||||
&i.ReadAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getNotifiedByID = `-- name: GetNotifiedByID :one
|
||||
SELECT notified_id, nn.notification_id, user_id, read, read_at, n.notification_id, caused_by, action_type, data, created_on FROM notification_notified as nn
|
||||
INNER JOIN notification AS n ON n.notification_id = nn.notification_id
|
||||
WHERE notified_id = $1
|
||||
`
|
||||
|
||||
type GetNotifiedByIDRow struct {
|
||||
NotifiedID uuid.UUID `json:"notified_id"`
|
||||
NotificationID uuid.UUID `json:"notification_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
Read bool `json:"read"`
|
||||
ReadAt sql.NullTime `json:"read_at"`
|
||||
NotificationID_2 uuid.UUID `json:"notification_id_2"`
|
||||
CausedBy uuid.UUID `json:"caused_by"`
|
||||
ActionType string `json:"action_type"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
CreatedOn time.Time `json:"created_on"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetNotifiedByID(ctx context.Context, notifiedID uuid.UUID) (GetNotifiedByIDRow, error) {
|
||||
row := q.db.QueryRowContext(ctx, getNotifiedByID, notifiedID)
|
||||
var i GetNotifiedByIDRow
|
||||
err := row.Scan(
|
||||
&i.NotifiedID,
|
||||
&i.NotificationID,
|
||||
&i.UserID,
|
||||
&i.Read,
|
||||
&i.ReadAt,
|
||||
&i.NotificationID_2,
|
||||
&i.CausedBy,
|
||||
&i.ActionType,
|
||||
&i.Data,
|
||||
&i.CreatedOn,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getNotifiedByIDNoExtra = `-- name: GetNotifiedByIDNoExtra :one
|
||||
SELECT notified_id, notification_id, user_id, read, read_at FROM notification_notified as nn WHERE nn.notified_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetNotifiedByIDNoExtra(ctx context.Context, notifiedID uuid.UUID) (NotificationNotified, error) {
|
||||
row := q.db.QueryRowContext(ctx, getNotifiedByIDNoExtra, notifiedID)
|
||||
var i NotificationNotified
|
||||
err := row.Scan(
|
||||
&i.NotifiedID,
|
||||
&i.NotificationID,
|
||||
&i.UserID,
|
||||
&i.Read,
|
||||
&i.ReadAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const hasUnreadNotification = `-- name: HasUnreadNotification :one
|
||||
SELECT EXISTS (SELECT 1 FROM notification_notified WHERE read = false AND user_id = $1)
|
||||
`
|
||||
|
||||
func (q *Queries) HasUnreadNotification(ctx context.Context, userID uuid.UUID) (bool, error) {
|
||||
row := q.db.QueryRowContext(ctx, hasUnreadNotification, userID)
|
||||
var exists bool
|
||||
err := row.Scan(&exists)
|
||||
return exists, err
|
||||
}
|
||||
|
||||
const markAllNotificationsRead = `-- name: MarkAllNotificationsRead :exec
|
||||
UPDATE notification_notified SET read = true, read_at = $2 WHERE user_id = $1
|
||||
`
|
||||
|
||||
type MarkAllNotificationsReadParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
ReadAt sql.NullTime `json:"read_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) MarkAllNotificationsRead(ctx context.Context, arg MarkAllNotificationsReadParams) error {
|
||||
_, err := q.db.ExecContext(ctx, markAllNotificationsRead, arg.UserID, arg.ReadAt)
|
||||
return err
|
||||
}
|
||||
|
||||
const markNotificationAsRead = `-- name: MarkNotificationAsRead :exec
|
||||
UPDATE notification_notified SET read = $3, read_at = $2 WHERE user_id = $1 AND notified_id = $4
|
||||
`
|
||||
|
||||
type MarkNotificationAsReadParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
ReadAt sql.NullTime `json:"read_at"`
|
||||
Read bool `json:"read"`
|
||||
NotifiedID uuid.UUID `json:"notified_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) MarkNotificationAsRead(ctx context.Context, arg MarkNotificationAsReadParams) error {
|
||||
_, err := q.db.ExecContext(ctx, markNotificationAsRead,
|
||||
arg.UserID,
|
||||
arg.ReadAt,
|
||||
arg.Read,
|
||||
arg.NotifiedID,
|
||||
)
|
||||
return err
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: organization.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
const createOrganization = `-- name: CreateOrganization :one
|
||||
INSERT INTO organization (created_at, name) VALUES ($1, $2) RETURNING organization_id, created_at, name
|
||||
`
|
||||
|
||||
type CreateOrganizationParams struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateOrganization(ctx context.Context, arg CreateOrganizationParams) (Organization, error) {
|
||||
row := q.db.QueryRowContext(ctx, createOrganization, arg.CreatedAt, arg.Name)
|
||||
var i Organization
|
||||
err := row.Scan(&i.OrganizationID, &i.CreatedAt, &i.Name)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getAllOrganizations = `-- name: GetAllOrganizations :many
|
||||
SELECT organization_id, created_at, name FROM organization
|
||||
`
|
||||
|
||||
func (q *Queries) GetAllOrganizations(ctx context.Context) ([]Organization, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getAllOrganizations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Organization
|
||||
for rows.Next() {
|
||||
var i Organization
|
||||
if err := rows.Scan(&i.OrganizationID, &i.CreatedAt, &i.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
@ -1,577 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: project.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const createPersonalProject = `-- name: CreatePersonalProject :one
|
||||
INSERT INTO project(team_id, created_at, name) VALUES (null, $1, $2) RETURNING project_id, team_id, created_at, name, public_on, short_id
|
||||
`
|
||||
|
||||
type CreatePersonalProjectParams struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreatePersonalProject(ctx context.Context, arg CreatePersonalProjectParams) (Project, error) {
|
||||
row := q.db.QueryRowContext(ctx, createPersonalProject, arg.CreatedAt, arg.Name)
|
||||
var i Project
|
||||
err := row.Scan(
|
||||
&i.ProjectID,
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.PublicOn,
|
||||
&i.ShortID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createPersonalProjectLink = `-- name: CreatePersonalProjectLink :one
|
||||
INSERT INTO personal_project (project_id, user_id) VALUES ($1, $2) RETURNING personal_project_id, project_id, user_id
|
||||
`
|
||||
|
||||
type CreatePersonalProjectLinkParams struct {
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreatePersonalProjectLink(ctx context.Context, arg CreatePersonalProjectLinkParams) (PersonalProject, error) {
|
||||
row := q.db.QueryRowContext(ctx, createPersonalProjectLink, arg.ProjectID, arg.UserID)
|
||||
var i PersonalProject
|
||||
err := row.Scan(&i.PersonalProjectID, &i.ProjectID, &i.UserID)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createProjectMember = `-- name: CreateProjectMember :one
|
||||
INSERT INTO project_member (project_id, user_id, role_code, added_at) VALUES ($1, $2, $3, $4)
|
||||
RETURNING project_member_id, project_id, user_id, added_at, role_code
|
||||
`
|
||||
|
||||
type CreateProjectMemberParams struct {
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
RoleCode string `json:"role_code"`
|
||||
AddedAt time.Time `json:"added_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateProjectMember(ctx context.Context, arg CreateProjectMemberParams) (ProjectMember, error) {
|
||||
row := q.db.QueryRowContext(ctx, createProjectMember,
|
||||
arg.ProjectID,
|
||||
arg.UserID,
|
||||
arg.RoleCode,
|
||||
arg.AddedAt,
|
||||
)
|
||||
var i ProjectMember
|
||||
err := row.Scan(
|
||||
&i.ProjectMemberID,
|
||||
&i.ProjectID,
|
||||
&i.UserID,
|
||||
&i.AddedAt,
|
||||
&i.RoleCode,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createTeamProject = `-- name: CreateTeamProject :one
|
||||
INSERT INTO project(team_id, created_at, name) VALUES ($1, $2, $3) RETURNING project_id, team_id, created_at, name, public_on, short_id
|
||||
`
|
||||
|
||||
type CreateTeamProjectParams struct {
|
||||
TeamID uuid.UUID `json:"team_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateTeamProject(ctx context.Context, arg CreateTeamProjectParams) (Project, error) {
|
||||
row := q.db.QueryRowContext(ctx, createTeamProject, arg.TeamID, arg.CreatedAt, arg.Name)
|
||||
var i Project
|
||||
err := row.Scan(
|
||||
&i.ProjectID,
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.PublicOn,
|
||||
&i.ShortID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteInvitedProjectMemberByID = `-- name: DeleteInvitedProjectMemberByID :exec
|
||||
DELETE FROM project_member_invited WHERE project_member_invited_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteInvitedProjectMemberByID(ctx context.Context, projectMemberInvitedID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteInvitedProjectMemberByID, projectMemberInvitedID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteProjectByID = `-- name: DeleteProjectByID :exec
|
||||
DELETE FROM project WHERE project_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteProjectByID(ctx context.Context, projectID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteProjectByID, projectID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteProjectMember = `-- name: DeleteProjectMember :exec
|
||||
DELETE FROM project_member WHERE user_id = $1 AND project_id = $2
|
||||
`
|
||||
|
||||
type DeleteProjectMemberParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) DeleteProjectMember(ctx context.Context, arg DeleteProjectMemberParams) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteProjectMember, arg.UserID, arg.ProjectID)
|
||||
return err
|
||||
}
|
||||
|
||||
const getAllProjectsForTeam = `-- name: GetAllProjectsForTeam :many
|
||||
SELECT project_id, team_id, created_at, name, public_on, short_id FROM project WHERE team_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetAllProjectsForTeam(ctx context.Context, teamID uuid.UUID) ([]Project, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getAllProjectsForTeam, teamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Project
|
||||
for rows.Next() {
|
||||
var i Project
|
||||
if err := rows.Scan(
|
||||
&i.ProjectID,
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.PublicOn,
|
||||
&i.ShortID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getAllTeamProjects = `-- name: GetAllTeamProjects :many
|
||||
SELECT project_id, team_id, created_at, name, public_on, short_id FROM project WHERE team_id IS NOT null
|
||||
`
|
||||
|
||||
func (q *Queries) GetAllTeamProjects(ctx context.Context) ([]Project, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getAllTeamProjects)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Project
|
||||
for rows.Next() {
|
||||
var i Project
|
||||
if err := rows.Scan(
|
||||
&i.ProjectID,
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.PublicOn,
|
||||
&i.ShortID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getAllVisibleProjectsForUserID = `-- name: GetAllVisibleProjectsForUserID :many
|
||||
SELECT project.project_id, project.team_id, project.created_at, project.name, project.public_on, project.short_id FROM project LEFT JOIN
|
||||
project_member ON project_member.project_id = project.project_id WHERE project_member.user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetAllVisibleProjectsForUserID(ctx context.Context, userID uuid.UUID) ([]Project, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getAllVisibleProjectsForUserID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Project
|
||||
for rows.Next() {
|
||||
var i Project
|
||||
if err := rows.Scan(
|
||||
&i.ProjectID,
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.PublicOn,
|
||||
&i.ShortID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getInvitedMembersForProjectID = `-- name: GetInvitedMembersForProjectID :many
|
||||
SELECT uai.user_account_invited_id, email, invited_on FROM project_member_invited AS pmi
|
||||
INNER JOIN user_account_invited AS uai
|
||||
ON uai.user_account_invited_id = pmi.user_account_invited_id
|
||||
WHERE project_id = $1
|
||||
`
|
||||
|
||||
type GetInvitedMembersForProjectIDRow struct {
|
||||
UserAccountInvitedID uuid.UUID `json:"user_account_invited_id"`
|
||||
Email string `json:"email"`
|
||||
InvitedOn time.Time `json:"invited_on"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetInvitedMembersForProjectID(ctx context.Context, projectID uuid.UUID) ([]GetInvitedMembersForProjectIDRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getInvitedMembersForProjectID, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetInvitedMembersForProjectIDRow
|
||||
for rows.Next() {
|
||||
var i GetInvitedMembersForProjectIDRow
|
||||
if err := rows.Scan(&i.UserAccountInvitedID, &i.Email, &i.InvitedOn); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getMemberProjectIDsForUserID = `-- name: GetMemberProjectIDsForUserID :many
|
||||
SELECT project_id FROM project_member WHERE user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetMemberProjectIDsForUserID(ctx context.Context, userID uuid.UUID) ([]uuid.UUID, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getMemberProjectIDsForUserID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []uuid.UUID
|
||||
for rows.Next() {
|
||||
var project_id uuid.UUID
|
||||
if err := rows.Scan(&project_id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, project_id)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getPersonalProjectsForUserID = `-- name: GetPersonalProjectsForUserID :many
|
||||
SELECT project.project_id, project.team_id, project.created_at, project.name, project.public_on, project.short_id FROM project
|
||||
LEFT JOIN personal_project ON personal_project.project_id = project.project_id
|
||||
WHERE personal_project.user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetPersonalProjectsForUserID(ctx context.Context, userID uuid.UUID) ([]Project, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getPersonalProjectsForUserID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Project
|
||||
for rows.Next() {
|
||||
var i Project
|
||||
if err := rows.Scan(
|
||||
&i.ProjectID,
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.PublicOn,
|
||||
&i.ShortID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getProjectByID = `-- name: GetProjectByID :one
|
||||
SELECT project_id, team_id, created_at, name, public_on, short_id FROM project WHERE project_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetProjectByID(ctx context.Context, projectID uuid.UUID) (Project, error) {
|
||||
row := q.db.QueryRowContext(ctx, getProjectByID, projectID)
|
||||
var i Project
|
||||
err := row.Scan(
|
||||
&i.ProjectID,
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.PublicOn,
|
||||
&i.ShortID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getProjectIDByShortID = `-- name: GetProjectIDByShortID :one
|
||||
SELECT project_id FROM project WHERE short_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetProjectIDByShortID(ctx context.Context, shortID string) (uuid.UUID, error) {
|
||||
row := q.db.QueryRowContext(ctx, getProjectIDByShortID, shortID)
|
||||
var project_id uuid.UUID
|
||||
err := row.Scan(&project_id)
|
||||
return project_id, err
|
||||
}
|
||||
|
||||
const getProjectMemberInvitedIDByEmail = `-- name: GetProjectMemberInvitedIDByEmail :one
|
||||
SELECT email, invited_on, project_member_invited_id FROM user_account_invited AS uai
|
||||
inner join project_member_invited AS pmi
|
||||
ON pmi.user_account_invited_id = uai.user_account_invited_id
|
||||
WHERE email = $1
|
||||
`
|
||||
|
||||
type GetProjectMemberInvitedIDByEmailRow struct {
|
||||
Email string `json:"email"`
|
||||
InvitedOn time.Time `json:"invited_on"`
|
||||
ProjectMemberInvitedID uuid.UUID `json:"project_member_invited_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetProjectMemberInvitedIDByEmail(ctx context.Context, email string) (GetProjectMemberInvitedIDByEmailRow, error) {
|
||||
row := q.db.QueryRowContext(ctx, getProjectMemberInvitedIDByEmail, email)
|
||||
var i GetProjectMemberInvitedIDByEmailRow
|
||||
err := row.Scan(&i.Email, &i.InvitedOn, &i.ProjectMemberInvitedID)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getProjectMembersForProjectID = `-- name: GetProjectMembersForProjectID :many
|
||||
SELECT project_member_id, project_id, user_id, added_at, role_code FROM project_member WHERE project_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetProjectMembersForProjectID(ctx context.Context, projectID uuid.UUID) ([]ProjectMember, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getProjectMembersForProjectID, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ProjectMember
|
||||
for rows.Next() {
|
||||
var i ProjectMember
|
||||
if err := rows.Scan(
|
||||
&i.ProjectMemberID,
|
||||
&i.ProjectID,
|
||||
&i.UserID,
|
||||
&i.AddedAt,
|
||||
&i.RoleCode,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getProjectRolesForUserID = `-- name: GetProjectRolesForUserID :many
|
||||
SELECT project_id, role_code FROM project_member WHERE user_id = $1
|
||||
`
|
||||
|
||||
type GetProjectRolesForUserIDRow struct {
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
RoleCode string `json:"role_code"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetProjectRolesForUserID(ctx context.Context, userID uuid.UUID) ([]GetProjectRolesForUserIDRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getProjectRolesForUserID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetProjectRolesForUserIDRow
|
||||
for rows.Next() {
|
||||
var i GetProjectRolesForUserIDRow
|
||||
if err := rows.Scan(&i.ProjectID, &i.RoleCode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getPublicOn = `-- name: GetPublicOn :one
|
||||
SELECT public_on FROM project WHERE project_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetPublicOn(ctx context.Context, projectID uuid.UUID) (sql.NullTime, error) {
|
||||
row := q.db.QueryRowContext(ctx, getPublicOn, projectID)
|
||||
var public_on sql.NullTime
|
||||
err := row.Scan(&public_on)
|
||||
return public_on, err
|
||||
}
|
||||
|
||||
const getRoleForProjectMemberByUserID = `-- name: GetRoleForProjectMemberByUserID :one
|
||||
SELECT code, role.name FROM project_member INNER JOIN role ON role.code = project_member.role_code
|
||||
WHERE user_id = $1 AND project_id = $2
|
||||
`
|
||||
|
||||
type GetRoleForProjectMemberByUserIDParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetRoleForProjectMemberByUserID(ctx context.Context, arg GetRoleForProjectMemberByUserIDParams) (Role, error) {
|
||||
row := q.db.QueryRowContext(ctx, getRoleForProjectMemberByUserID, arg.UserID, arg.ProjectID)
|
||||
var i Role
|
||||
err := row.Scan(&i.Code, &i.Name)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getUserRolesForProject = `-- name: GetUserRolesForProject :one
|
||||
SELECT p.team_id, COALESCE(tm.role_code, '') AS team_role, COALESCE(pm.role_code, '') AS project_role
|
||||
FROM project AS p
|
||||
LEFT JOIN project_member AS pm ON pm.project_id = p.project_id AND pm.user_id = $1
|
||||
LEFT JOIN team_member AS tm ON tm.team_id = p.team_id AND tm.user_id = $1
|
||||
WHERE p.project_id = $2
|
||||
`
|
||||
|
||||
type GetUserRolesForProjectParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
}
|
||||
|
||||
type GetUserRolesForProjectRow struct {
|
||||
TeamID uuid.UUID `json:"team_id"`
|
||||
TeamRole string `json:"team_role"`
|
||||
ProjectRole string `json:"project_role"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetUserRolesForProject(ctx context.Context, arg GetUserRolesForProjectParams) (GetUserRolesForProjectRow, error) {
|
||||
row := q.db.QueryRowContext(ctx, getUserRolesForProject, arg.UserID, arg.ProjectID)
|
||||
var i GetUserRolesForProjectRow
|
||||
err := row.Scan(&i.TeamID, &i.TeamRole, &i.ProjectRole)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const setPublicOn = `-- name: SetPublicOn :one
|
||||
UPDATE project SET public_on = $2 WHERE project_id = $1 RETURNING project_id, team_id, created_at, name, public_on, short_id
|
||||
`
|
||||
|
||||
type SetPublicOnParams struct {
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
PublicOn sql.NullTime `json:"public_on"`
|
||||
}
|
||||
|
||||
func (q *Queries) SetPublicOn(ctx context.Context, arg SetPublicOnParams) (Project, error) {
|
||||
row := q.db.QueryRowContext(ctx, setPublicOn, arg.ProjectID, arg.PublicOn)
|
||||
var i Project
|
||||
err := row.Scan(
|
||||
&i.ProjectID,
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.PublicOn,
|
||||
&i.ShortID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateProjectMemberRole = `-- name: UpdateProjectMemberRole :one
|
||||
UPDATE project_member SET role_code = $3 WHERE project_id = $1 AND user_id = $2
|
||||
RETURNING project_member_id, project_id, user_id, added_at, role_code
|
||||
`
|
||||
|
||||
type UpdateProjectMemberRoleParams struct {
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
RoleCode string `json:"role_code"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateProjectMemberRole(ctx context.Context, arg UpdateProjectMemberRoleParams) (ProjectMember, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateProjectMemberRole, arg.ProjectID, arg.UserID, arg.RoleCode)
|
||||
var i ProjectMember
|
||||
err := row.Scan(
|
||||
&i.ProjectMemberID,
|
||||
&i.ProjectID,
|
||||
&i.UserID,
|
||||
&i.AddedAt,
|
||||
&i.RoleCode,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateProjectNameByID = `-- name: UpdateProjectNameByID :one
|
||||
UPDATE project SET name = $2 WHERE project_id = $1 RETURNING project_id, team_id, created_at, name, public_on, short_id
|
||||
`
|
||||
|
||||
type UpdateProjectNameByIDParams struct {
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateProjectNameByID(ctx context.Context, arg UpdateProjectNameByIDParams) (Project, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateProjectNameByID, arg.ProjectID, arg.Name)
|
||||
var i Project
|
||||
err := row.Scan(
|
||||
&i.ProjectID,
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.PublicOn,
|
||||
&i.ShortID,
|
||||
)
|
||||
return i, err
|
||||
}
|
@ -1,168 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: project_label.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const createProjectLabel = `-- name: CreateProjectLabel :one
|
||||
INSERT INTO project_label (project_id, label_color_id, created_date, name)
|
||||
VALUES ($1, $2, $3, $4) RETURNING project_label_id, project_id, label_color_id, created_date, name
|
||||
`
|
||||
|
||||
type CreateProjectLabelParams struct {
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
LabelColorID uuid.UUID `json:"label_color_id"`
|
||||
CreatedDate time.Time `json:"created_date"`
|
||||
Name sql.NullString `json:"name"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateProjectLabel(ctx context.Context, arg CreateProjectLabelParams) (ProjectLabel, error) {
|
||||
row := q.db.QueryRowContext(ctx, createProjectLabel,
|
||||
arg.ProjectID,
|
||||
arg.LabelColorID,
|
||||
arg.CreatedDate,
|
||||
arg.Name,
|
||||
)
|
||||
var i ProjectLabel
|
||||
err := row.Scan(
|
||||
&i.ProjectLabelID,
|
||||
&i.ProjectID,
|
||||
&i.LabelColorID,
|
||||
&i.CreatedDate,
|
||||
&i.Name,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteProjectLabelByID = `-- name: DeleteProjectLabelByID :exec
|
||||
DELETE FROM project_label WHERE project_label_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteProjectLabelByID(ctx context.Context, projectLabelID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteProjectLabelByID, projectLabelID)
|
||||
return err
|
||||
}
|
||||
|
||||
const getProjectLabelByID = `-- name: GetProjectLabelByID :one
|
||||
SELECT project_label_id, project_id, label_color_id, created_date, name FROM project_label WHERE project_label_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetProjectLabelByID(ctx context.Context, projectLabelID uuid.UUID) (ProjectLabel, error) {
|
||||
row := q.db.QueryRowContext(ctx, getProjectLabelByID, projectLabelID)
|
||||
var i ProjectLabel
|
||||
err := row.Scan(
|
||||
&i.ProjectLabelID,
|
||||
&i.ProjectID,
|
||||
&i.LabelColorID,
|
||||
&i.CreatedDate,
|
||||
&i.Name,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getProjectLabelsForProject = `-- name: GetProjectLabelsForProject :many
|
||||
SELECT project_label_id, project_id, label_color_id, created_date, name FROM project_label WHERE project_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetProjectLabelsForProject(ctx context.Context, projectID uuid.UUID) ([]ProjectLabel, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getProjectLabelsForProject, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ProjectLabel
|
||||
for rows.Next() {
|
||||
var i ProjectLabel
|
||||
if err := rows.Scan(
|
||||
&i.ProjectLabelID,
|
||||
&i.ProjectID,
|
||||
&i.LabelColorID,
|
||||
&i.CreatedDate,
|
||||
&i.Name,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const updateProjectLabel = `-- name: UpdateProjectLabel :one
|
||||
UPDATE project_label SET name = $2, label_color_id = $3 WHERE project_label_id = $1 RETURNING project_label_id, project_id, label_color_id, created_date, name
|
||||
`
|
||||
|
||||
type UpdateProjectLabelParams struct {
|
||||
ProjectLabelID uuid.UUID `json:"project_label_id"`
|
||||
Name sql.NullString `json:"name"`
|
||||
LabelColorID uuid.UUID `json:"label_color_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateProjectLabel(ctx context.Context, arg UpdateProjectLabelParams) (ProjectLabel, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateProjectLabel, arg.ProjectLabelID, arg.Name, arg.LabelColorID)
|
||||
var i ProjectLabel
|
||||
err := row.Scan(
|
||||
&i.ProjectLabelID,
|
||||
&i.ProjectID,
|
||||
&i.LabelColorID,
|
||||
&i.CreatedDate,
|
||||
&i.Name,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateProjectLabelColor = `-- name: UpdateProjectLabelColor :one
|
||||
UPDATE project_label SET label_color_id = $2 WHERE project_label_id = $1 RETURNING project_label_id, project_id, label_color_id, created_date, name
|
||||
`
|
||||
|
||||
type UpdateProjectLabelColorParams struct {
|
||||
ProjectLabelID uuid.UUID `json:"project_label_id"`
|
||||
LabelColorID uuid.UUID `json:"label_color_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateProjectLabelColor(ctx context.Context, arg UpdateProjectLabelColorParams) (ProjectLabel, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateProjectLabelColor, arg.ProjectLabelID, arg.LabelColorID)
|
||||
var i ProjectLabel
|
||||
err := row.Scan(
|
||||
&i.ProjectLabelID,
|
||||
&i.ProjectID,
|
||||
&i.LabelColorID,
|
||||
&i.CreatedDate,
|
||||
&i.Name,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateProjectLabelName = `-- name: UpdateProjectLabelName :one
|
||||
UPDATE project_label SET name = $2 WHERE project_label_id = $1 RETURNING project_label_id, project_id, label_color_id, created_date, name
|
||||
`
|
||||
|
||||
type UpdateProjectLabelNameParams struct {
|
||||
ProjectLabelID uuid.UUID `json:"project_label_id"`
|
||||
Name sql.NullString `json:"name"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateProjectLabelName(ctx context.Context, arg UpdateProjectLabelNameParams) (ProjectLabel, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateProjectLabelName, arg.ProjectLabelID, arg.Name)
|
||||
var i ProjectLabel
|
||||
err := row.Scan(
|
||||
&i.ProjectLabelID,
|
||||
&i.ProjectID,
|
||||
&i.LabelColorID,
|
||||
&i.CreatedDate,
|
||||
&i.Name,
|
||||
)
|
||||
return i, err
|
||||
}
|
@ -4,185 +4,19 @@ package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Querier interface {
|
||||
CreateAuthToken(ctx context.Context, arg CreateAuthTokenParams) (AuthToken, error)
|
||||
CreateConfirmToken(ctx context.Context, email string) (UserAccountConfirmToken, error)
|
||||
CreateDueDateReminder(ctx context.Context, arg CreateDueDateReminderParams) (TaskDueDateReminder, error)
|
||||
CreateInvitedProjectMember(ctx context.Context, arg CreateInvitedProjectMemberParams) (ProjectMemberInvited, error)
|
||||
CreateInvitedUser(ctx context.Context, email string) (UserAccountInvited, error)
|
||||
CreateLabelColor(ctx context.Context, arg CreateLabelColorParams) (LabelColor, error)
|
||||
CreateNotification(ctx context.Context, arg CreateNotificationParams) (Notification, error)
|
||||
CreateNotificationNotifed(ctx context.Context, arg CreateNotificationNotifedParams) (NotificationNotified, error)
|
||||
CreateOrganization(ctx context.Context, arg CreateOrganizationParams) (Organization, error)
|
||||
CreatePersonalProject(ctx context.Context, arg CreatePersonalProjectParams) (Project, error)
|
||||
CreatePersonalProjectLink(ctx context.Context, arg CreatePersonalProjectLinkParams) (PersonalProject, error)
|
||||
CreateProjectLabel(ctx context.Context, arg CreateProjectLabelParams) (ProjectLabel, error)
|
||||
CreateProjectMember(ctx context.Context, arg CreateProjectMemberParams) (ProjectMember, error)
|
||||
CreateSystemOption(ctx context.Context, arg CreateSystemOptionParams) (SystemOption, error)
|
||||
CreateTask(ctx context.Context, arg CreateTaskParams) (Task, error)
|
||||
CreateTaskActivity(ctx context.Context, arg CreateTaskActivityParams) (TaskActivity, error)
|
||||
CreateTaskAll(ctx context.Context, arg CreateTaskAllParams) (Task, error)
|
||||
CreateTaskAssigned(ctx context.Context, arg CreateTaskAssignedParams) (TaskAssigned, error)
|
||||
CreateTaskChecklist(ctx context.Context, arg CreateTaskChecklistParams) (TaskChecklist, error)
|
||||
CreateTaskChecklistItem(ctx context.Context, arg CreateTaskChecklistItemParams) (TaskChecklistItem, error)
|
||||
CreateTaskComment(ctx context.Context, arg CreateTaskCommentParams) (TaskComment, error)
|
||||
CreateTaskGroup(ctx context.Context, arg CreateTaskGroupParams) (TaskGroup, error)
|
||||
CreateTaskLabelForTask(ctx context.Context, arg CreateTaskLabelForTaskParams) (TaskLabel, error)
|
||||
CreateTaskWatcher(ctx context.Context, arg CreateTaskWatcherParams) (TaskWatcher, error)
|
||||
CreateTeam(ctx context.Context, arg CreateTeamParams) (Team, error)
|
||||
CreateTeamMember(ctx context.Context, arg CreateTeamMemberParams) (TeamMember, error)
|
||||
CreateTeamProject(ctx context.Context, arg CreateTeamProjectParams) (Project, error)
|
||||
CreateAccessToken(ctx context.Context, arg CreateAccessTokenParams) (AccessToken, error)
|
||||
CreateUserAccount(ctx context.Context, arg CreateUserAccountParams) (UserAccount, error)
|
||||
DeleteAuthTokenByID(ctx context.Context, tokenID uuid.UUID) error
|
||||
DeleteAuthTokenByUserID(ctx context.Context, userID uuid.UUID) error
|
||||
DeleteConfirmTokenForEmail(ctx context.Context, email string) error
|
||||
DeleteDueDateReminder(ctx context.Context, dueDateReminderID uuid.UUID) error
|
||||
DeleteExpiredTokens(ctx context.Context) error
|
||||
DeleteInvitedProjectMemberByID(ctx context.Context, projectMemberInvitedID uuid.UUID) error
|
||||
DeleteInvitedUserAccount(ctx context.Context, userAccountInvitedID uuid.UUID) (UserAccountInvited, error)
|
||||
DeleteProjectByID(ctx context.Context, projectID uuid.UUID) error
|
||||
DeleteProjectLabelByID(ctx context.Context, projectLabelID uuid.UUID) error
|
||||
DeleteProjectMember(ctx context.Context, arg DeleteProjectMemberParams) error
|
||||
DeleteProjectMemberInvitedForEmail(ctx context.Context, email string) error
|
||||
DeleteTaskAssignedByID(ctx context.Context, arg DeleteTaskAssignedByIDParams) (TaskAssigned, error)
|
||||
DeleteTaskByID(ctx context.Context, taskID uuid.UUID) error
|
||||
DeleteTaskChecklistByID(ctx context.Context, taskChecklistID uuid.UUID) error
|
||||
DeleteTaskChecklistItem(ctx context.Context, taskChecklistItemID uuid.UUID) error
|
||||
DeleteTaskCommentByID(ctx context.Context, taskCommentID uuid.UUID) (TaskComment, error)
|
||||
DeleteTaskGroupByID(ctx context.Context, taskGroupID uuid.UUID) (int64, error)
|
||||
DeleteTaskLabelByID(ctx context.Context, taskLabelID uuid.UUID) error
|
||||
DeleteTaskLabelForTaskByProjectLabelID(ctx context.Context, arg DeleteTaskLabelForTaskByProjectLabelIDParams) error
|
||||
DeleteTaskWatcher(ctx context.Context, arg DeleteTaskWatcherParams) error
|
||||
DeleteTasksByTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) (int64, error)
|
||||
DeleteTeamByID(ctx context.Context, teamID uuid.UUID) error
|
||||
DeleteTeamMember(ctx context.Context, arg DeleteTeamMemberParams) error
|
||||
DeleteUserAccountByID(ctx context.Context, userID uuid.UUID) error
|
||||
DeleteUserAccountInvitedForEmail(ctx context.Context, email string) error
|
||||
DoesUserExist(ctx context.Context, arg DoesUserExistParams) (bool, error)
|
||||
GetActivityForTaskID(ctx context.Context, taskID uuid.UUID) ([]TaskActivity, error)
|
||||
GetAllNotificationsForUserID(ctx context.Context, userID uuid.UUID) ([]GetAllNotificationsForUserIDRow, error)
|
||||
GetAllOrganizations(ctx context.Context) ([]Organization, error)
|
||||
GetAllProjectsForTeam(ctx context.Context, teamID uuid.UUID) ([]Project, error)
|
||||
GetAllTaskGroups(ctx context.Context) ([]TaskGroup, error)
|
||||
GetAllTasks(ctx context.Context) ([]Task, error)
|
||||
GetAllTeamProjects(ctx context.Context) ([]Project, error)
|
||||
GetAllTeams(ctx context.Context) ([]Team, error)
|
||||
GetAllUserAccounts(ctx context.Context) ([]UserAccount, error)
|
||||
GetAllVisibleProjectsForUserID(ctx context.Context, userID uuid.UUID) ([]Project, error)
|
||||
GetAssignedMembersForTask(ctx context.Context, taskID uuid.UUID) ([]TaskAssigned, error)
|
||||
GetAssignedTasksDueDateForUserID(ctx context.Context, arg GetAssignedTasksDueDateForUserIDParams) ([]Task, error)
|
||||
GetAssignedTasksProjectForUserID(ctx context.Context, arg GetAssignedTasksProjectForUserIDParams) ([]Task, error)
|
||||
GetAuthTokenByID(ctx context.Context, tokenID uuid.UUID) (AuthToken, error)
|
||||
GetCommentCountForTask(ctx context.Context, taskID uuid.UUID) (int64, error)
|
||||
GetCommentsForTaskID(ctx context.Context, taskID uuid.UUID) ([]TaskComment, error)
|
||||
GetConfirmTokenByEmail(ctx context.Context, email string) (UserAccountConfirmToken, error)
|
||||
GetConfirmTokenByID(ctx context.Context, confirmTokenID uuid.UUID) (UserAccountConfirmToken, error)
|
||||
GetDueDateReminderByID(ctx context.Context, dueDateReminderID uuid.UUID) (TaskDueDateReminder, error)
|
||||
GetDueDateRemindersForDuration(ctx context.Context, startAt time.Time) ([]TaskDueDateReminder, error)
|
||||
GetDueDateRemindersForTaskID(ctx context.Context, taskID uuid.UUID) ([]TaskDueDateReminder, error)
|
||||
GetInvitedMembersForProjectID(ctx context.Context, projectID uuid.UUID) ([]GetInvitedMembersForProjectIDRow, error)
|
||||
GetInvitedUserAccounts(ctx context.Context) ([]UserAccountInvited, error)
|
||||
GetInvitedUserByEmail(ctx context.Context, email string) (UserAccountInvited, error)
|
||||
GetLabelColorByID(ctx context.Context, labelColorID uuid.UUID) (LabelColor, error)
|
||||
GetLabelColors(ctx context.Context) ([]LabelColor, error)
|
||||
GetLastMoveForTaskID(ctx context.Context, taskID uuid.UUID) (GetLastMoveForTaskIDRow, error)
|
||||
GetMemberData(ctx context.Context, projectID uuid.UUID) ([]UserAccount, error)
|
||||
GetMemberProjectIDsForUserID(ctx context.Context, userID uuid.UUID) ([]uuid.UUID, error)
|
||||
GetMemberTeamIDsForUserID(ctx context.Context, userID uuid.UUID) ([]uuid.UUID, error)
|
||||
GetNotificationByID(ctx context.Context, notificationID uuid.UUID) (Notification, error)
|
||||
GetNotificationsForUserIDCursor(ctx context.Context, arg GetNotificationsForUserIDCursorParams) ([]GetNotificationsForUserIDCursorRow, error)
|
||||
GetNotificationsForUserIDPaged(ctx context.Context, arg GetNotificationsForUserIDPagedParams) ([]GetNotificationsForUserIDPagedRow, error)
|
||||
GetNotifiedByID(ctx context.Context, notifiedID uuid.UUID) (GetNotifiedByIDRow, error)
|
||||
GetNotifiedByIDNoExtra(ctx context.Context, notifiedID uuid.UUID) (NotificationNotified, error)
|
||||
GetPersonalProjectsForUserID(ctx context.Context, userID uuid.UUID) ([]Project, error)
|
||||
GetProjectByID(ctx context.Context, projectID uuid.UUID) (Project, error)
|
||||
GetProjectIDByShortID(ctx context.Context, shortID string) (uuid.UUID, error)
|
||||
GetProjectIDForTask(ctx context.Context, taskID uuid.UUID) (uuid.UUID, error)
|
||||
GetProjectIDForTaskChecklist(ctx context.Context, taskChecklistID uuid.UUID) (uuid.UUID, error)
|
||||
GetProjectIDForTaskChecklistItem(ctx context.Context, taskChecklistItemID uuid.UUID) (uuid.UUID, error)
|
||||
GetProjectIDForTaskGroup(ctx context.Context, taskGroupID uuid.UUID) (uuid.UUID, error)
|
||||
GetProjectIdMappings(ctx context.Context, dollar_1 []uuid.UUID) ([]GetProjectIdMappingsRow, error)
|
||||
GetProjectInfoForTask(ctx context.Context, taskID uuid.UUID) (GetProjectInfoForTaskRow, error)
|
||||
GetProjectLabelByID(ctx context.Context, projectLabelID uuid.UUID) (ProjectLabel, error)
|
||||
GetProjectLabelsForProject(ctx context.Context, projectID uuid.UUID) ([]ProjectLabel, error)
|
||||
GetProjectMemberInvitedIDByEmail(ctx context.Context, email string) (GetProjectMemberInvitedIDByEmailRow, error)
|
||||
GetProjectMembersForProjectID(ctx context.Context, projectID uuid.UUID) ([]ProjectMember, error)
|
||||
GetProjectRolesForUserID(ctx context.Context, userID uuid.UUID) ([]GetProjectRolesForUserIDRow, error)
|
||||
GetProjectsForInvitedMember(ctx context.Context, email string) ([]uuid.UUID, error)
|
||||
GetPublicOn(ctx context.Context, projectID uuid.UUID) (sql.NullTime, error)
|
||||
GetRecentlyAssignedTaskForUserID(ctx context.Context, arg GetRecentlyAssignedTaskForUserIDParams) ([]Task, error)
|
||||
GetRoleForProjectMemberByUserID(ctx context.Context, arg GetRoleForProjectMemberByUserIDParams) (Role, error)
|
||||
GetRoleForTeamMember(ctx context.Context, arg GetRoleForTeamMemberParams) (Role, error)
|
||||
GetRoleForUserID(ctx context.Context, userID uuid.UUID) (GetRoleForUserIDRow, error)
|
||||
GetSystemOptionByKey(ctx context.Context, key string) (GetSystemOptionByKeyRow, error)
|
||||
GetTaskByID(ctx context.Context, taskID uuid.UUID) (Task, error)
|
||||
GetTaskChecklistByID(ctx context.Context, taskChecklistID uuid.UUID) (TaskChecklist, error)
|
||||
GetTaskChecklistItemByID(ctx context.Context, taskChecklistItemID uuid.UUID) (TaskChecklistItem, error)
|
||||
GetTaskChecklistItemsForTaskChecklist(ctx context.Context, taskChecklistID uuid.UUID) ([]TaskChecklistItem, error)
|
||||
GetTaskChecklistsForTask(ctx context.Context, taskID uuid.UUID) ([]TaskChecklist, error)
|
||||
GetTaskForDueDateReminder(ctx context.Context, dueDateReminderID uuid.UUID) (Task, error)
|
||||
GetTaskGroupByID(ctx context.Context, taskGroupID uuid.UUID) (TaskGroup, error)
|
||||
GetTaskGroupsForProject(ctx context.Context, projectID uuid.UUID) ([]TaskGroup, error)
|
||||
GetTaskIDByShortID(ctx context.Context, shortID string) (uuid.UUID, error)
|
||||
GetTaskLabelByID(ctx context.Context, taskLabelID uuid.UUID) (TaskLabel, error)
|
||||
GetTaskLabelForTaskByProjectLabelID(ctx context.Context, arg GetTaskLabelForTaskByProjectLabelIDParams) (TaskLabel, error)
|
||||
GetTaskLabelsForTaskID(ctx context.Context, taskID uuid.UUID) ([]TaskLabel, error)
|
||||
GetTaskWatcher(ctx context.Context, arg GetTaskWatcherParams) (TaskWatcher, error)
|
||||
GetTaskWatchersForTask(ctx context.Context, taskID uuid.UUID) ([]TaskWatcher, error)
|
||||
GetTasksForTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) ([]Task, error)
|
||||
GetTeamByID(ctx context.Context, teamID uuid.UUID) (Team, error)
|
||||
GetTeamMemberByID(ctx context.Context, arg GetTeamMemberByIDParams) (TeamMember, error)
|
||||
GetTeamMembersForTeamID(ctx context.Context, teamID uuid.UUID) ([]TeamMember, error)
|
||||
GetTeamRoleForUserID(ctx context.Context, arg GetTeamRoleForUserIDParams) (GetTeamRoleForUserIDRow, error)
|
||||
GetTeamRolesForUserID(ctx context.Context, userID uuid.UUID) ([]GetTeamRolesForUserIDRow, error)
|
||||
GetTeamsForOrganization(ctx context.Context, organizationID uuid.UUID) ([]Team, error)
|
||||
GetTeamsForUserIDWhereAdmin(ctx context.Context, userID uuid.UUID) ([]Team, error)
|
||||
GetTemplateForActivityID(ctx context.Context, taskActivityTypeID int32) (string, error)
|
||||
GetUserAccountByEmail(ctx context.Context, email string) (UserAccount, error)
|
||||
DeleteAccessToken(ctx context.Context, token string) error
|
||||
GetAccessToken(ctx context.Context, token string) (AccessToken, error)
|
||||
GetUserAccountByID(ctx context.Context, userID uuid.UUID) (UserAccount, error)
|
||||
GetUserAccountByUsername(ctx context.Context, username string) (UserAccount, error)
|
||||
GetUserRolesForProject(ctx context.Context, arg GetUserRolesForProjectParams) (GetUserRolesForProjectRow, error)
|
||||
HasActiveUser(ctx context.Context) (bool, error)
|
||||
HasAnyUser(ctx context.Context) (bool, error)
|
||||
HasUnreadNotification(ctx context.Context, userID uuid.UUID) (bool, error)
|
||||
MarkAllNotificationsRead(ctx context.Context, arg MarkAllNotificationsReadParams) error
|
||||
MarkNotificationAsRead(ctx context.Context, arg MarkNotificationAsReadParams) error
|
||||
SetFirstUserActive(ctx context.Context) (UserAccount, error)
|
||||
SetInactiveLastMoveForTaskID(ctx context.Context, taskID uuid.UUID) error
|
||||
SetPublicOn(ctx context.Context, arg SetPublicOnParams) (Project, error)
|
||||
SetTaskChecklistItemComplete(ctx context.Context, arg SetTaskChecklistItemCompleteParams) (TaskChecklistItem, error)
|
||||
SetTaskComplete(ctx context.Context, arg SetTaskCompleteParams) (Task, error)
|
||||
SetTaskGroupName(ctx context.Context, arg SetTaskGroupNameParams) (TaskGroup, error)
|
||||
SetUserActiveByEmail(ctx context.Context, email string) (UserAccount, error)
|
||||
SetUserPassword(ctx context.Context, arg SetUserPasswordParams) (UserAccount, error)
|
||||
UpdateDueDateReminder(ctx context.Context, arg UpdateDueDateReminderParams) (TaskDueDateReminder, error)
|
||||
UpdateDueDateReminderRemindAt(ctx context.Context, arg UpdateDueDateReminderRemindAtParams) (TaskDueDateReminder, error)
|
||||
UpdateProjectLabel(ctx context.Context, arg UpdateProjectLabelParams) (ProjectLabel, error)
|
||||
UpdateProjectLabelColor(ctx context.Context, arg UpdateProjectLabelColorParams) (ProjectLabel, error)
|
||||
UpdateProjectLabelName(ctx context.Context, arg UpdateProjectLabelNameParams) (ProjectLabel, error)
|
||||
UpdateProjectMemberRole(ctx context.Context, arg UpdateProjectMemberRoleParams) (ProjectMember, error)
|
||||
UpdateProjectNameByID(ctx context.Context, arg UpdateProjectNameByIDParams) (Project, error)
|
||||
UpdateTaskChecklistItemLocation(ctx context.Context, arg UpdateTaskChecklistItemLocationParams) (TaskChecklistItem, error)
|
||||
UpdateTaskChecklistItemName(ctx context.Context, arg UpdateTaskChecklistItemNameParams) (TaskChecklistItem, error)
|
||||
UpdateTaskChecklistName(ctx context.Context, arg UpdateTaskChecklistNameParams) (TaskChecklist, error)
|
||||
UpdateTaskChecklistPosition(ctx context.Context, arg UpdateTaskChecklistPositionParams) (TaskChecklist, error)
|
||||
UpdateTaskComment(ctx context.Context, arg UpdateTaskCommentParams) (TaskComment, error)
|
||||
UpdateTaskDescription(ctx context.Context, arg UpdateTaskDescriptionParams) (Task, error)
|
||||
UpdateTaskDueDate(ctx context.Context, arg UpdateTaskDueDateParams) (Task, error)
|
||||
UpdateTaskGroupLocation(ctx context.Context, arg UpdateTaskGroupLocationParams) (TaskGroup, error)
|
||||
UpdateTaskLocation(ctx context.Context, arg UpdateTaskLocationParams) (Task, error)
|
||||
UpdateTaskName(ctx context.Context, arg UpdateTaskNameParams) (Task, error)
|
||||
UpdateTaskPosition(ctx context.Context, arg UpdateTaskPositionParams) (Task, error)
|
||||
UpdateTeamMemberRole(ctx context.Context, arg UpdateTeamMemberRoleParams) (TeamMember, error)
|
||||
UpdateUserAccountInfo(ctx context.Context, arg UpdateUserAccountInfoParams) (UserAccount, error)
|
||||
UpdateUserAccountProfileAvatarURL(ctx context.Context, arg UpdateUserAccountProfileAvatarURLParams) (UserAccount, error)
|
||||
UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) (UserAccount, error)
|
||||
GetUserAccounts(ctx context.Context) ([]UserAccount, error)
|
||||
HasAnyUserAccount(ctx context.Context) (bool, error)
|
||||
}
|
||||
|
||||
var _ Querier = (*Queries)(nil)
|
||||
|
@ -1,9 +0,0 @@
|
||||
-- name: GetLabelColorByID :one
|
||||
SELECT * FROM label_color WHERE label_color_id = $1;
|
||||
|
||||
-- name: GetLabelColors :many
|
||||
SELECT * FROM label_color;
|
||||
|
||||
-- name: CreateLabelColor :one
|
||||
INSERT INTO label_color (name, color_hex, position) VALUES ($1, $2, $3)
|
||||
RETURNING *;
|
@ -1,50 +0,0 @@
|
||||
-- name: GetAllNotificationsForUserID :many
|
||||
SELECT * FROM notification_notified AS nn
|
||||
INNER JOIN notification AS n ON n.notification_id = nn.notification_id
|
||||
WHERE nn.user_id = $1;
|
||||
|
||||
-- name: GetNotifiedByID :one
|
||||
SELECT * FROM notification_notified as nn
|
||||
INNER JOIN notification AS n ON n.notification_id = nn.notification_id
|
||||
WHERE notified_id = $1;
|
||||
|
||||
-- name: GetNotifiedByIDNoExtra :one
|
||||
SELECT * FROM notification_notified as nn WHERE nn.notified_id = $1;
|
||||
|
||||
-- name: HasUnreadNotification :one
|
||||
SELECT EXISTS (SELECT 1 FROM notification_notified WHERE read = false AND user_id = $1);
|
||||
|
||||
-- name: MarkNotificationAsRead :exec
|
||||
UPDATE notification_notified SET read = $3, read_at = $2 WHERE user_id = $1 AND notified_id = $4;
|
||||
|
||||
-- name: MarkAllNotificationsRead :exec
|
||||
UPDATE notification_notified SET read = true, read_at = $2 WHERE user_id = $1;
|
||||
|
||||
-- name: CreateNotification :one
|
||||
INSERT INTO notification (caused_by, data, action_type, created_on)
|
||||
VALUES ($1, $2, $3, $4) RETURNING *;
|
||||
|
||||
-- name: CreateNotificationNotifed :one
|
||||
INSERT INTO notification_notified (notification_id, user_id) VALUES ($1, $2) RETURNING *;
|
||||
|
||||
-- name: GetNotificationByID :one
|
||||
SELECT * FROM notification WHERE notification_id = $1;
|
||||
|
||||
-- name: GetNotificationsForUserIDPaged :many
|
||||
SELECT n.*, nn.* FROM notification_notified AS nn
|
||||
INNER JOIN notification AS n ON n.notification_id = nn.notification_id
|
||||
WHERE nn.user_id = @user_id::uuid
|
||||
AND (@enable_unread::boolean = false OR nn.read = false)
|
||||
AND (@enable_action_type::boolean = false OR n.action_type = ANY(@action_type::text[]))
|
||||
ORDER BY n.created_on DESC
|
||||
LIMIT @limit_rows::int;
|
||||
|
||||
-- name: GetNotificationsForUserIDCursor :many
|
||||
SELECT n.*, nn.* FROM notification_notified AS nn
|
||||
INNER JOIN notification AS n ON n.notification_id = nn.notification_id
|
||||
WHERE (n.created_on, n.notification_id) < (@created_on::timestamptz, @notification_id::uuid)
|
||||
AND nn.user_id = @user_id::uuid
|
||||
AND (@enable_unread::boolean = false OR nn.read = false)
|
||||
AND (@enable_action_type::boolean = false OR n.action_type = ANY(@action_type::text[]))
|
||||
ORDER BY n.created_on DESC
|
||||
LIMIT @limit_rows::int;
|
@ -1,5 +0,0 @@
|
||||
-- name: GetAllOrganizations :many
|
||||
SELECT * FROM organization;
|
||||
|
||||
-- name: CreateOrganization :one
|
||||
INSERT INTO organization (created_at, name) VALUES ($1, $2) RETURNING *;
|
@ -1,88 +0,0 @@
|
||||
-- name: GetAllTeamProjects :many
|
||||
SELECT * FROM project WHERE team_id IS NOT null;
|
||||
|
||||
-- name: GetProjectIDByShortID :one
|
||||
SELECT project_id FROM project WHERE short_id = $1;
|
||||
|
||||
-- name: GetAllProjectsForTeam :many
|
||||
SELECT * FROM project WHERE team_id = $1;
|
||||
|
||||
-- name: GetProjectByID :one
|
||||
SELECT * FROM project WHERE project_id = $1;
|
||||
|
||||
-- name: CreateTeamProject :one
|
||||
INSERT INTO project(team_id, created_at, name) VALUES ($1, $2, $3) RETURNING *;
|
||||
|
||||
-- name: CreatePersonalProject :one
|
||||
INSERT INTO project(team_id, created_at, name) VALUES (null, $1, $2) RETURNING *;
|
||||
|
||||
-- name: UpdateProjectNameByID :one
|
||||
UPDATE project SET name = $2 WHERE project_id = $1 RETURNING *;
|
||||
|
||||
-- name: DeleteProjectByID :exec
|
||||
DELETE FROM project WHERE project_id = $1;
|
||||
|
||||
-- name: GetProjectMembersForProjectID :many
|
||||
SELECT * FROM project_member WHERE project_id = $1;
|
||||
|
||||
-- name: GetRoleForProjectMemberByUserID :one
|
||||
SELECT code, role.name FROM project_member INNER JOIN role ON role.code = project_member.role_code
|
||||
WHERE user_id = $1 AND project_id = $2;
|
||||
|
||||
-- name: CreateProjectMember :one
|
||||
INSERT INTO project_member (project_id, user_id, role_code, added_at) VALUES ($1, $2, $3, $4)
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteProjectMember :exec
|
||||
DELETE FROM project_member WHERE user_id = $1 AND project_id = $2;
|
||||
|
||||
-- name: UpdateProjectMemberRole :one
|
||||
UPDATE project_member SET role_code = $3 WHERE project_id = $1 AND user_id = $2
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetProjectRolesForUserID :many
|
||||
SELECT project_id, role_code FROM project_member WHERE user_id = $1;
|
||||
|
||||
-- name: GetMemberProjectIDsForUserID :many
|
||||
SELECT project_id FROM project_member WHERE user_id = $1;
|
||||
|
||||
-- name: GetInvitedMembersForProjectID :many
|
||||
SELECT uai.user_account_invited_id, email, invited_on FROM project_member_invited AS pmi
|
||||
INNER JOIN user_account_invited AS uai
|
||||
ON uai.user_account_invited_id = pmi.user_account_invited_id
|
||||
WHERE project_id = $1;
|
||||
|
||||
-- name: GetProjectMemberInvitedIDByEmail :one
|
||||
SELECT email, invited_on, project_member_invited_id FROM user_account_invited AS uai
|
||||
inner join project_member_invited AS pmi
|
||||
ON pmi.user_account_invited_id = uai.user_account_invited_id
|
||||
WHERE email = $1;
|
||||
|
||||
-- name: DeleteInvitedProjectMemberByID :exec
|
||||
DELETE FROM project_member_invited WHERE project_member_invited_id = $1;
|
||||
|
||||
-- name: GetAllVisibleProjectsForUserID :many
|
||||
SELECT project.* FROM project LEFT JOIN
|
||||
project_member ON project_member.project_id = project.project_id WHERE project_member.user_id = $1;
|
||||
|
||||
-- name: GetPersonalProjectsForUserID :many
|
||||
SELECT project.* FROM project
|
||||
LEFT JOIN personal_project ON personal_project.project_id = project.project_id
|
||||
WHERE personal_project.user_id = $1;
|
||||
|
||||
|
||||
-- name: GetUserRolesForProject :one
|
||||
SELECT p.team_id, COALESCE(tm.role_code, '') AS team_role, COALESCE(pm.role_code, '') AS project_role
|
||||
FROM project AS p
|
||||
LEFT JOIN project_member AS pm ON pm.project_id = p.project_id AND pm.user_id = $1
|
||||
LEFT JOIN team_member AS tm ON tm.team_id = p.team_id AND tm.user_id = $1
|
||||
WHERE p.project_id = $2;
|
||||
|
||||
-- name: CreatePersonalProjectLink :one
|
||||
INSERT INTO personal_project (project_id, user_id) VALUES ($1, $2) RETURNING *;
|
||||
|
||||
-- name: SetPublicOn :one
|
||||
UPDATE project SET public_on = $2 WHERE project_id = $1 RETURNING *;
|
||||
|
||||
-- name: GetPublicOn :one
|
||||
SELECT public_on FROM project WHERE project_id = $1;
|
@ -1,21 +0,0 @@
|
||||
-- name: CreateProjectLabel :one
|
||||
INSERT INTO project_label (project_id, label_color_id, created_date, name)
|
||||
VALUES ($1, $2, $3, $4) RETURNING *;
|
||||
|
||||
-- name: GetProjectLabelsForProject :many
|
||||
SELECT * FROM project_label WHERE project_id = $1;
|
||||
|
||||
-- name: GetProjectLabelByID :one
|
||||
SELECT * FROM project_label WHERE project_label_id = $1;
|
||||
|
||||
-- name: DeleteProjectLabelByID :exec
|
||||
DELETE FROM project_label WHERE project_label_id = $1;
|
||||
|
||||
-- name: UpdateProjectLabelName :one
|
||||
UPDATE project_label SET name = $2 WHERE project_label_id = $1 RETURNING *;
|
||||
|
||||
-- name: UpdateProjectLabelColor :one
|
||||
UPDATE project_label SET label_color_id = $2 WHERE project_label_id = $1 RETURNING *;
|
||||
|
||||
-- name: UpdateProjectLabel :one
|
||||
UPDATE project_label SET name = $2, label_color_id = $3 WHERE project_label_id = $1 RETURNING *;
|
@ -1,5 +0,0 @@
|
||||
-- name: GetSystemOptionByKey :one
|
||||
SELECT key, value FROM system_options WHERE key = $1;
|
||||
|
||||
-- name: CreateSystemOption :one
|
||||
INSERT INTO system_options (key, value) VALUES ($1, $2) RETURNING *;
|
@ -1,149 +0,0 @@
|
||||
-- name: GetTaskWatcher :one
|
||||
SELECT * FROM task_watcher WHERE user_id = $1 AND task_id = $2;
|
||||
|
||||
-- name: GetTaskWatchersForTask :many
|
||||
SELECT * FROM task_watcher WHERE task_id = $1;
|
||||
|
||||
-- name: CreateTaskWatcher :one
|
||||
INSERT INTO task_watcher (user_id, task_id, watched_at) VALUES ($1, $2, $3) RETURNING *;
|
||||
|
||||
-- name: GetTaskIDByShortID :one
|
||||
SELECT task_id FROM task WHERE short_id = $1;
|
||||
|
||||
-- name: DeleteTaskWatcher :exec
|
||||
DELETE FROM task_watcher WHERE user_id = $1 AND task_id = $2;
|
||||
|
||||
-- name: CreateTask :one
|
||||
INSERT INTO task (task_group_id, created_at, name, position)
|
||||
VALUES($1, $2, $3, $4) RETURNING *;
|
||||
|
||||
-- name: CreateTaskAll :one
|
||||
INSERT INTO task (task_group_id, created_at, name, position, description, complete, due_date)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *;
|
||||
|
||||
-- name: UpdateTaskDescription :one
|
||||
UPDATE task SET description = $2 WHERE task_id = $1 RETURNING *;
|
||||
|
||||
-- name: GetTaskByID :one
|
||||
SELECT * FROM task WHERE task_id = $1;
|
||||
|
||||
-- name: GetTasksForTaskGroupID :many
|
||||
SELECT * FROM task WHERE task_group_id = $1;
|
||||
|
||||
-- name: GetAllTasks :many
|
||||
SELECT * FROM task;
|
||||
|
||||
-- name: UpdateTaskLocation :one
|
||||
UPDATE task SET task_group_id = $2, position = $3 WHERE task_id = $1 RETURNING *;
|
||||
|
||||
-- name: UpdateTaskPosition :one
|
||||
UPDATE task SET position = $2 WHERE task_id = $1 RETURNING *;
|
||||
|
||||
-- name: DeleteTaskByID :exec
|
||||
DELETE FROM task WHERE task_id = $1;
|
||||
|
||||
-- name: UpdateTaskName :one
|
||||
UPDATE task SET name = $2 WHERE task_id = $1 RETURNING *;
|
||||
|
||||
-- name: DeleteTasksByTaskGroupID :execrows
|
||||
DELETE FROM task where task_group_id = $1;
|
||||
|
||||
-- name: UpdateTaskDueDate :one
|
||||
UPDATE task SET due_date = $2, has_time = $3 WHERE task_id = $1 RETURNING *;
|
||||
|
||||
-- name: SetTaskComplete :one
|
||||
UPDATE task SET complete = $2, completed_at = $3 WHERE task_id = $1 RETURNING *;
|
||||
|
||||
-- name: GetProjectIDForTask :one
|
||||
SELECT project_id FROM task
|
||||
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
||||
WHERE task_id = $1;
|
||||
|
||||
-- name: GetProjectInfoForTask :one
|
||||
SELECT project.short_id AS project_short_id, project.name, task.short_id AS task_short_id FROM task
|
||||
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
||||
INNER JOIN project ON task_group.project_id = project.project_id
|
||||
WHERE task_id = $1;
|
||||
|
||||
-- name: CreateTaskComment :one
|
||||
INSERT INTO task_comment (task_id, message, created_at, created_by)
|
||||
VALUES ($1, $2, $3, $4) RETURNING *;
|
||||
|
||||
-- name: GetCommentsForTaskID :many
|
||||
SELECT * FROM task_comment WHERE task_id = $1 ORDER BY created_at;
|
||||
|
||||
-- name: DeleteTaskCommentByID :one
|
||||
DELETE FROM task_comment WHERE task_comment_id = $1 RETURNING *;
|
||||
|
||||
-- name: UpdateTaskComment :one
|
||||
UPDATE task_comment SET message = $2, updated_at = $3 WHERE task_comment_id = $1 RETURNING *;
|
||||
|
||||
-- name: GetRecentlyAssignedTaskForUserID :many
|
||||
SELECT task.* FROM task_assigned INNER JOIN
|
||||
task ON task.task_id = task_assigned.task_id WHERE user_id = $1
|
||||
AND $4::boolean = true OR (
|
||||
$4::boolean = false AND complete = $2 AND (
|
||||
$2 = false OR ($2 = true AND completed_at > $3)
|
||||
)
|
||||
)
|
||||
ORDER BY task_assigned.assigned_date DESC;
|
||||
|
||||
-- name: GetAssignedTasksProjectForUserID :many
|
||||
SELECT task.* FROM task_assigned
|
||||
INNER JOIN task ON task.task_id = task_assigned.task_id
|
||||
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
||||
WHERE user_id = $1
|
||||
AND $4::boolean = true OR (
|
||||
$4::boolean = false AND complete = $2 AND (
|
||||
$2 = false OR ($2 = true AND completed_at > $3)
|
||||
)
|
||||
)
|
||||
ORDER BY task_group.project_id DESC, task_assigned.assigned_date DESC;
|
||||
|
||||
-- name: GetProjectIdMappings :many
|
||||
SELECT project_id, task_id FROM task
|
||||
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
||||
WHERE task_id = ANY($1::uuid[]);
|
||||
|
||||
-- name: GetAssignedTasksDueDateForUserID :many
|
||||
SELECT task.* FROM task_assigned
|
||||
INNER JOIN task ON task.task_id = task_assigned.task_id
|
||||
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
||||
WHERE user_id = $1
|
||||
AND $4::boolean = true OR (
|
||||
$4::boolean = false AND complete = $2 AND (
|
||||
$2 = false OR ($2 = true AND completed_at > $3)
|
||||
)
|
||||
)
|
||||
ORDER BY task.due_date DESC, task_group.project_id DESC;
|
||||
|
||||
-- name: GetCommentCountForTask :one
|
||||
SELECT COUNT(*) FROM task_comment WHERE task_id = $1;
|
||||
|
||||
|
||||
-- name: CreateDueDateReminder :one
|
||||
INSERT INTO task_due_date_reminder (task_id, period, duration, remind_at) VALUES ($1, $2, $3, $4) RETURNING *;
|
||||
|
||||
-- name: UpdateDueDateReminder :one
|
||||
UPDATE task_due_date_reminder SET remind_at = $4, period = $2, duration = $3 WHERE due_date_reminder_id = $1 RETURNING *;
|
||||
|
||||
-- name: GetTaskForDueDateReminder :one
|
||||
SELECT task.* FROM task_due_date_reminder
|
||||
INNER JOIN task ON task.task_id = task_due_date_reminder.task_id
|
||||
WHERE task_due_date_reminder.due_date_reminder_id = $1;
|
||||
|
||||
-- name: UpdateDueDateReminderRemindAt :one
|
||||
UPDATE task_due_date_reminder SET remind_at = $2 WHERE due_date_reminder_id = $1 RETURNING *;
|
||||
|
||||
-- name: GetDueDateRemindersForTaskID :many
|
||||
SELECT * FROM task_due_date_reminder WHERE task_id = $1;
|
||||
|
||||
-- name: GetDueDateReminderByID :one
|
||||
SELECT * FROM task_due_date_reminder WHERE due_date_reminder_id = $1;
|
||||
|
||||
-- name: DeleteDueDateReminder :exec
|
||||
DELETE FROM task_due_date_reminder WHERE due_date_reminder_id = $1;
|
||||
|
||||
-- name: GetDueDateRemindersForDuration :many
|
||||
SELECT * FROM task_due_date_reminder WHERE remind_at >= @start_at::timestamptz;
|
||||
|
@ -1,22 +0,0 @@
|
||||
-- name: CreateTaskActivity :one
|
||||
INSERT INTO task_activity (task_id, caused_by, created_at, activity_type_id, data)
|
||||
VALUES ($1, $2, $3, $4, $5) RETURNING *;
|
||||
|
||||
-- name: GetActivityForTaskID :many
|
||||
SELECT * FROM task_activity WHERE task_id = $1 AND active = true;
|
||||
|
||||
-- name: GetTemplateForActivityID :one
|
||||
SELECT template FROM task_activity_type WHERE task_activity_type_id = $1;
|
||||
|
||||
-- name: GetLastMoveForTaskID :one
|
||||
SELECT active, created_at, data->>'CurTaskGroupID' AS cur_task_group_id, data->>'PrevTaskGroupID' AS prev_task_group_id FROM task_activity
|
||||
WHERE task_id = $1 AND activity_type_id = 2 AND created_at >= NOW() - INTERVAL '5 minutes'
|
||||
ORDER BY created_at DESC LIMIT 1;
|
||||
|
||||
-- name: SetInactiveLastMoveForTaskID :exec
|
||||
UPDATE task_activity SET active = false WHERE task_activity_id = (
|
||||
SELECT task_activity_id FROM task_activity AS ta
|
||||
WHERE ta.activity_type_id = 2 AND ta.task_id = $1
|
||||
AND ta.created_at >= NOW() - INTERVAL '5 minutes'
|
||||
ORDER BY created_at DESC LIMIT 1
|
||||
);
|
@ -1,9 +0,0 @@
|
||||
-- name: CreateTaskAssigned :one
|
||||
INSERT INTO task_assigned (task_id, user_id, assigned_date)
|
||||
VALUES($1, $2, $3) RETURNING *;
|
||||
|
||||
-- name: GetAssignedMembersForTask :many
|
||||
SELECT * FROM task_assigned WHERE task_id = $1;
|
||||
|
||||
-- name: DeleteTaskAssignedByID :one
|
||||
DELETE FROM task_assigned WHERE task_id = $1 AND user_id = $2 RETURNING *;
|
@ -1,56 +0,0 @@
|
||||
-- name: CreateTaskChecklist :one
|
||||
INSERT INTO task_checklist (task_id, created_at, name, position) VALUES ($1, $2, $3, $4)
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetTaskChecklistsForTask :many
|
||||
SELECT * FROM task_checklist WHERE task_id = $1;
|
||||
|
||||
-- name: UpdateTaskChecklistName :one
|
||||
UPDATE task_checklist SET name = $2 WHERE task_checklist_id = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteTaskChecklistByID :exec
|
||||
DELETE FROM task_checklist WHERE task_checklist_id = $1;
|
||||
|
||||
-- name: GetTaskChecklistByID :one
|
||||
SELECT * FROM task_checklist WHERE task_checklist_id = $1;
|
||||
|
||||
-- name: CreateTaskChecklistItem :one
|
||||
INSERT INTO task_checklist_item (task_checklist_id, created_at, name, position, complete, due_date) VALUES ($1, $2, $3, $4, false, null)
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetTaskChecklistItemsForTaskChecklist :many
|
||||
SELECT * FROM task_checklist_item WHERE task_checklist_id = $1;
|
||||
|
||||
-- name: SetTaskChecklistItemComplete :one
|
||||
UPDATE task_checklist_item SET complete = $2 WHERE task_checklist_item_id = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteTaskChecklistItem :exec
|
||||
DELETE FROM task_checklist_item WHERE task_checklist_item_id = $1;
|
||||
|
||||
-- name: GetTaskChecklistItemByID :one
|
||||
SELECT * FROM task_checklist_item WHERE task_checklist_item_id = $1;
|
||||
|
||||
-- name: UpdateTaskChecklistItemName :one
|
||||
UPDATE task_checklist_item SET name = $2 WHERE task_checklist_item_id = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateTaskChecklistPosition :one
|
||||
UPDATE task_checklist SET position = $2 WHERE task_checklist_id = $1 RETURNING *;
|
||||
|
||||
-- name: UpdateTaskChecklistItemLocation :one
|
||||
UPDATE task_checklist_item SET position = $2, task_checklist_id = $3 WHERE task_checklist_item_id = $1 RETURNING *;
|
||||
|
||||
-- name: GetProjectIDForTaskChecklist :one
|
||||
SELECT project_id FROM task_checklist
|
||||
INNER JOIN task ON task.task_id = task_checklist.task_id
|
||||
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
||||
WHERE task_checklist.task_checklist_id = $1;
|
||||
|
||||
-- name: GetProjectIDForTaskChecklistItem :one
|
||||
SELECT project_id FROM task_checklist_item AS tci
|
||||
INNER JOIN task_checklist ON task_checklist.task_checklist_id = tci.task_checklist_id
|
||||
INNER JOIN task ON task.task_id = task_checklist.task_id
|
||||
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
||||
WHERE tci.task_checklist_item_id = $1;
|
@ -1,24 +0,0 @@
|
||||
-- name: CreateTaskGroup :one
|
||||
INSERT INTO task_group (project_id, created_at, name, position)
|
||||
VALUES($1, $2, $3, $4) RETURNING *;
|
||||
|
||||
-- name: GetTaskGroupsForProject :many
|
||||
SELECT * FROM task_group WHERE project_id = $1;
|
||||
|
||||
-- name: GetProjectIDForTaskGroup :one
|
||||
SELECT project_id from task_group WHERE task_group_id = $1;
|
||||
|
||||
-- name: GetAllTaskGroups :many
|
||||
SELECT * FROM task_group;
|
||||
|
||||
-- name: GetTaskGroupByID :one
|
||||
SELECT * FROM task_group WHERE task_group_id = $1;
|
||||
|
||||
-- name: SetTaskGroupName :one
|
||||
UPDATE task_group SET name = $2 WHERE task_group_id = $1 RETURNING *;
|
||||
|
||||
-- name: DeleteTaskGroupByID :execrows
|
||||
DELETE FROM task_group WHERE task_group_id = $1;
|
||||
|
||||
-- name: UpdateTaskGroupLocation :one
|
||||
UPDATE task_group SET position = $2 WHERE task_group_id = $1 RETURNING *;
|
@ -1,18 +0,0 @@
|
||||
-- name: CreateTaskLabelForTask :one
|
||||
INSERT INTO task_label (task_id, project_label_id, assigned_date)
|
||||
VALUES ($1, $2, $3) RETURNING *;
|
||||
|
||||
-- name: GetTaskLabelsForTaskID :many
|
||||
SELECT * FROM task_label WHERE task_id = $1;
|
||||
|
||||
-- name: GetTaskLabelByID :one
|
||||
SELECT * FROM task_label WHERE task_label_id = $1;
|
||||
|
||||
-- name: DeleteTaskLabelByID :exec
|
||||
DELETE FROM task_label WHERE task_label_id = $1;
|
||||
|
||||
-- name: GetTaskLabelForTaskByProjectLabelID :one
|
||||
SELECT * FROM task_label WHERE task_id = $1 AND project_label_id = $2;
|
||||
|
||||
-- name: DeleteTaskLabelForTaskByProjectLabelID :exec
|
||||
DELETE FROM task_label WHERE project_label_id = $2 AND task_id = $1;
|
@ -1,27 +0,0 @@
|
||||
-- name: GetAllTeams :many
|
||||
SELECT * FROM team;
|
||||
|
||||
-- name: GetTeamByID :one
|
||||
SELECT * FROM team WHERE team_id = $1;
|
||||
|
||||
-- name: CreateTeam :one
|
||||
INSERT INTO team (organization_id, created_at, name) VALUES ($1, $2, $3) RETURNING *;
|
||||
|
||||
-- name: DeleteTeamByID :exec
|
||||
DELETE FROM team WHERE team_id = $1;
|
||||
|
||||
-- name: GetTeamsForOrganization :many
|
||||
SELECT * FROM team WHERE organization_id = $1;
|
||||
|
||||
-- name: GetMemberTeamIDsForUserID :many
|
||||
SELECT team_id FROM team_member WHERE user_id = $1;
|
||||
|
||||
-- name: GetTeamRoleForUserID :one
|
||||
SELECT team_id, role_code FROM team_member WHERE user_id = $1 AND team_id = $2;
|
||||
|
||||
-- name: GetTeamRolesForUserID :many
|
||||
SELECT team_id, role_code FROM team_member WHERE user_id = $1;
|
||||
|
||||
-- name: GetTeamsForUserIDWhereAdmin :many
|
||||
SELECT team.* FROM team_member INNER JOIN team
|
||||
ON team.team_id = team_member.team_id WHERE (role_code = 'admin' OR role_code = 'member') AND user_id = $1;
|
@ -1,21 +0,0 @@
|
||||
-- name: CreateTeamMember :one
|
||||
INSERT INTO team_member (team_id, user_id, addedDate, role_code) VALUES ($1, $2, $3, $4)
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetTeamMembersForTeamID :many
|
||||
SELECT * FROM team_member WHERE team_id = $1;
|
||||
|
||||
-- name: DeleteTeamMember :exec
|
||||
DELETE FROM team_member WHERE user_id = $1 AND team_id = $2;
|
||||
|
||||
-- name: GetRoleForTeamMember :one
|
||||
SELECT code, role.name FROM team_member
|
||||
INNER JOIN role ON role.code = team_member.role_code
|
||||
WHERE user_id = $1 AND team_id = $2;
|
||||
|
||||
-- name: UpdateTeamMemberRole :one
|
||||
UPDATE team_member SET role_code = $3 WHERE user_id = $2 AND team_id = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetTeamMemberByID :one
|
||||
SELECT * FROM team_member WHERE team_id = $1 AND user_id = $2;
|
@ -1,14 +0,0 @@
|
||||
-- name: GetAuthTokenByID :one
|
||||
SELECT * FROM auth_token WHERE token_id = $1;
|
||||
|
||||
-- name: CreateAuthToken :one
|
||||
INSERT INTO auth_token (user_id, created_at, expires_at) VALUES ($1, $2, $3) RETURNING *;
|
||||
|
||||
-- name: DeleteAuthTokenByID :exec
|
||||
DELETE FROM auth_token WHERE token_id = $1;
|
||||
|
||||
-- name: DeleteAuthTokenByUserID :exec
|
||||
DELETE FROM auth_token WHERE user_id = $1;
|
||||
|
||||
-- name: DeleteExpiredTokens :exec
|
||||
DELETE FROM auth_token WHERE expires_at <= NOW();
|
23
internal/db/query/user_account.sql
Normal file
23
internal/db/query/user_account.sql
Normal file
@ -0,0 +1,23 @@
|
||||
-- name: GetUserAccounts :many
|
||||
SELECT * FROM user_account;
|
||||
|
||||
-- name: GetUserAccountByUsername :one
|
||||
SELECT * FROM user_account WHERE username = $1;
|
||||
|
||||
-- name: GetUserAccountByID :one
|
||||
SELECT * FROM user_account WHERE user_id = $1;
|
||||
|
||||
-- name: HasAnyUserAccount :one
|
||||
SELECT EXISTS (SELECT * FROM user_account LIMIT 1);
|
||||
|
||||
-- name: CreateUserAccount :one
|
||||
INSERT INTO user_account (created_at, fullname, username, email, password_hash) VALUES ($1, $2, $3, $4, $5) RETURNING *;
|
||||
|
||||
-- name: CreateAccessToken :one
|
||||
INSERT INTO access_token (token, user_id, expires_at, created_at) VALUES ($1, $2, $3, $4) RETURNING *;
|
||||
|
||||
-- name: GetAccessToken :one
|
||||
SELECT * FROM access_token WHERE token = $1;
|
||||
|
||||
-- name: DeleteAccessToken :exec
|
||||
DELETE FROM access_token WHERE token = $1;
|
@ -1,106 +0,0 @@
|
||||
-- name: GetUserAccountByID :one
|
||||
SELECT * FROM user_account WHERE user_id = $1;
|
||||
|
||||
-- name: GetAllUserAccounts :many
|
||||
SELECT * FROM user_account WHERE username != 'system';
|
||||
|
||||
-- name: GetUserAccountByUsername :one
|
||||
SELECT * FROM user_account WHERE username = $1;
|
||||
|
||||
-- name: GetUserAccountByEmail :one
|
||||
SELECT * FROM user_account WHERE email = $1;
|
||||
|
||||
-- name: CreateUserAccount :one
|
||||
INSERT INTO user_account(full_name, initials, email, username, created_at, password_hash, role_code, active)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *;
|
||||
|
||||
-- name: UpdateUserAccountProfileAvatarURL :one
|
||||
UPDATE user_account SET profile_avatar_url = $2 WHERE user_id = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetMemberData :many
|
||||
SELECT * FROM user_account
|
||||
WHERE username != 'system'
|
||||
AND user_id NOT IN (SELECT user_id FROM project_member WHERE project_id = $1);
|
||||
|
||||
-- name: UpdateUserAccountInfo :one
|
||||
UPDATE user_account SET bio = $2, full_name = $3, initials = $4, email = $5
|
||||
WHERE user_id = $1 RETURNING *;
|
||||
|
||||
-- name: DeleteUserAccountByID :exec
|
||||
DELETE FROM user_account WHERE user_id = $1;
|
||||
|
||||
-- name: GetRoleForUserID :one
|
||||
SELECT username, role.code, role.name FROM user_account
|
||||
INNER JOIN role ON role.code = user_account.role_code
|
||||
WHERE user_id = $1;
|
||||
|
||||
-- name: UpdateUserRole :one
|
||||
UPDATE user_account SET role_code = $2 WHERE user_id = $1 RETURNING *;
|
||||
|
||||
-- name: SetUserPassword :one
|
||||
UPDATE user_account SET password_hash = $2 WHERE user_id = $1 RETURNING *;
|
||||
|
||||
-- name: CreateInvitedUser :one
|
||||
INSERT INTO user_account_invited (email) VALUES ($1) RETURNING *;
|
||||
|
||||
-- name: GetInvitedUserByEmail :one
|
||||
SELECT * FROM user_account_invited WHERE email = $1;
|
||||
|
||||
-- name: CreateInvitedProjectMember :one
|
||||
INSERT INTO project_member_invited (project_id, user_account_invited_id) VALUES ($1, $2)
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetInvitedUserAccounts :many
|
||||
SELECT * FROM user_account_invited;
|
||||
|
||||
-- name: DeleteInvitedUserAccount :one
|
||||
DELETE FROM user_account_invited WHERE user_account_invited_id = $1 RETURNING *;
|
||||
|
||||
-- name: HasAnyUser :one
|
||||
SELECT EXISTS(SELECT 1 FROM user_account WHERE username != 'system');
|
||||
|
||||
-- name: HasActiveUser :one
|
||||
SELECT EXISTS(SELECT 1 FROM user_account WHERE username != 'system' AND active = true);
|
||||
|
||||
-- name: DoesUserExist :one
|
||||
SELECT EXISTS(SELECT 1 FROM user_account WHERE email = $1 OR username = $2);
|
||||
|
||||
-- name: CreateConfirmToken :one
|
||||
INSERT INTO user_account_confirm_token (email) VALUES ($1) RETURNING *;
|
||||
|
||||
-- name: GetConfirmTokenByEmail :one
|
||||
SELECT * FROM user_account_confirm_token WHERE email = $1;
|
||||
|
||||
-- name: GetConfirmTokenByID :one
|
||||
SELECT * FROM user_account_confirm_token WHERE confirm_token_id = $1;
|
||||
|
||||
-- name: SetFirstUserActive :one
|
||||
UPDATE user_account SET active = true WHERE user_id = (
|
||||
SELECT user_id from user_account WHERE active = false LIMIT 1
|
||||
) RETURNING *;
|
||||
|
||||
-- name: SetUserActiveByEmail :one
|
||||
UPDATE user_account SET active = true WHERE email = $1 RETURNING *;
|
||||
|
||||
-- name: GetProjectsForInvitedMember :many
|
||||
SELECT project_id FROM user_account_invited AS uai
|
||||
INNER JOIN project_member_invited AS pmi
|
||||
ON pmi.user_account_invited_id = uai.user_account_invited_id
|
||||
WHERE uai.email = $1;
|
||||
|
||||
-- name: DeleteProjectMemberInvitedForEmail :exec
|
||||
DELETE FROM project_member_invited WHERE project_member_invited_id IN (
|
||||
SELECT pmi.project_member_invited_id FROM user_account_invited AS uai
|
||||
INNER JOIN project_member_invited AS pmi
|
||||
ON pmi.user_account_invited_id = uai.user_account_invited_id
|
||||
WHERE uai.email = $1
|
||||
);
|
||||
|
||||
-- name: DeleteUserAccountInvitedForEmail :exec
|
||||
DELETE FROM user_account_invited WHERE email = $1;
|
||||
|
||||
-- name: DeleteConfirmTokenForEmail :exec
|
||||
DELETE FROM user_account_confirm_token WHERE email = $1;
|
||||
|
||||
|
@ -1,19 +1,17 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
import "database/sql"
|
||||
|
||||
// Repository contains methods for interacting with a database storage
|
||||
type Repository struct {
|
||||
*Queries
|
||||
db *sqlx.DB
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
// NewRepository returns an implementation of the Repository interface.
|
||||
func NewRepository(db *sqlx.DB) *Repository {
|
||||
func NewRepository(db *sql.DB) *Repository {
|
||||
return &Repository{
|
||||
Queries: New(db.DB),
|
||||
Queries: New(db),
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
@ -1,41 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: system_options.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
const createSystemOption = `-- name: CreateSystemOption :one
|
||||
INSERT INTO system_options (key, value) VALUES ($1, $2) RETURNING option_id, key, value
|
||||
`
|
||||
|
||||
type CreateSystemOptionParams struct {
|
||||
Key string `json:"key"`
|
||||
Value sql.NullString `json:"value"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateSystemOption(ctx context.Context, arg CreateSystemOptionParams) (SystemOption, error) {
|
||||
row := q.db.QueryRowContext(ctx, createSystemOption, arg.Key, arg.Value)
|
||||
var i SystemOption
|
||||
err := row.Scan(&i.OptionID, &i.Key, &i.Value)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getSystemOptionByKey = `-- name: GetSystemOptionByKey :one
|
||||
SELECT key, value FROM system_options WHERE key = $1
|
||||
`
|
||||
|
||||
type GetSystemOptionByKeyRow struct {
|
||||
Key string `json:"key"`
|
||||
Value sql.NullString `json:"value"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetSystemOptionByKey(ctx context.Context, key string) (GetSystemOptionByKeyRow, error) {
|
||||
row := q.db.QueryRowContext(ctx, getSystemOptionByKey, key)
|
||||
var i GetSystemOptionByKeyRow
|
||||
err := row.Scan(&i.Key, &i.Value)
|
||||
return i, err
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,131 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: task_activity.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const createTaskActivity = `-- name: CreateTaskActivity :one
|
||||
INSERT INTO task_activity (task_id, caused_by, created_at, activity_type_id, data)
|
||||
VALUES ($1, $2, $3, $4, $5) RETURNING task_activity_id, active, task_id, created_at, caused_by, activity_type_id, data
|
||||
`
|
||||
|
||||
type CreateTaskActivityParams struct {
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
CausedBy uuid.UUID `json:"caused_by"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ActivityTypeID int32 `json:"activity_type_id"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateTaskActivity(ctx context.Context, arg CreateTaskActivityParams) (TaskActivity, error) {
|
||||
row := q.db.QueryRowContext(ctx, createTaskActivity,
|
||||
arg.TaskID,
|
||||
arg.CausedBy,
|
||||
arg.CreatedAt,
|
||||
arg.ActivityTypeID,
|
||||
arg.Data,
|
||||
)
|
||||
var i TaskActivity
|
||||
err := row.Scan(
|
||||
&i.TaskActivityID,
|
||||
&i.Active,
|
||||
&i.TaskID,
|
||||
&i.CreatedAt,
|
||||
&i.CausedBy,
|
||||
&i.ActivityTypeID,
|
||||
&i.Data,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getActivityForTaskID = `-- name: GetActivityForTaskID :many
|
||||
SELECT task_activity_id, active, task_id, created_at, caused_by, activity_type_id, data FROM task_activity WHERE task_id = $1 AND active = true
|
||||
`
|
||||
|
||||
func (q *Queries) GetActivityForTaskID(ctx context.Context, taskID uuid.UUID) ([]TaskActivity, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getActivityForTaskID, taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []TaskActivity
|
||||
for rows.Next() {
|
||||
var i TaskActivity
|
||||
if err := rows.Scan(
|
||||
&i.TaskActivityID,
|
||||
&i.Active,
|
||||
&i.TaskID,
|
||||
&i.CreatedAt,
|
||||
&i.CausedBy,
|
||||
&i.ActivityTypeID,
|
||||
&i.Data,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getLastMoveForTaskID = `-- name: GetLastMoveForTaskID :one
|
||||
SELECT active, created_at, data->>'CurTaskGroupID' AS cur_task_group_id, data->>'PrevTaskGroupID' AS prev_task_group_id FROM task_activity
|
||||
WHERE task_id = $1 AND activity_type_id = 2 AND created_at >= NOW() - INTERVAL '5 minutes'
|
||||
ORDER BY created_at DESC LIMIT 1
|
||||
`
|
||||
|
||||
type GetLastMoveForTaskIDRow struct {
|
||||
Active bool `json:"active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
CurTaskGroupID interface{} `json:"cur_task_group_id"`
|
||||
PrevTaskGroupID interface{} `json:"prev_task_group_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetLastMoveForTaskID(ctx context.Context, taskID uuid.UUID) (GetLastMoveForTaskIDRow, error) {
|
||||
row := q.db.QueryRowContext(ctx, getLastMoveForTaskID, taskID)
|
||||
var i GetLastMoveForTaskIDRow
|
||||
err := row.Scan(
|
||||
&i.Active,
|
||||
&i.CreatedAt,
|
||||
&i.CurTaskGroupID,
|
||||
&i.PrevTaskGroupID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTemplateForActivityID = `-- name: GetTemplateForActivityID :one
|
||||
SELECT template FROM task_activity_type WHERE task_activity_type_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTemplateForActivityID(ctx context.Context, taskActivityTypeID int32) (string, error) {
|
||||
row := q.db.QueryRowContext(ctx, getTemplateForActivityID, taskActivityTypeID)
|
||||
var template string
|
||||
err := row.Scan(&template)
|
||||
return template, err
|
||||
}
|
||||
|
||||
const setInactiveLastMoveForTaskID = `-- name: SetInactiveLastMoveForTaskID :exec
|
||||
UPDATE task_activity SET active = false WHERE task_activity_id = (
|
||||
SELECT task_activity_id FROM task_activity AS ta
|
||||
WHERE ta.activity_type_id = 2 AND ta.task_id = $1
|
||||
AND ta.created_at >= NOW() - INTERVAL '5 minutes'
|
||||
ORDER BY created_at DESC LIMIT 1
|
||||
)
|
||||
`
|
||||
|
||||
func (q *Queries) SetInactiveLastMoveForTaskID(ctx context.Context, taskID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, setInactiveLastMoveForTaskID, taskID)
|
||||
return err
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: task_assigned.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const createTaskAssigned = `-- name: CreateTaskAssigned :one
|
||||
INSERT INTO task_assigned (task_id, user_id, assigned_date)
|
||||
VALUES($1, $2, $3) RETURNING task_assigned_id, task_id, user_id, assigned_date
|
||||
`
|
||||
|
||||
type CreateTaskAssignedParams struct {
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
AssignedDate time.Time `json:"assigned_date"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateTaskAssigned(ctx context.Context, arg CreateTaskAssignedParams) (TaskAssigned, error) {
|
||||
row := q.db.QueryRowContext(ctx, createTaskAssigned, arg.TaskID, arg.UserID, arg.AssignedDate)
|
||||
var i TaskAssigned
|
||||
err := row.Scan(
|
||||
&i.TaskAssignedID,
|
||||
&i.TaskID,
|
||||
&i.UserID,
|
||||
&i.AssignedDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteTaskAssignedByID = `-- name: DeleteTaskAssignedByID :one
|
||||
DELETE FROM task_assigned WHERE task_id = $1 AND user_id = $2 RETURNING task_assigned_id, task_id, user_id, assigned_date
|
||||
`
|
||||
|
||||
type DeleteTaskAssignedByIDParams struct {
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) DeleteTaskAssignedByID(ctx context.Context, arg DeleteTaskAssignedByIDParams) (TaskAssigned, error) {
|
||||
row := q.db.QueryRowContext(ctx, deleteTaskAssignedByID, arg.TaskID, arg.UserID)
|
||||
var i TaskAssigned
|
||||
err := row.Scan(
|
||||
&i.TaskAssignedID,
|
||||
&i.TaskID,
|
||||
&i.UserID,
|
||||
&i.AssignedDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getAssignedMembersForTask = `-- name: GetAssignedMembersForTask :many
|
||||
SELECT task_assigned_id, task_id, user_id, assigned_date FROM task_assigned WHERE task_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetAssignedMembersForTask(ctx context.Context, taskID uuid.UUID) ([]TaskAssigned, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getAssignedMembersForTask, taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []TaskAssigned
|
||||
for rows.Next() {
|
||||
var i TaskAssigned
|
||||
if err := rows.Scan(
|
||||
&i.TaskAssignedID,
|
||||
&i.TaskID,
|
||||
&i.UserID,
|
||||
&i.AssignedDate,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
@ -1,344 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: task_checklist.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const createTaskChecklist = `-- name: CreateTaskChecklist :one
|
||||
INSERT INTO task_checklist (task_id, created_at, name, position) VALUES ($1, $2, $3, $4)
|
||||
RETURNING task_checklist_id, task_id, created_at, name, position
|
||||
`
|
||||
|
||||
type CreateTaskChecklistParams struct {
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
Position float64 `json:"position"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateTaskChecklist(ctx context.Context, arg CreateTaskChecklistParams) (TaskChecklist, error) {
|
||||
row := q.db.QueryRowContext(ctx, createTaskChecklist,
|
||||
arg.TaskID,
|
||||
arg.CreatedAt,
|
||||
arg.Name,
|
||||
arg.Position,
|
||||
)
|
||||
var i TaskChecklist
|
||||
err := row.Scan(
|
||||
&i.TaskChecklistID,
|
||||
&i.TaskID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createTaskChecklistItem = `-- name: CreateTaskChecklistItem :one
|
||||
INSERT INTO task_checklist_item (task_checklist_id, created_at, name, position, complete, due_date) VALUES ($1, $2, $3, $4, false, null)
|
||||
RETURNING task_checklist_item_id, task_checklist_id, created_at, complete, name, position, due_date
|
||||
`
|
||||
|
||||
type CreateTaskChecklistItemParams struct {
|
||||
TaskChecklistID uuid.UUID `json:"task_checklist_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
Position float64 `json:"position"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateTaskChecklistItem(ctx context.Context, arg CreateTaskChecklistItemParams) (TaskChecklistItem, error) {
|
||||
row := q.db.QueryRowContext(ctx, createTaskChecklistItem,
|
||||
arg.TaskChecklistID,
|
||||
arg.CreatedAt,
|
||||
arg.Name,
|
||||
arg.Position,
|
||||
)
|
||||
var i TaskChecklistItem
|
||||
err := row.Scan(
|
||||
&i.TaskChecklistItemID,
|
||||
&i.TaskChecklistID,
|
||||
&i.CreatedAt,
|
||||
&i.Complete,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
&i.DueDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteTaskChecklistByID = `-- name: DeleteTaskChecklistByID :exec
|
||||
DELETE FROM task_checklist WHERE task_checklist_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteTaskChecklistByID(ctx context.Context, taskChecklistID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteTaskChecklistByID, taskChecklistID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteTaskChecklistItem = `-- name: DeleteTaskChecklistItem :exec
|
||||
DELETE FROM task_checklist_item WHERE task_checklist_item_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteTaskChecklistItem(ctx context.Context, taskChecklistItemID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteTaskChecklistItem, taskChecklistItemID)
|
||||
return err
|
||||
}
|
||||
|
||||
const getProjectIDForTaskChecklist = `-- name: GetProjectIDForTaskChecklist :one
|
||||
SELECT project_id FROM task_checklist
|
||||
INNER JOIN task ON task.task_id = task_checklist.task_id
|
||||
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
||||
WHERE task_checklist.task_checklist_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetProjectIDForTaskChecklist(ctx context.Context, taskChecklistID uuid.UUID) (uuid.UUID, error) {
|
||||
row := q.db.QueryRowContext(ctx, getProjectIDForTaskChecklist, taskChecklistID)
|
||||
var project_id uuid.UUID
|
||||
err := row.Scan(&project_id)
|
||||
return project_id, err
|
||||
}
|
||||
|
||||
const getProjectIDForTaskChecklistItem = `-- name: GetProjectIDForTaskChecklistItem :one
|
||||
SELECT project_id FROM task_checklist_item AS tci
|
||||
INNER JOIN task_checklist ON task_checklist.task_checklist_id = tci.task_checklist_id
|
||||
INNER JOIN task ON task.task_id = task_checklist.task_id
|
||||
INNER JOIN task_group ON task_group.task_group_id = task.task_group_id
|
||||
WHERE tci.task_checklist_item_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetProjectIDForTaskChecklistItem(ctx context.Context, taskChecklistItemID uuid.UUID) (uuid.UUID, error) {
|
||||
row := q.db.QueryRowContext(ctx, getProjectIDForTaskChecklistItem, taskChecklistItemID)
|
||||
var project_id uuid.UUID
|
||||
err := row.Scan(&project_id)
|
||||
return project_id, err
|
||||
}
|
||||
|
||||
const getTaskChecklistByID = `-- name: GetTaskChecklistByID :one
|
||||
SELECT task_checklist_id, task_id, created_at, name, position FROM task_checklist WHERE task_checklist_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTaskChecklistByID(ctx context.Context, taskChecklistID uuid.UUID) (TaskChecklist, error) {
|
||||
row := q.db.QueryRowContext(ctx, getTaskChecklistByID, taskChecklistID)
|
||||
var i TaskChecklist
|
||||
err := row.Scan(
|
||||
&i.TaskChecklistID,
|
||||
&i.TaskID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTaskChecklistItemByID = `-- name: GetTaskChecklistItemByID :one
|
||||
SELECT task_checklist_item_id, task_checklist_id, created_at, complete, name, position, due_date FROM task_checklist_item WHERE task_checklist_item_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTaskChecklistItemByID(ctx context.Context, taskChecklistItemID uuid.UUID) (TaskChecklistItem, error) {
|
||||
row := q.db.QueryRowContext(ctx, getTaskChecklistItemByID, taskChecklistItemID)
|
||||
var i TaskChecklistItem
|
||||
err := row.Scan(
|
||||
&i.TaskChecklistItemID,
|
||||
&i.TaskChecklistID,
|
||||
&i.CreatedAt,
|
||||
&i.Complete,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
&i.DueDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTaskChecklistItemsForTaskChecklist = `-- name: GetTaskChecklistItemsForTaskChecklist :many
|
||||
SELECT task_checklist_item_id, task_checklist_id, created_at, complete, name, position, due_date FROM task_checklist_item WHERE task_checklist_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTaskChecklistItemsForTaskChecklist(ctx context.Context, taskChecklistID uuid.UUID) ([]TaskChecklistItem, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getTaskChecklistItemsForTaskChecklist, taskChecklistID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []TaskChecklistItem
|
||||
for rows.Next() {
|
||||
var i TaskChecklistItem
|
||||
if err := rows.Scan(
|
||||
&i.TaskChecklistItemID,
|
||||
&i.TaskChecklistID,
|
||||
&i.CreatedAt,
|
||||
&i.Complete,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
&i.DueDate,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getTaskChecklistsForTask = `-- name: GetTaskChecklistsForTask :many
|
||||
SELECT task_checklist_id, task_id, created_at, name, position FROM task_checklist WHERE task_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTaskChecklistsForTask(ctx context.Context, taskID uuid.UUID) ([]TaskChecklist, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getTaskChecklistsForTask, taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []TaskChecklist
|
||||
for rows.Next() {
|
||||
var i TaskChecklist
|
||||
if err := rows.Scan(
|
||||
&i.TaskChecklistID,
|
||||
&i.TaskID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const setTaskChecklistItemComplete = `-- name: SetTaskChecklistItemComplete :one
|
||||
UPDATE task_checklist_item SET complete = $2 WHERE task_checklist_item_id = $1
|
||||
RETURNING task_checklist_item_id, task_checklist_id, created_at, complete, name, position, due_date
|
||||
`
|
||||
|
||||
type SetTaskChecklistItemCompleteParams struct {
|
||||
TaskChecklistItemID uuid.UUID `json:"task_checklist_item_id"`
|
||||
Complete bool `json:"complete"`
|
||||
}
|
||||
|
||||
func (q *Queries) SetTaskChecklistItemComplete(ctx context.Context, arg SetTaskChecklistItemCompleteParams) (TaskChecklistItem, error) {
|
||||
row := q.db.QueryRowContext(ctx, setTaskChecklistItemComplete, arg.TaskChecklistItemID, arg.Complete)
|
||||
var i TaskChecklistItem
|
||||
err := row.Scan(
|
||||
&i.TaskChecklistItemID,
|
||||
&i.TaskChecklistID,
|
||||
&i.CreatedAt,
|
||||
&i.Complete,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
&i.DueDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateTaskChecklistItemLocation = `-- name: UpdateTaskChecklistItemLocation :one
|
||||
UPDATE task_checklist_item SET position = $2, task_checklist_id = $3 WHERE task_checklist_item_id = $1 RETURNING task_checklist_item_id, task_checklist_id, created_at, complete, name, position, due_date
|
||||
`
|
||||
|
||||
type UpdateTaskChecklistItemLocationParams struct {
|
||||
TaskChecklistItemID uuid.UUID `json:"task_checklist_item_id"`
|
||||
Position float64 `json:"position"`
|
||||
TaskChecklistID uuid.UUID `json:"task_checklist_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateTaskChecklistItemLocation(ctx context.Context, arg UpdateTaskChecklistItemLocationParams) (TaskChecklistItem, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateTaskChecklistItemLocation, arg.TaskChecklistItemID, arg.Position, arg.TaskChecklistID)
|
||||
var i TaskChecklistItem
|
||||
err := row.Scan(
|
||||
&i.TaskChecklistItemID,
|
||||
&i.TaskChecklistID,
|
||||
&i.CreatedAt,
|
||||
&i.Complete,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
&i.DueDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateTaskChecklistItemName = `-- name: UpdateTaskChecklistItemName :one
|
||||
UPDATE task_checklist_item SET name = $2 WHERE task_checklist_item_id = $1
|
||||
RETURNING task_checklist_item_id, task_checklist_id, created_at, complete, name, position, due_date
|
||||
`
|
||||
|
||||
type UpdateTaskChecklistItemNameParams struct {
|
||||
TaskChecklistItemID uuid.UUID `json:"task_checklist_item_id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateTaskChecklistItemName(ctx context.Context, arg UpdateTaskChecklistItemNameParams) (TaskChecklistItem, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateTaskChecklistItemName, arg.TaskChecklistItemID, arg.Name)
|
||||
var i TaskChecklistItem
|
||||
err := row.Scan(
|
||||
&i.TaskChecklistItemID,
|
||||
&i.TaskChecklistID,
|
||||
&i.CreatedAt,
|
||||
&i.Complete,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
&i.DueDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateTaskChecklistName = `-- name: UpdateTaskChecklistName :one
|
||||
UPDATE task_checklist SET name = $2 WHERE task_checklist_id = $1
|
||||
RETURNING task_checklist_id, task_id, created_at, name, position
|
||||
`
|
||||
|
||||
type UpdateTaskChecklistNameParams struct {
|
||||
TaskChecklistID uuid.UUID `json:"task_checklist_id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateTaskChecklistName(ctx context.Context, arg UpdateTaskChecklistNameParams) (TaskChecklist, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateTaskChecklistName, arg.TaskChecklistID, arg.Name)
|
||||
var i TaskChecklist
|
||||
err := row.Scan(
|
||||
&i.TaskChecklistID,
|
||||
&i.TaskID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateTaskChecklistPosition = `-- name: UpdateTaskChecklistPosition :one
|
||||
UPDATE task_checklist SET position = $2 WHERE task_checklist_id = $1 RETURNING task_checklist_id, task_id, created_at, name, position
|
||||
`
|
||||
|
||||
type UpdateTaskChecklistPositionParams struct {
|
||||
TaskChecklistID uuid.UUID `json:"task_checklist_id"`
|
||||
Position float64 `json:"position"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateTaskChecklistPosition(ctx context.Context, arg UpdateTaskChecklistPositionParams) (TaskChecklist, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateTaskChecklistPosition, arg.TaskChecklistID, arg.Position)
|
||||
var i TaskChecklist
|
||||
err := row.Scan(
|
||||
&i.TaskChecklistID,
|
||||
&i.TaskID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
)
|
||||
return i, err
|
||||
}
|
@ -1,191 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: task_group.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const createTaskGroup = `-- name: CreateTaskGroup :one
|
||||
INSERT INTO task_group (project_id, created_at, name, position)
|
||||
VALUES($1, $2, $3, $4) RETURNING task_group_id, project_id, created_at, name, position
|
||||
`
|
||||
|
||||
type CreateTaskGroupParams struct {
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
Position float64 `json:"position"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateTaskGroup(ctx context.Context, arg CreateTaskGroupParams) (TaskGroup, error) {
|
||||
row := q.db.QueryRowContext(ctx, createTaskGroup,
|
||||
arg.ProjectID,
|
||||
arg.CreatedAt,
|
||||
arg.Name,
|
||||
arg.Position,
|
||||
)
|
||||
var i TaskGroup
|
||||
err := row.Scan(
|
||||
&i.TaskGroupID,
|
||||
&i.ProjectID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteTaskGroupByID = `-- name: DeleteTaskGroupByID :execrows
|
||||
DELETE FROM task_group WHERE task_group_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteTaskGroupByID(ctx context.Context, taskGroupID uuid.UUID) (int64, error) {
|
||||
result, err := q.db.ExecContext(ctx, deleteTaskGroupByID, taskGroupID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.RowsAffected()
|
||||
}
|
||||
|
||||
const getAllTaskGroups = `-- name: GetAllTaskGroups :many
|
||||
SELECT task_group_id, project_id, created_at, name, position FROM task_group
|
||||
`
|
||||
|
||||
func (q *Queries) GetAllTaskGroups(ctx context.Context) ([]TaskGroup, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getAllTaskGroups)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []TaskGroup
|
||||
for rows.Next() {
|
||||
var i TaskGroup
|
||||
if err := rows.Scan(
|
||||
&i.TaskGroupID,
|
||||
&i.ProjectID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getProjectIDForTaskGroup = `-- name: GetProjectIDForTaskGroup :one
|
||||
SELECT project_id from task_group WHERE task_group_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetProjectIDForTaskGroup(ctx context.Context, taskGroupID uuid.UUID) (uuid.UUID, error) {
|
||||
row := q.db.QueryRowContext(ctx, getProjectIDForTaskGroup, taskGroupID)
|
||||
var project_id uuid.UUID
|
||||
err := row.Scan(&project_id)
|
||||
return project_id, err
|
||||
}
|
||||
|
||||
const getTaskGroupByID = `-- name: GetTaskGroupByID :one
|
||||
SELECT task_group_id, project_id, created_at, name, position FROM task_group WHERE task_group_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTaskGroupByID(ctx context.Context, taskGroupID uuid.UUID) (TaskGroup, error) {
|
||||
row := q.db.QueryRowContext(ctx, getTaskGroupByID, taskGroupID)
|
||||
var i TaskGroup
|
||||
err := row.Scan(
|
||||
&i.TaskGroupID,
|
||||
&i.ProjectID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTaskGroupsForProject = `-- name: GetTaskGroupsForProject :many
|
||||
SELECT task_group_id, project_id, created_at, name, position FROM task_group WHERE project_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTaskGroupsForProject(ctx context.Context, projectID uuid.UUID) ([]TaskGroup, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getTaskGroupsForProject, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []TaskGroup
|
||||
for rows.Next() {
|
||||
var i TaskGroup
|
||||
if err := rows.Scan(
|
||||
&i.TaskGroupID,
|
||||
&i.ProjectID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const setTaskGroupName = `-- name: SetTaskGroupName :one
|
||||
UPDATE task_group SET name = $2 WHERE task_group_id = $1 RETURNING task_group_id, project_id, created_at, name, position
|
||||
`
|
||||
|
||||
type SetTaskGroupNameParams struct {
|
||||
TaskGroupID uuid.UUID `json:"task_group_id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (q *Queries) SetTaskGroupName(ctx context.Context, arg SetTaskGroupNameParams) (TaskGroup, error) {
|
||||
row := q.db.QueryRowContext(ctx, setTaskGroupName, arg.TaskGroupID, arg.Name)
|
||||
var i TaskGroup
|
||||
err := row.Scan(
|
||||
&i.TaskGroupID,
|
||||
&i.ProjectID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateTaskGroupLocation = `-- name: UpdateTaskGroupLocation :one
|
||||
UPDATE task_group SET position = $2 WHERE task_group_id = $1 RETURNING task_group_id, project_id, created_at, name, position
|
||||
`
|
||||
|
||||
type UpdateTaskGroupLocationParams struct {
|
||||
TaskGroupID uuid.UUID `json:"task_group_id"`
|
||||
Position float64 `json:"position"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateTaskGroupLocation(ctx context.Context, arg UpdateTaskGroupLocationParams) (TaskGroup, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateTaskGroupLocation, arg.TaskGroupID, arg.Position)
|
||||
var i TaskGroup
|
||||
err := row.Scan(
|
||||
&i.TaskGroupID,
|
||||
&i.ProjectID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.Position,
|
||||
)
|
||||
return i, err
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: task_label.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const createTaskLabelForTask = `-- name: CreateTaskLabelForTask :one
|
||||
INSERT INTO task_label (task_id, project_label_id, assigned_date)
|
||||
VALUES ($1, $2, $3) RETURNING task_label_id, task_id, project_label_id, assigned_date
|
||||
`
|
||||
|
||||
type CreateTaskLabelForTaskParams struct {
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
ProjectLabelID uuid.UUID `json:"project_label_id"`
|
||||
AssignedDate time.Time `json:"assigned_date"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateTaskLabelForTask(ctx context.Context, arg CreateTaskLabelForTaskParams) (TaskLabel, error) {
|
||||
row := q.db.QueryRowContext(ctx, createTaskLabelForTask, arg.TaskID, arg.ProjectLabelID, arg.AssignedDate)
|
||||
var i TaskLabel
|
||||
err := row.Scan(
|
||||
&i.TaskLabelID,
|
||||
&i.TaskID,
|
||||
&i.ProjectLabelID,
|
||||
&i.AssignedDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteTaskLabelByID = `-- name: DeleteTaskLabelByID :exec
|
||||
DELETE FROM task_label WHERE task_label_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteTaskLabelByID(ctx context.Context, taskLabelID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteTaskLabelByID, taskLabelID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteTaskLabelForTaskByProjectLabelID = `-- name: DeleteTaskLabelForTaskByProjectLabelID :exec
|
||||
DELETE FROM task_label WHERE project_label_id = $2 AND task_id = $1
|
||||
`
|
||||
|
||||
type DeleteTaskLabelForTaskByProjectLabelIDParams struct {
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
ProjectLabelID uuid.UUID `json:"project_label_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) DeleteTaskLabelForTaskByProjectLabelID(ctx context.Context, arg DeleteTaskLabelForTaskByProjectLabelIDParams) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteTaskLabelForTaskByProjectLabelID, arg.TaskID, arg.ProjectLabelID)
|
||||
return err
|
||||
}
|
||||
|
||||
const getTaskLabelByID = `-- name: GetTaskLabelByID :one
|
||||
SELECT task_label_id, task_id, project_label_id, assigned_date FROM task_label WHERE task_label_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTaskLabelByID(ctx context.Context, taskLabelID uuid.UUID) (TaskLabel, error) {
|
||||
row := q.db.QueryRowContext(ctx, getTaskLabelByID, taskLabelID)
|
||||
var i TaskLabel
|
||||
err := row.Scan(
|
||||
&i.TaskLabelID,
|
||||
&i.TaskID,
|
||||
&i.ProjectLabelID,
|
||||
&i.AssignedDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTaskLabelForTaskByProjectLabelID = `-- name: GetTaskLabelForTaskByProjectLabelID :one
|
||||
SELECT task_label_id, task_id, project_label_id, assigned_date FROM task_label WHERE task_id = $1 AND project_label_id = $2
|
||||
`
|
||||
|
||||
type GetTaskLabelForTaskByProjectLabelIDParams struct {
|
||||
TaskID uuid.UUID `json:"task_id"`
|
||||
ProjectLabelID uuid.UUID `json:"project_label_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetTaskLabelForTaskByProjectLabelID(ctx context.Context, arg GetTaskLabelForTaskByProjectLabelIDParams) (TaskLabel, error) {
|
||||
row := q.db.QueryRowContext(ctx, getTaskLabelForTaskByProjectLabelID, arg.TaskID, arg.ProjectLabelID)
|
||||
var i TaskLabel
|
||||
err := row.Scan(
|
||||
&i.TaskLabelID,
|
||||
&i.TaskID,
|
||||
&i.ProjectLabelID,
|
||||
&i.AssignedDate,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTaskLabelsForTaskID = `-- name: GetTaskLabelsForTaskID :many
|
||||
SELECT task_label_id, task_id, project_label_id, assigned_date FROM task_label WHERE task_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTaskLabelsForTaskID(ctx context.Context, taskID uuid.UUID) ([]TaskLabel, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getTaskLabelsForTaskID, taskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []TaskLabel
|
||||
for rows.Next() {
|
||||
var i TaskLabel
|
||||
if err := rows.Scan(
|
||||
&i.TaskLabelID,
|
||||
&i.TaskID,
|
||||
&i.ProjectLabelID,
|
||||
&i.AssignedDate,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
@ -1,235 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: team.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const createTeam = `-- name: CreateTeam :one
|
||||
INSERT INTO team (organization_id, created_at, name) VALUES ($1, $2, $3) RETURNING team_id, created_at, name, organization_id
|
||||
`
|
||||
|
||||
type CreateTeamParams struct {
|
||||
OrganizationID uuid.UUID `json:"organization_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateTeam(ctx context.Context, arg CreateTeamParams) (Team, error) {
|
||||
row := q.db.QueryRowContext(ctx, createTeam, arg.OrganizationID, arg.CreatedAt, arg.Name)
|
||||
var i Team
|
||||
err := row.Scan(
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.OrganizationID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteTeamByID = `-- name: DeleteTeamByID :exec
|
||||
DELETE FROM team WHERE team_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteTeamByID(ctx context.Context, teamID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteTeamByID, teamID)
|
||||
return err
|
||||
}
|
||||
|
||||
const getAllTeams = `-- name: GetAllTeams :many
|
||||
SELECT team_id, created_at, name, organization_id FROM team
|
||||
`
|
||||
|
||||
func (q *Queries) GetAllTeams(ctx context.Context) ([]Team, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getAllTeams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Team
|
||||
for rows.Next() {
|
||||
var i Team
|
||||
if err := rows.Scan(
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.OrganizationID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getMemberTeamIDsForUserID = `-- name: GetMemberTeamIDsForUserID :many
|
||||
SELECT team_id FROM team_member WHERE user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetMemberTeamIDsForUserID(ctx context.Context, userID uuid.UUID) ([]uuid.UUID, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getMemberTeamIDsForUserID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []uuid.UUID
|
||||
for rows.Next() {
|
||||
var team_id uuid.UUID
|
||||
if err := rows.Scan(&team_id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, team_id)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getTeamByID = `-- name: GetTeamByID :one
|
||||
SELECT team_id, created_at, name, organization_id FROM team WHERE team_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTeamByID(ctx context.Context, teamID uuid.UUID) (Team, error) {
|
||||
row := q.db.QueryRowContext(ctx, getTeamByID, teamID)
|
||||
var i Team
|
||||
err := row.Scan(
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.OrganizationID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTeamRoleForUserID = `-- name: GetTeamRoleForUserID :one
|
||||
SELECT team_id, role_code FROM team_member WHERE user_id = $1 AND team_id = $2
|
||||
`
|
||||
|
||||
type GetTeamRoleForUserIDParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
TeamID uuid.UUID `json:"team_id"`
|
||||
}
|
||||
|
||||
type GetTeamRoleForUserIDRow struct {
|
||||
TeamID uuid.UUID `json:"team_id"`
|
||||
RoleCode string `json:"role_code"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetTeamRoleForUserID(ctx context.Context, arg GetTeamRoleForUserIDParams) (GetTeamRoleForUserIDRow, error) {
|
||||
row := q.db.QueryRowContext(ctx, getTeamRoleForUserID, arg.UserID, arg.TeamID)
|
||||
var i GetTeamRoleForUserIDRow
|
||||
err := row.Scan(&i.TeamID, &i.RoleCode)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTeamRolesForUserID = `-- name: GetTeamRolesForUserID :many
|
||||
SELECT team_id, role_code FROM team_member WHERE user_id = $1
|
||||
`
|
||||
|
||||
type GetTeamRolesForUserIDRow struct {
|
||||
TeamID uuid.UUID `json:"team_id"`
|
||||
RoleCode string `json:"role_code"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetTeamRolesForUserID(ctx context.Context, userID uuid.UUID) ([]GetTeamRolesForUserIDRow, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getTeamRolesForUserID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetTeamRolesForUserIDRow
|
||||
for rows.Next() {
|
||||
var i GetTeamRolesForUserIDRow
|
||||
if err := rows.Scan(&i.TeamID, &i.RoleCode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getTeamsForOrganization = `-- name: GetTeamsForOrganization :many
|
||||
SELECT team_id, created_at, name, organization_id FROM team WHERE organization_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTeamsForOrganization(ctx context.Context, organizationID uuid.UUID) ([]Team, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getTeamsForOrganization, organizationID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Team
|
||||
for rows.Next() {
|
||||
var i Team
|
||||
if err := rows.Scan(
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.OrganizationID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getTeamsForUserIDWhereAdmin = `-- name: GetTeamsForUserIDWhereAdmin :many
|
||||
SELECT team.team_id, team.created_at, team.name, team.organization_id FROM team_member INNER JOIN team
|
||||
ON team.team_id = team_member.team_id WHERE (role_code = 'admin' OR role_code = 'member') AND user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTeamsForUserIDWhereAdmin(ctx context.Context, userID uuid.UUID) ([]Team, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getTeamsForUserIDWhereAdmin, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Team
|
||||
for rows.Next() {
|
||||
var i Team
|
||||
if err := rows.Scan(
|
||||
&i.TeamID,
|
||||
&i.CreatedAt,
|
||||
&i.Name,
|
||||
&i.OrganizationID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: team_member.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const createTeamMember = `-- name: CreateTeamMember :one
|
||||
INSERT INTO team_member (team_id, user_id, addedDate, role_code) VALUES ($1, $2, $3, $4)
|
||||
RETURNING team_member_id, team_id, user_id, addeddate, role_code
|
||||
`
|
||||
|
||||
type CreateTeamMemberParams struct {
|
||||
TeamID uuid.UUID `json:"team_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
Addeddate time.Time `json:"addeddate"`
|
||||
RoleCode string `json:"role_code"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateTeamMember(ctx context.Context, arg CreateTeamMemberParams) (TeamMember, error) {
|
||||
row := q.db.QueryRowContext(ctx, createTeamMember,
|
||||
arg.TeamID,
|
||||
arg.UserID,
|
||||
arg.Addeddate,
|
||||
arg.RoleCode,
|
||||
)
|
||||
var i TeamMember
|
||||
err := row.Scan(
|
||||
&i.TeamMemberID,
|
||||
&i.TeamID,
|
||||
&i.UserID,
|
||||
&i.Addeddate,
|
||||
&i.RoleCode,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteTeamMember = `-- name: DeleteTeamMember :exec
|
||||
DELETE FROM team_member WHERE user_id = $1 AND team_id = $2
|
||||
`
|
||||
|
||||
type DeleteTeamMemberParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
TeamID uuid.UUID `json:"team_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) DeleteTeamMember(ctx context.Context, arg DeleteTeamMemberParams) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteTeamMember, arg.UserID, arg.TeamID)
|
||||
return err
|
||||
}
|
||||
|
||||
const getRoleForTeamMember = `-- name: GetRoleForTeamMember :one
|
||||
SELECT code, role.name FROM team_member
|
||||
INNER JOIN role ON role.code = team_member.role_code
|
||||
WHERE user_id = $1 AND team_id = $2
|
||||
`
|
||||
|
||||
type GetRoleForTeamMemberParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
TeamID uuid.UUID `json:"team_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetRoleForTeamMember(ctx context.Context, arg GetRoleForTeamMemberParams) (Role, error) {
|
||||
row := q.db.QueryRowContext(ctx, getRoleForTeamMember, arg.UserID, arg.TeamID)
|
||||
var i Role
|
||||
err := row.Scan(&i.Code, &i.Name)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTeamMemberByID = `-- name: GetTeamMemberByID :one
|
||||
SELECT team_member_id, team_id, user_id, addeddate, role_code FROM team_member WHERE team_id = $1 AND user_id = $2
|
||||
`
|
||||
|
||||
type GetTeamMemberByIDParams struct {
|
||||
TeamID uuid.UUID `json:"team_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetTeamMemberByID(ctx context.Context, arg GetTeamMemberByIDParams) (TeamMember, error) {
|
||||
row := q.db.QueryRowContext(ctx, getTeamMemberByID, arg.TeamID, arg.UserID)
|
||||
var i TeamMember
|
||||
err := row.Scan(
|
||||
&i.TeamMemberID,
|
||||
&i.TeamID,
|
||||
&i.UserID,
|
||||
&i.Addeddate,
|
||||
&i.RoleCode,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getTeamMembersForTeamID = `-- name: GetTeamMembersForTeamID :many
|
||||
SELECT team_member_id, team_id, user_id, addeddate, role_code FROM team_member WHERE team_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetTeamMembersForTeamID(ctx context.Context, teamID uuid.UUID) ([]TeamMember, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getTeamMembersForTeamID, teamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []TeamMember
|
||||
for rows.Next() {
|
||||
var i TeamMember
|
||||
if err := rows.Scan(
|
||||
&i.TeamMemberID,
|
||||
&i.TeamID,
|
||||
&i.UserID,
|
||||
&i.Addeddate,
|
||||
&i.RoleCode,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const updateTeamMemberRole = `-- name: UpdateTeamMemberRole :one
|
||||
UPDATE team_member SET role_code = $3 WHERE user_id = $2 AND team_id = $1
|
||||
RETURNING team_member_id, team_id, user_id, addeddate, role_code
|
||||
`
|
||||
|
||||
type UpdateTeamMemberRoleParams struct {
|
||||
TeamID uuid.UUID `json:"team_id"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
RoleCode string `json:"role_code"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateTeamMemberRole(ctx context.Context, arg UpdateTeamMemberRoleParams) (TeamMember, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateTeamMemberRole, arg.TeamID, arg.UserID, arg.RoleCode)
|
||||
var i TeamMember
|
||||
err := row.Scan(
|
||||
&i.TeamMemberID,
|
||||
&i.TeamID,
|
||||
&i.UserID,
|
||||
&i.Addeddate,
|
||||
&i.RoleCode,
|
||||
)
|
||||
return i, err
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: token.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const createAuthToken = `-- name: CreateAuthToken :one
|
||||
INSERT INTO auth_token (user_id, created_at, expires_at) VALUES ($1, $2, $3) RETURNING token_id, user_id, created_at, expires_at
|
||||
`
|
||||
|
||||
type CreateAuthTokenParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateAuthToken(ctx context.Context, arg CreateAuthTokenParams) (AuthToken, error) {
|
||||
row := q.db.QueryRowContext(ctx, createAuthToken, arg.UserID, arg.CreatedAt, arg.ExpiresAt)
|
||||
var i AuthToken
|
||||
err := row.Scan(
|
||||
&i.TokenID,
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.ExpiresAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteAuthTokenByID = `-- name: DeleteAuthTokenByID :exec
|
||||
DELETE FROM auth_token WHERE token_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteAuthTokenByID(ctx context.Context, tokenID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteAuthTokenByID, tokenID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteAuthTokenByUserID = `-- name: DeleteAuthTokenByUserID :exec
|
||||
DELETE FROM auth_token WHERE user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteAuthTokenByUserID(ctx context.Context, userID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteAuthTokenByUserID, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteExpiredTokens = `-- name: DeleteExpiredTokens :exec
|
||||
DELETE FROM auth_token WHERE expires_at <= NOW()
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteExpiredTokens(ctx context.Context) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteExpiredTokens)
|
||||
return err
|
||||
}
|
||||
|
||||
const getAuthTokenByID = `-- name: GetAuthTokenByID :one
|
||||
SELECT token_id, user_id, created_at, expires_at FROM auth_token WHERE token_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetAuthTokenByID(ctx context.Context, tokenID uuid.UUID) (AuthToken, error) {
|
||||
row := q.db.QueryRowContext(ctx, getAuthTokenByID, tokenID)
|
||||
var i AuthToken
|
||||
err := row.Scan(
|
||||
&i.TokenID,
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.ExpiresAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
181
internal/db/user_account.sql.go
Normal file
181
internal/db/user_account.sql.go
Normal file
@ -0,0 +1,181 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: user_account.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const createAccessToken = `-- name: CreateAccessToken :one
|
||||
INSERT INTO access_token (token, user_id, expires_at, created_at) VALUES ($1, $2, $3, $4) RETURNING token, user_id, expires_at, created_at
|
||||
`
|
||||
|
||||
type CreateAccessTokenParams struct {
|
||||
Token string `json:"token"`
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateAccessToken(ctx context.Context, arg CreateAccessTokenParams) (AccessToken, error) {
|
||||
row := q.db.QueryRowContext(ctx, createAccessToken,
|
||||
arg.Token,
|
||||
arg.UserID,
|
||||
arg.ExpiresAt,
|
||||
arg.CreatedAt,
|
||||
)
|
||||
var i AccessToken
|
||||
err := row.Scan(
|
||||
&i.Token,
|
||||
&i.UserID,
|
||||
&i.ExpiresAt,
|
||||
&i.CreatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createUserAccount = `-- name: CreateUserAccount :one
|
||||
INSERT INTO user_account (created_at, fullname, username, email, password_hash) VALUES ($1, $2, $3, $4, $5) RETURNING user_id, created_at, fullname, username, email, password_hash, avatar_url
|
||||
`
|
||||
|
||||
type CreateUserAccountParams struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Fullname string `json:"fullname"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
PasswordHash string `json:"password_hash"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateUserAccount(ctx context.Context, arg CreateUserAccountParams) (UserAccount, error) {
|
||||
row := q.db.QueryRowContext(ctx, createUserAccount,
|
||||
arg.CreatedAt,
|
||||
arg.Fullname,
|
||||
arg.Username,
|
||||
arg.Email,
|
||||
arg.PasswordHash,
|
||||
)
|
||||
var i UserAccount
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Fullname,
|
||||
&i.Username,
|
||||
&i.Email,
|
||||
&i.PasswordHash,
|
||||
&i.AvatarUrl,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteAccessToken = `-- name: DeleteAccessToken :exec
|
||||
DELETE FROM access_token WHERE token = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteAccessToken(ctx context.Context, token string) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteAccessToken, token)
|
||||
return err
|
||||
}
|
||||
|
||||
const getAccessToken = `-- name: GetAccessToken :one
|
||||
SELECT token, user_id, expires_at, created_at FROM access_token WHERE token = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetAccessToken(ctx context.Context, token string) (AccessToken, error) {
|
||||
row := q.db.QueryRowContext(ctx, getAccessToken, token)
|
||||
var i AccessToken
|
||||
err := row.Scan(
|
||||
&i.Token,
|
||||
&i.UserID,
|
||||
&i.ExpiresAt,
|
||||
&i.CreatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getUserAccountByID = `-- name: GetUserAccountByID :one
|
||||
SELECT user_id, created_at, fullname, username, email, password_hash, avatar_url FROM user_account WHERE user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserAccountByID(ctx context.Context, userID uuid.UUID) (UserAccount, error) {
|
||||
row := q.db.QueryRowContext(ctx, getUserAccountByID, userID)
|
||||
var i UserAccount
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Fullname,
|
||||
&i.Username,
|
||||
&i.Email,
|
||||
&i.PasswordHash,
|
||||
&i.AvatarUrl,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getUserAccountByUsername = `-- name: GetUserAccountByUsername :one
|
||||
SELECT user_id, created_at, fullname, username, email, password_hash, avatar_url FROM user_account WHERE username = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserAccountByUsername(ctx context.Context, username string) (UserAccount, error) {
|
||||
row := q.db.QueryRowContext(ctx, getUserAccountByUsername, username)
|
||||
var i UserAccount
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Fullname,
|
||||
&i.Username,
|
||||
&i.Email,
|
||||
&i.PasswordHash,
|
||||
&i.AvatarUrl,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getUserAccounts = `-- name: GetUserAccounts :many
|
||||
SELECT user_id, created_at, fullname, username, email, password_hash, avatar_url FROM user_account
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserAccounts(ctx context.Context) ([]UserAccount, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getUserAccounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []UserAccount
|
||||
for rows.Next() {
|
||||
var i UserAccount
|
||||
if err := rows.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Fullname,
|
||||
&i.Username,
|
||||
&i.Email,
|
||||
&i.PasswordHash,
|
||||
&i.AvatarUrl,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const hasAnyUserAccount = `-- name: HasAnyUserAccount :one
|
||||
SELECT EXISTS (SELECT user_id, created_at, fullname, username, email, password_hash, avatar_url FROM user_account LIMIT 1)
|
||||
`
|
||||
|
||||
func (q *Queries) HasAnyUserAccount(ctx context.Context) (bool, error) {
|
||||
row := q.db.QueryRowContext(ctx, hasAnyUserAccount)
|
||||
var exists bool
|
||||
err := row.Scan(&exists)
|
||||
return exists, err
|
||||
}
|
@ -1,646 +0,0 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// source: user_accounts.sql
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const createConfirmToken = `-- name: CreateConfirmToken :one
|
||||
INSERT INTO user_account_confirm_token (email) VALUES ($1) RETURNING confirm_token_id, email
|
||||
`
|
||||
|
||||
func (q *Queries) CreateConfirmToken(ctx context.Context, email string) (UserAccountConfirmToken, error) {
|
||||
row := q.db.QueryRowContext(ctx, createConfirmToken, email)
|
||||
var i UserAccountConfirmToken
|
||||
err := row.Scan(&i.ConfirmTokenID, &i.Email)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createInvitedProjectMember = `-- name: CreateInvitedProjectMember :one
|
||||
INSERT INTO project_member_invited (project_id, user_account_invited_id) VALUES ($1, $2)
|
||||
RETURNING project_member_invited_id, project_id, user_account_invited_id
|
||||
`
|
||||
|
||||
type CreateInvitedProjectMemberParams struct {
|
||||
ProjectID uuid.UUID `json:"project_id"`
|
||||
UserAccountInvitedID uuid.UUID `json:"user_account_invited_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateInvitedProjectMember(ctx context.Context, arg CreateInvitedProjectMemberParams) (ProjectMemberInvited, error) {
|
||||
row := q.db.QueryRowContext(ctx, createInvitedProjectMember, arg.ProjectID, arg.UserAccountInvitedID)
|
||||
var i ProjectMemberInvited
|
||||
err := row.Scan(&i.ProjectMemberInvitedID, &i.ProjectID, &i.UserAccountInvitedID)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createInvitedUser = `-- name: CreateInvitedUser :one
|
||||
INSERT INTO user_account_invited (email) VALUES ($1) RETURNING user_account_invited_id, email, invited_on, has_joined
|
||||
`
|
||||
|
||||
func (q *Queries) CreateInvitedUser(ctx context.Context, email string) (UserAccountInvited, error) {
|
||||
row := q.db.QueryRowContext(ctx, createInvitedUser, email)
|
||||
var i UserAccountInvited
|
||||
err := row.Scan(
|
||||
&i.UserAccountInvitedID,
|
||||
&i.Email,
|
||||
&i.InvitedOn,
|
||||
&i.HasJoined,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createUserAccount = `-- name: CreateUserAccount :one
|
||||
INSERT INTO user_account(full_name, initials, email, username, created_at, password_hash, role_code, active)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active
|
||||
`
|
||||
|
||||
type CreateUserAccountParams struct {
|
||||
FullName string `json:"full_name"`
|
||||
Initials string `json:"initials"`
|
||||
Email string `json:"email"`
|
||||
Username string `json:"username"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
PasswordHash string `json:"password_hash"`
|
||||
RoleCode string `json:"role_code"`
|
||||
Active bool `json:"active"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateUserAccount(ctx context.Context, arg CreateUserAccountParams) (UserAccount, error) {
|
||||
row := q.db.QueryRowContext(ctx, createUserAccount,
|
||||
arg.FullName,
|
||||
arg.Initials,
|
||||
arg.Email,
|
||||
arg.Username,
|
||||
arg.CreatedAt,
|
||||
arg.PasswordHash,
|
||||
arg.RoleCode,
|
||||
arg.Active,
|
||||
)
|
||||
var i UserAccount
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.PasswordHash,
|
||||
&i.ProfileBgColor,
|
||||
&i.FullName,
|
||||
&i.Initials,
|
||||
&i.ProfileAvatarUrl,
|
||||
&i.RoleCode,
|
||||
&i.Bio,
|
||||
&i.Active,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteConfirmTokenForEmail = `-- name: DeleteConfirmTokenForEmail :exec
|
||||
DELETE FROM user_account_confirm_token WHERE email = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteConfirmTokenForEmail(ctx context.Context, email string) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteConfirmTokenForEmail, email)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteInvitedUserAccount = `-- name: DeleteInvitedUserAccount :one
|
||||
DELETE FROM user_account_invited WHERE user_account_invited_id = $1 RETURNING user_account_invited_id, email, invited_on, has_joined
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteInvitedUserAccount(ctx context.Context, userAccountInvitedID uuid.UUID) (UserAccountInvited, error) {
|
||||
row := q.db.QueryRowContext(ctx, deleteInvitedUserAccount, userAccountInvitedID)
|
||||
var i UserAccountInvited
|
||||
err := row.Scan(
|
||||
&i.UserAccountInvitedID,
|
||||
&i.Email,
|
||||
&i.InvitedOn,
|
||||
&i.HasJoined,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const deleteProjectMemberInvitedForEmail = `-- name: DeleteProjectMemberInvitedForEmail :exec
|
||||
DELETE FROM project_member_invited WHERE project_member_invited_id IN (
|
||||
SELECT pmi.project_member_invited_id FROM user_account_invited AS uai
|
||||
INNER JOIN project_member_invited AS pmi
|
||||
ON pmi.user_account_invited_id = uai.user_account_invited_id
|
||||
WHERE uai.email = $1
|
||||
)
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteProjectMemberInvitedForEmail(ctx context.Context, email string) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteProjectMemberInvitedForEmail, email)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteUserAccountByID = `-- name: DeleteUserAccountByID :exec
|
||||
DELETE FROM user_account WHERE user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteUserAccountByID(ctx context.Context, userID uuid.UUID) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteUserAccountByID, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteUserAccountInvitedForEmail = `-- name: DeleteUserAccountInvitedForEmail :exec
|
||||
DELETE FROM user_account_invited WHERE email = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteUserAccountInvitedForEmail(ctx context.Context, email string) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteUserAccountInvitedForEmail, email)
|
||||
return err
|
||||
}
|
||||
|
||||
const doesUserExist = `-- name: DoesUserExist :one
|
||||
SELECT EXISTS(SELECT 1 FROM user_account WHERE email = $1 OR username = $2)
|
||||
`
|
||||
|
||||
type DoesUserExistParams struct {
|
||||
Email string `json:"email"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
func (q *Queries) DoesUserExist(ctx context.Context, arg DoesUserExistParams) (bool, error) {
|
||||
row := q.db.QueryRowContext(ctx, doesUserExist, arg.Email, arg.Username)
|
||||
var exists bool
|
||||
err := row.Scan(&exists)
|
||||
return exists, err
|
||||
}
|
||||
|
||||
const getAllUserAccounts = `-- name: GetAllUserAccounts :many
|
||||
SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active FROM user_account WHERE username != 'system'
|
||||
`
|
||||
|
||||
func (q *Queries) GetAllUserAccounts(ctx context.Context) ([]UserAccount, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getAllUserAccounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []UserAccount
|
||||
for rows.Next() {
|
||||
var i UserAccount
|
||||
if err := rows.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.PasswordHash,
|
||||
&i.ProfileBgColor,
|
||||
&i.FullName,
|
||||
&i.Initials,
|
||||
&i.ProfileAvatarUrl,
|
||||
&i.RoleCode,
|
||||
&i.Bio,
|
||||
&i.Active,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getConfirmTokenByEmail = `-- name: GetConfirmTokenByEmail :one
|
||||
SELECT confirm_token_id, email FROM user_account_confirm_token WHERE email = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetConfirmTokenByEmail(ctx context.Context, email string) (UserAccountConfirmToken, error) {
|
||||
row := q.db.QueryRowContext(ctx, getConfirmTokenByEmail, email)
|
||||
var i UserAccountConfirmToken
|
||||
err := row.Scan(&i.ConfirmTokenID, &i.Email)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getConfirmTokenByID = `-- name: GetConfirmTokenByID :one
|
||||
SELECT confirm_token_id, email FROM user_account_confirm_token WHERE confirm_token_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetConfirmTokenByID(ctx context.Context, confirmTokenID uuid.UUID) (UserAccountConfirmToken, error) {
|
||||
row := q.db.QueryRowContext(ctx, getConfirmTokenByID, confirmTokenID)
|
||||
var i UserAccountConfirmToken
|
||||
err := row.Scan(&i.ConfirmTokenID, &i.Email)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getInvitedUserAccounts = `-- name: GetInvitedUserAccounts :many
|
||||
SELECT user_account_invited_id, email, invited_on, has_joined FROM user_account_invited
|
||||
`
|
||||
|
||||
func (q *Queries) GetInvitedUserAccounts(ctx context.Context) ([]UserAccountInvited, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getInvitedUserAccounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []UserAccountInvited
|
||||
for rows.Next() {
|
||||
var i UserAccountInvited
|
||||
if err := rows.Scan(
|
||||
&i.UserAccountInvitedID,
|
||||
&i.Email,
|
||||
&i.InvitedOn,
|
||||
&i.HasJoined,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getInvitedUserByEmail = `-- name: GetInvitedUserByEmail :one
|
||||
SELECT user_account_invited_id, email, invited_on, has_joined FROM user_account_invited WHERE email = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetInvitedUserByEmail(ctx context.Context, email string) (UserAccountInvited, error) {
|
||||
row := q.db.QueryRowContext(ctx, getInvitedUserByEmail, email)
|
||||
var i UserAccountInvited
|
||||
err := row.Scan(
|
||||
&i.UserAccountInvitedID,
|
||||
&i.Email,
|
||||
&i.InvitedOn,
|
||||
&i.HasJoined,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getMemberData = `-- name: GetMemberData :many
|
||||
SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active FROM user_account
|
||||
WHERE username != 'system'
|
||||
AND user_id NOT IN (SELECT user_id FROM project_member WHERE project_id = $1)
|
||||
`
|
||||
|
||||
func (q *Queries) GetMemberData(ctx context.Context, projectID uuid.UUID) ([]UserAccount, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getMemberData, projectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []UserAccount
|
||||
for rows.Next() {
|
||||
var i UserAccount
|
||||
if err := rows.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.PasswordHash,
|
||||
&i.ProfileBgColor,
|
||||
&i.FullName,
|
||||
&i.Initials,
|
||||
&i.ProfileAvatarUrl,
|
||||
&i.RoleCode,
|
||||
&i.Bio,
|
||||
&i.Active,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getProjectsForInvitedMember = `-- name: GetProjectsForInvitedMember :many
|
||||
SELECT project_id FROM user_account_invited AS uai
|
||||
INNER JOIN project_member_invited AS pmi
|
||||
ON pmi.user_account_invited_id = uai.user_account_invited_id
|
||||
WHERE uai.email = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetProjectsForInvitedMember(ctx context.Context, email string) ([]uuid.UUID, error) {
|
||||
rows, err := q.db.QueryContext(ctx, getProjectsForInvitedMember, email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []uuid.UUID
|
||||
for rows.Next() {
|
||||
var project_id uuid.UUID
|
||||
if err := rows.Scan(&project_id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, project_id)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getRoleForUserID = `-- name: GetRoleForUserID :one
|
||||
SELECT username, role.code, role.name FROM user_account
|
||||
INNER JOIN role ON role.code = user_account.role_code
|
||||
WHERE user_id = $1
|
||||
`
|
||||
|
||||
type GetRoleForUserIDRow struct {
|
||||
Username string `json:"username"`
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetRoleForUserID(ctx context.Context, userID uuid.UUID) (GetRoleForUserIDRow, error) {
|
||||
row := q.db.QueryRowContext(ctx, getRoleForUserID, userID)
|
||||
var i GetRoleForUserIDRow
|
||||
err := row.Scan(&i.Username, &i.Code, &i.Name)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getUserAccountByEmail = `-- name: GetUserAccountByEmail :one
|
||||
SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active FROM user_account WHERE email = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserAccountByEmail(ctx context.Context, email string) (UserAccount, error) {
|
||||
row := q.db.QueryRowContext(ctx, getUserAccountByEmail, email)
|
||||
var i UserAccount
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.PasswordHash,
|
||||
&i.ProfileBgColor,
|
||||
&i.FullName,
|
||||
&i.Initials,
|
||||
&i.ProfileAvatarUrl,
|
||||
&i.RoleCode,
|
||||
&i.Bio,
|
||||
&i.Active,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getUserAccountByID = `-- name: GetUserAccountByID :one
|
||||
SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active FROM user_account WHERE user_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserAccountByID(ctx context.Context, userID uuid.UUID) (UserAccount, error) {
|
||||
row := q.db.QueryRowContext(ctx, getUserAccountByID, userID)
|
||||
var i UserAccount
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.PasswordHash,
|
||||
&i.ProfileBgColor,
|
||||
&i.FullName,
|
||||
&i.Initials,
|
||||
&i.ProfileAvatarUrl,
|
||||
&i.RoleCode,
|
||||
&i.Bio,
|
||||
&i.Active,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getUserAccountByUsername = `-- name: GetUserAccountByUsername :one
|
||||
SELECT user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active FROM user_account WHERE username = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetUserAccountByUsername(ctx context.Context, username string) (UserAccount, error) {
|
||||
row := q.db.QueryRowContext(ctx, getUserAccountByUsername, username)
|
||||
var i UserAccount
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.PasswordHash,
|
||||
&i.ProfileBgColor,
|
||||
&i.FullName,
|
||||
&i.Initials,
|
||||
&i.ProfileAvatarUrl,
|
||||
&i.RoleCode,
|
||||
&i.Bio,
|
||||
&i.Active,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const hasActiveUser = `-- name: HasActiveUser :one
|
||||
SELECT EXISTS(SELECT 1 FROM user_account WHERE username != 'system' AND active = true)
|
||||
`
|
||||
|
||||
func (q *Queries) HasActiveUser(ctx context.Context) (bool, error) {
|
||||
row := q.db.QueryRowContext(ctx, hasActiveUser)
|
||||
var exists bool
|
||||
err := row.Scan(&exists)
|
||||
return exists, err
|
||||
}
|
||||
|
||||
const hasAnyUser = `-- name: HasAnyUser :one
|
||||
SELECT EXISTS(SELECT 1 FROM user_account WHERE username != 'system')
|
||||
`
|
||||
|
||||
func (q *Queries) HasAnyUser(ctx context.Context) (bool, error) {
|
||||
row := q.db.QueryRowContext(ctx, hasAnyUser)
|
||||
var exists bool
|
||||
err := row.Scan(&exists)
|
||||
return exists, err
|
||||
}
|
||||
|
||||
const setFirstUserActive = `-- name: SetFirstUserActive :one
|
||||
UPDATE user_account SET active = true WHERE user_id = (
|
||||
SELECT user_id from user_account WHERE active = false LIMIT 1
|
||||
) RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active
|
||||
`
|
||||
|
||||
func (q *Queries) SetFirstUserActive(ctx context.Context) (UserAccount, error) {
|
||||
row := q.db.QueryRowContext(ctx, setFirstUserActive)
|
||||
var i UserAccount
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.PasswordHash,
|
||||
&i.ProfileBgColor,
|
||||
&i.FullName,
|
||||
&i.Initials,
|
||||
&i.ProfileAvatarUrl,
|
||||
&i.RoleCode,
|
||||
&i.Bio,
|
||||
&i.Active,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const setUserActiveByEmail = `-- name: SetUserActiveByEmail :one
|
||||
UPDATE user_account SET active = true WHERE email = $1 RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active
|
||||
`
|
||||
|
||||
func (q *Queries) SetUserActiveByEmail(ctx context.Context, email string) (UserAccount, error) {
|
||||
row := q.db.QueryRowContext(ctx, setUserActiveByEmail, email)
|
||||
var i UserAccount
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.PasswordHash,
|
||||
&i.ProfileBgColor,
|
||||
&i.FullName,
|
||||
&i.Initials,
|
||||
&i.ProfileAvatarUrl,
|
||||
&i.RoleCode,
|
||||
&i.Bio,
|
||||
&i.Active,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const setUserPassword = `-- name: SetUserPassword :one
|
||||
UPDATE user_account SET password_hash = $2 WHERE user_id = $1 RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active
|
||||
`
|
||||
|
||||
type SetUserPasswordParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
PasswordHash string `json:"password_hash"`
|
||||
}
|
||||
|
||||
func (q *Queries) SetUserPassword(ctx context.Context, arg SetUserPasswordParams) (UserAccount, error) {
|
||||
row := q.db.QueryRowContext(ctx, setUserPassword, arg.UserID, arg.PasswordHash)
|
||||
var i UserAccount
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.PasswordHash,
|
||||
&i.ProfileBgColor,
|
||||
&i.FullName,
|
||||
&i.Initials,
|
||||
&i.ProfileAvatarUrl,
|
||||
&i.RoleCode,
|
||||
&i.Bio,
|
||||
&i.Active,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateUserAccountInfo = `-- name: UpdateUserAccountInfo :one
|
||||
UPDATE user_account SET bio = $2, full_name = $3, initials = $4, email = $5
|
||||
WHERE user_id = $1 RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active
|
||||
`
|
||||
|
||||
type UpdateUserAccountInfoParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
Bio string `json:"bio"`
|
||||
FullName string `json:"full_name"`
|
||||
Initials string `json:"initials"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateUserAccountInfo(ctx context.Context, arg UpdateUserAccountInfoParams) (UserAccount, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateUserAccountInfo,
|
||||
arg.UserID,
|
||||
arg.Bio,
|
||||
arg.FullName,
|
||||
arg.Initials,
|
||||
arg.Email,
|
||||
)
|
||||
var i UserAccount
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.PasswordHash,
|
||||
&i.ProfileBgColor,
|
||||
&i.FullName,
|
||||
&i.Initials,
|
||||
&i.ProfileAvatarUrl,
|
||||
&i.RoleCode,
|
||||
&i.Bio,
|
||||
&i.Active,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateUserAccountProfileAvatarURL = `-- name: UpdateUserAccountProfileAvatarURL :one
|
||||
UPDATE user_account SET profile_avatar_url = $2 WHERE user_id = $1
|
||||
RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active
|
||||
`
|
||||
|
||||
type UpdateUserAccountProfileAvatarURLParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
ProfileAvatarUrl sql.NullString `json:"profile_avatar_url"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateUserAccountProfileAvatarURL(ctx context.Context, arg UpdateUserAccountProfileAvatarURLParams) (UserAccount, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateUserAccountProfileAvatarURL, arg.UserID, arg.ProfileAvatarUrl)
|
||||
var i UserAccount
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.PasswordHash,
|
||||
&i.ProfileBgColor,
|
||||
&i.FullName,
|
||||
&i.Initials,
|
||||
&i.ProfileAvatarUrl,
|
||||
&i.RoleCode,
|
||||
&i.Bio,
|
||||
&i.Active,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateUserRole = `-- name: UpdateUserRole :one
|
||||
UPDATE user_account SET role_code = $2 WHERE user_id = $1 RETURNING user_id, created_at, email, username, password_hash, profile_bg_color, full_name, initials, profile_avatar_url, role_code, bio, active
|
||||
`
|
||||
|
||||
type UpdateUserRoleParams struct {
|
||||
UserID uuid.UUID `json:"user_id"`
|
||||
RoleCode string `json:"role_code"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateUserRole(ctx context.Context, arg UpdateUserRoleParams) (UserAccount, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateUserRole, arg.UserID, arg.RoleCode)
|
||||
var i UserAccount
|
||||
err := row.Scan(
|
||||
&i.UserID,
|
||||
&i.CreatedAt,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.PasswordHash,
|
||||
&i.ProfileBgColor,
|
||||
&i.FullName,
|
||||
&i.Initials,
|
||||
&i.ProfileAvatarUrl,
|
||||
&i.RoleCode,
|
||||
&i.Bio,
|
||||
&i.Active,
|
||||
)
|
||||
return i, err
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,285 +0,0 @@
|
||||
package graph
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/graphql/handler"
|
||||
"github.com/99designs/gqlgen/graphql/handler/extension"
|
||||
"github.com/99designs/gqlgen/graphql/handler/lru"
|
||||
"github.com/99designs/gqlgen/graphql/handler/transport"
|
||||
"github.com/99designs/gqlgen/graphql/playground"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/jordanknott/taskcafe/internal/jobs"
|
||||
"github.com/jordanknott/taskcafe/internal/logger"
|
||||
"github.com/jordanknott/taskcafe/internal/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
type NotificationObservers struct {
|
||||
Mu sync.Mutex
|
||||
Subscribers map[string]map[string]chan *Notified
|
||||
}
|
||||
|
||||
// NewHandler returns a new graphql endpoint handler.
|
||||
func NewHandler(repo db.Repository, appConfig config.AppConfig, jobQueue jobs.JobQueue, redisClient *redis.Client) http.Handler {
|
||||
resolver := &Resolver{
|
||||
Repository: repo,
|
||||
Redis: redisClient,
|
||||
AppConfig: appConfig,
|
||||
Job: jobQueue,
|
||||
Notifications: &NotificationObservers{
|
||||
Mu: sync.Mutex{},
|
||||
Subscribers: make(map[string]map[string]chan *Notified),
|
||||
},
|
||||
}
|
||||
resolver.SubscribeRedis()
|
||||
c := Config{
|
||||
Resolvers: resolver,
|
||||
}
|
||||
c.Directives.HasRole = func(ctx context.Context, obj interface{}, next graphql.Resolver, roles []RoleLevel, level ActionLevel, typeArg ObjectType) (interface{}, error) {
|
||||
userID, ok := GetUser(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New("user must be logged in")
|
||||
}
|
||||
user, err := repo.GetUserAccountByID(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user.RoleCode == "admin" {
|
||||
return next(ctx)
|
||||
} else if level == ActionLevelOrg {
|
||||
return nil, errors.New("must be an org admin")
|
||||
}
|
||||
|
||||
var subjectID uuid.UUID
|
||||
in := graphql.GetFieldContext(ctx).Args["input"]
|
||||
val := reflect.ValueOf(in) // could be any underlying type
|
||||
if val.Kind() == reflect.Ptr {
|
||||
val = reflect.Indirect(val)
|
||||
}
|
||||
var fieldName string
|
||||
switch typeArg {
|
||||
case ObjectTypeTeam:
|
||||
fieldName = "TeamID"
|
||||
case ObjectTypeTask:
|
||||
fieldName = "TaskID"
|
||||
case ObjectTypeTaskGroup:
|
||||
fieldName = "TaskGroupID"
|
||||
case ObjectTypeTaskChecklist:
|
||||
fieldName = "TaskChecklistID"
|
||||
case ObjectTypeTaskChecklistItem:
|
||||
fieldName = "TaskChecklistItemID"
|
||||
default:
|
||||
fieldName = "ProjectID"
|
||||
}
|
||||
logger.New(ctx).WithFields(log.Fields{"typeArg": typeArg, "fieldName": fieldName}).Info("getting field by name")
|
||||
subjectField := val.FieldByName(fieldName)
|
||||
if !subjectField.IsValid() {
|
||||
logger.New(ctx).Error("subject field name does not exist on input type")
|
||||
return nil, errors.New("subject field name does not exist on input type")
|
||||
}
|
||||
if fieldName == "TeamID" && subjectField.IsNil() {
|
||||
// Is a personal project, no check
|
||||
// TODO: add config setting to disable personal projects
|
||||
return next(ctx)
|
||||
}
|
||||
subjectID, ok = subjectField.Interface().(uuid.UUID)
|
||||
if !ok {
|
||||
logger.New(ctx).Error("error while casting subject UUID")
|
||||
return nil, errors.New("error while casting subject uuid")
|
||||
}
|
||||
|
||||
if level == ActionLevelProject {
|
||||
logger.New(ctx).WithFields(log.Fields{"subjectID": subjectID}).Info("fetching subject ID by typeArg")
|
||||
if typeArg == ObjectTypeTask {
|
||||
subjectID, err = repo.GetProjectIDForTask(ctx, subjectID)
|
||||
}
|
||||
if typeArg == ObjectTypeTaskGroup {
|
||||
subjectID, err = repo.GetProjectIDForTaskGroup(ctx, subjectID)
|
||||
}
|
||||
if typeArg == ObjectTypeTaskChecklist {
|
||||
subjectID, err = repo.GetProjectIDForTaskChecklist(ctx, subjectID)
|
||||
}
|
||||
if typeArg == ObjectTypeTaskChecklistItem {
|
||||
subjectID, err = repo.GetProjectIDForTaskChecklistItem(ctx, subjectID)
|
||||
}
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("error while getting subject ID")
|
||||
return nil, err
|
||||
}
|
||||
projectRoles, err := GetProjectRoles(ctx, repo, subjectID)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, &gqlerror.Error{
|
||||
Message: "not authorized",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "401",
|
||||
},
|
||||
}
|
||||
}
|
||||
logger.New(ctx).WithError(err).Error("error while getting project roles")
|
||||
return nil, err
|
||||
}
|
||||
for _, validRole := range roles {
|
||||
logger.New(ctx).WithFields(log.Fields{"validRole": validRole}).Info("checking role")
|
||||
if CompareRoleLevel(projectRoles.TeamRole, validRole) || CompareRoleLevel(projectRoles.ProjectRole, validRole) {
|
||||
logger.New(ctx).WithFields(log.Fields{"teamRole": projectRoles.TeamRole, "projectRole": projectRoles.ProjectRole}).Info("is team or project role")
|
||||
return next(ctx)
|
||||
}
|
||||
}
|
||||
return nil, &gqlerror.Error{
|
||||
Message: "not authorized",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "401",
|
||||
},
|
||||
}
|
||||
} else if level == ActionLevelTeam {
|
||||
role, err := repo.GetTeamRoleForUserID(ctx, db.GetTeamRoleForUserIDParams{UserID: userID, TeamID: subjectID})
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("error while getting team roles for user ID")
|
||||
return nil, err
|
||||
}
|
||||
for _, validRole := range roles {
|
||||
if CompareRoleLevel(role.RoleCode, validRole) || CompareRoleLevel(role.RoleCode, validRole) {
|
||||
return next(ctx)
|
||||
}
|
||||
}
|
||||
return nil, &gqlerror.Error{
|
||||
Message: "not authorized",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "401",
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
return nil, &gqlerror.Error{
|
||||
Message: "bad path",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "500",
|
||||
},
|
||||
}
|
||||
}
|
||||
srv := handler.New(NewExecutableSchema(c))
|
||||
srv.AddTransport(transport.Websocket{
|
||||
KeepAlivePingInterval: 10 * time.Second,
|
||||
})
|
||||
srv.AddTransport(transport.Options{})
|
||||
srv.AddTransport(transport.GET{})
|
||||
srv.AddTransport(transport.POST{})
|
||||
srv.AddTransport(transport.MultipartForm{})
|
||||
|
||||
srv.SetQueryCache(lru.New(1000))
|
||||
|
||||
srv.Use(extension.AutomaticPersistedQuery{
|
||||
Cache: lru.New(100),
|
||||
})
|
||||
if isProd := os.Getenv("PRODUCTION") == "true"; isProd {
|
||||
srv.Use(extension.FixedComplexityLimit(10))
|
||||
} else {
|
||||
srv.Use(extension.Introspection{})
|
||||
}
|
||||
return srv
|
||||
}
|
||||
|
||||
// NewPlaygroundHandler returns a new GraphQL Playground handler.
|
||||
func NewPlaygroundHandler(endpoint string) http.Handler {
|
||||
return playground.Handler("GraphQL Playground", endpoint)
|
||||
}
|
||||
|
||||
// GetUserID retrieves the UserID out of a context
|
||||
func GetUserID(ctx context.Context) (uuid.UUID, bool) {
|
||||
userID, ok := ctx.Value(utils.UserIDKey).(uuid.UUID)
|
||||
return userID, ok
|
||||
}
|
||||
|
||||
// GetUser retrieves both the user id & user role out of a context
|
||||
func GetUser(ctx context.Context) (uuid.UUID, bool) {
|
||||
userID, userOK := GetUserID(ctx)
|
||||
return userID, userOK
|
||||
}
|
||||
|
||||
// GetProjectRoles retrieves the team & project role for the given project ID
|
||||
func GetProjectRoles(ctx context.Context, r db.Repository, projectID uuid.UUID) (db.GetUserRolesForProjectRow, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return db.GetUserRolesForProjectRow{}, errors.New("user ID is not found")
|
||||
}
|
||||
return r.GetUserRolesForProject(ctx, db.GetUserRolesForProjectParams{UserID: userID, ProjectID: projectID})
|
||||
}
|
||||
|
||||
// CompareRoleLevel compares a string against a role level
|
||||
func CompareRoleLevel(a string, b RoleLevel) bool {
|
||||
if strings.ToLower(a) == strings.ToLower(b.String()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ConvertToRoleCode converts a role code string to a RoleCode type
|
||||
func ConvertToRoleCode(r string) RoleCode {
|
||||
if r == RoleCodeAdmin.String() {
|
||||
return RoleCodeAdmin
|
||||
}
|
||||
if r == RoleCodeMember.String() {
|
||||
return RoleCodeMember
|
||||
}
|
||||
return RoleCodeObserver
|
||||
}
|
||||
|
||||
type MemberType string
|
||||
|
||||
const (
|
||||
MemberTypeInvited MemberType = "INVITED"
|
||||
MemberTypeJoined MemberType = "JOINED"
|
||||
)
|
||||
|
||||
type MasterEntry struct {
|
||||
MemberType MemberType
|
||||
ID uuid.UUID
|
||||
}
|
||||
|
||||
const (
|
||||
TASK_ADDED_TO_TASK_GROUP int32 = 1
|
||||
TASK_MOVED_TO_TASK_GROUP int32 = 2
|
||||
TASK_MARK_COMPLETE int32 = 3
|
||||
TASK_MARK_INCOMPLETE int32 = 4
|
||||
TASK_DUE_DATE_CHANGED int32 = 5
|
||||
TASK_DUE_DATE_ADDED int32 = 6
|
||||
TASK_DUE_DATE_REMOVED int32 = 7
|
||||
TASK_CHECKLIST_CHANGED int32 = 8
|
||||
TASK_CHECKLIST_ADDED int32 = 9
|
||||
TASK_CHECKLIST_REMOVED int32 = 10
|
||||
)
|
||||
|
||||
func NotAuthorized() error {
|
||||
return &gqlerror.Error{
|
||||
Message: "Not authorized",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "UNAUTHENTICATED",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func IsProjectPublic(ctx context.Context, repo db.Repository, projectID uuid.UUID) (bool, error) {
|
||||
publicOn, err := repo.GetPublicOn(ctx, projectID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !publicOn.Valid {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
package graph
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// GetOwnedList todo: remove this
|
||||
func GetOwnedList(ctx context.Context, r db.Repository, user db.UserAccount) (*OwnedList, error) {
|
||||
return &OwnedList{}, nil
|
||||
}
|
||||
|
||||
type CreateNotificationParams struct {
|
||||
NotifiedList []uuid.UUID
|
||||
ActionType ActionType
|
||||
CausedBy uuid.UUID
|
||||
Data map[string]string
|
||||
}
|
||||
|
||||
func (r *Resolver) CreateNotification(ctx context.Context, data CreateNotificationParams) error {
|
||||
now := time.Now().UTC()
|
||||
raw, err := json.Marshal(NotifiedData{Data: data.Data})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while marshal json data for notification")
|
||||
return err
|
||||
}
|
||||
log.WithField("ActionType", data.ActionType).Info("creating notification object")
|
||||
n, err := r.Repository.CreateNotification(ctx, db.CreateNotificationParams{
|
||||
CausedBy: data.CausedBy,
|
||||
ActionType: data.ActionType.String(),
|
||||
CreatedOn: now,
|
||||
Data: json.RawMessage(raw),
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while creating notification")
|
||||
return err
|
||||
}
|
||||
for _, nn := range data.NotifiedList {
|
||||
log.WithFields(log.Fields{"UserID": nn, "NotificationID": n.NotificationID}).Info("creating notification notified object")
|
||||
notified, err := r.Repository.CreateNotificationNotifed(ctx, db.CreateNotificationNotifedParams{
|
||||
UserID: nn,
|
||||
NotificationID: n.NotificationID,
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while creating notification notified object")
|
||||
return err
|
||||
}
|
||||
for ouid, observers := range r.Notifications.Subscribers {
|
||||
log.WithField("ouid", ouid).Info("checking user subscribers")
|
||||
for oid, ochan := range observers {
|
||||
log.WithField("ouid", ouid).WithField("oid", oid).Info("checking user subscriber")
|
||||
ochan <- &Notified{
|
||||
ID: notified.NotifiedID,
|
||||
Read: notified.Read,
|
||||
ReadAt: ¬ified.ReadAt.Time,
|
||||
Notification: &n,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMemberList returns a list of projects the user is a member of
|
||||
func GetMemberList(ctx context.Context, r db.Repository, user db.UserAccount) (*MemberList, error) {
|
||||
projectMemberIDs, err := r.GetMemberProjectIDsForUserID(ctx, user.UserID)
|
||||
if err != sql.ErrNoRows && err != nil {
|
||||
return &MemberList{}, err
|
||||
}
|
||||
var projects []db.Project
|
||||
for _, projectID := range projectMemberIDs {
|
||||
project, err := r.GetProjectByID(ctx, projectID)
|
||||
if err != nil {
|
||||
return &MemberList{}, err
|
||||
}
|
||||
projects = append(projects, project)
|
||||
}
|
||||
teamMemberIDs, err := r.GetMemberTeamIDsForUserID(ctx, user.UserID)
|
||||
if err != sql.ErrNoRows && err != nil {
|
||||
return &MemberList{}, err
|
||||
}
|
||||
var teams []db.Team
|
||||
for _, teamID := range teamMemberIDs {
|
||||
team, err := r.GetTeamByID(ctx, teamID)
|
||||
if err != nil {
|
||||
return &MemberList{}, err
|
||||
}
|
||||
teams = append(teams, team)
|
||||
}
|
||||
|
||||
return &MemberList{Teams: teams, Projects: projects}, nil
|
||||
}
|
||||
|
||||
type ActivityData struct {
|
||||
Data map[string]string
|
||||
}
|
||||
|
||||
type NotifiedData struct {
|
||||
Data map[string]string
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,384 +0,0 @@
|
||||
package graph
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/jordanknott/taskcafe/internal/logger"
|
||||
"github.com/jordanknott/taskcafe/internal/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (r *mutationResolver) NotificationToggleRead(ctx context.Context, input NotificationToggleReadInput) (*Notified, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return &Notified{}, errors.New("unknown user ID")
|
||||
}
|
||||
notified, err := r.Repository.GetNotifiedByID(ctx, input.NotifiedID)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while getting notified by ID")
|
||||
return &Notified{}, err
|
||||
}
|
||||
readAt := time.Now().UTC()
|
||||
read := true
|
||||
if notified.Read {
|
||||
read = false
|
||||
err = r.Repository.MarkNotificationAsRead(ctx, db.MarkNotificationAsReadParams{
|
||||
UserID: userID,
|
||||
NotifiedID: input.NotifiedID,
|
||||
Read: false,
|
||||
ReadAt: sql.NullTime{
|
||||
Valid: false,
|
||||
Time: time.Time{},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
err = r.Repository.MarkNotificationAsRead(ctx, db.MarkNotificationAsReadParams{
|
||||
UserID: userID,
|
||||
Read: true,
|
||||
NotifiedID: input.NotifiedID,
|
||||
ReadAt: sql.NullTime{
|
||||
Valid: true,
|
||||
Time: readAt,
|
||||
},
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while marking notification as read")
|
||||
return &Notified{}, err
|
||||
}
|
||||
|
||||
return &Notified{
|
||||
ID: notified.NotifiedID,
|
||||
Read: read,
|
||||
ReadAt: &readAt,
|
||||
Notification: &db.Notification{
|
||||
NotificationID: notified.NotificationID,
|
||||
CausedBy: notified.CausedBy,
|
||||
ActionType: notified.ActionType,
|
||||
Data: notified.Data,
|
||||
CreatedOn: notified.CreatedOn,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) NotificationMarkAllRead(ctx context.Context) (*NotificationMarkAllAsReadResult, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return &NotificationMarkAllAsReadResult{}, errors.New("invalid user ID")
|
||||
}
|
||||
now := time.Now().UTC()
|
||||
err := r.Repository.MarkAllNotificationsRead(ctx, db.MarkAllNotificationsReadParams{UserID: userID, ReadAt: sql.NullTime{Valid: true, Time: now}})
|
||||
if err != nil {
|
||||
return &NotificationMarkAllAsReadResult{}, err
|
||||
}
|
||||
return &NotificationMarkAllAsReadResult{Success: false}, nil
|
||||
}
|
||||
|
||||
func (r *notificationResolver) ID(ctx context.Context, obj *db.Notification) (uuid.UUID, error) {
|
||||
return obj.NotificationID, nil
|
||||
}
|
||||
|
||||
func (r *notificationResolver) ActionType(ctx context.Context, obj *db.Notification) (ActionType, error) {
|
||||
actionType := ActionType(obj.ActionType)
|
||||
if !actionType.IsValid() {
|
||||
log.WithField("ActionType", obj.ActionType).Error("ActionType is invalid")
|
||||
return actionType, errors.New("ActionType is invalid")
|
||||
}
|
||||
return ActionType(obj.ActionType), nil // TODO
|
||||
}
|
||||
|
||||
func (r *notificationResolver) CausedBy(ctx context.Context, obj *db.Notification) (*NotificationCausedBy, error) {
|
||||
user, err := r.Repository.GetUserAccountByID(ctx, obj.CausedBy)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
log.WithError(err).Error("error while resolving Notification.CausedBy")
|
||||
return &NotificationCausedBy{}, err
|
||||
}
|
||||
return &NotificationCausedBy{
|
||||
Fullname: user.FullName,
|
||||
Username: user.Username,
|
||||
ID: obj.CausedBy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *notificationResolver) Data(ctx context.Context, obj *db.Notification) ([]NotificationData, error) {
|
||||
notifiedData := NotifiedData{}
|
||||
err := json.Unmarshal(obj.Data, ¬ifiedData)
|
||||
if err != nil {
|
||||
return []NotificationData{}, err
|
||||
}
|
||||
data := []NotificationData{}
|
||||
for key, value := range notifiedData.Data {
|
||||
data = append(data, NotificationData{Key: key, Value: value})
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (r *notificationResolver) CreatedAt(ctx context.Context, obj *db.Notification) (*time.Time, error) {
|
||||
return &obj.CreatedOn, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Notifications(ctx context.Context) ([]Notified, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
logger.New(ctx).Info("fetching notifications")
|
||||
if !ok {
|
||||
return []Notified{}, nil
|
||||
}
|
||||
notifications, err := r.Repository.GetAllNotificationsForUserID(ctx, userID)
|
||||
if err == sql.ErrNoRows {
|
||||
return []Notified{}, nil
|
||||
} else if err != nil {
|
||||
return []Notified{}, err
|
||||
}
|
||||
userNotifications := []Notified{}
|
||||
for _, notified := range notifications {
|
||||
var readAt *time.Time
|
||||
if notified.ReadAt.Valid {
|
||||
readAt = ¬ified.ReadAt.Time
|
||||
}
|
||||
n := Notified{
|
||||
ID: notified.NotifiedID,
|
||||
Read: notified.Read,
|
||||
ReadAt: readAt,
|
||||
Notification: &db.Notification{
|
||||
NotificationID: notified.NotificationID,
|
||||
CausedBy: notified.CausedBy,
|
||||
ActionType: notified.ActionType,
|
||||
Data: notified.Data,
|
||||
CreatedOn: notified.CreatedOn,
|
||||
},
|
||||
}
|
||||
userNotifications = append(userNotifications, n)
|
||||
}
|
||||
return userNotifications, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Notified(ctx context.Context, input NotifiedInput) (*NotifiedResult, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return &NotifiedResult{}, errors.New("userID is not found")
|
||||
}
|
||||
log.WithField("userID", userID).Info("fetching notified")
|
||||
if input.Cursor != nil {
|
||||
t, id, err := utils.DecodeCursor(*input.Cursor)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error decoding cursor")
|
||||
return &NotifiedResult{}, err
|
||||
}
|
||||
enableRead := false
|
||||
enableActionType := false
|
||||
actionTypes := []string{}
|
||||
switch input.Filter {
|
||||
case NotificationFilterUnread:
|
||||
enableRead = true
|
||||
break
|
||||
case NotificationFilterMentioned:
|
||||
enableActionType = true
|
||||
actionTypes = []string{"COMMENT_MENTIONED"}
|
||||
break
|
||||
case NotificationFilterAssigned:
|
||||
enableActionType = true
|
||||
actionTypes = []string{"TASK_ASSIGNED"}
|
||||
break
|
||||
}
|
||||
n, err := r.Repository.GetNotificationsForUserIDCursor(ctx, db.GetNotificationsForUserIDCursorParams{
|
||||
CreatedOn: t,
|
||||
NotificationID: id,
|
||||
LimitRows: int32(input.Limit + 1),
|
||||
UserID: userID,
|
||||
EnableUnread: enableRead,
|
||||
EnableActionType: enableActionType,
|
||||
ActionType: actionTypes,
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error decoding fetching notifications")
|
||||
return &NotifiedResult{}, err
|
||||
}
|
||||
hasNextPage := false
|
||||
log.WithFields(log.Fields{
|
||||
"nLen": len(n),
|
||||
"cursorTime": t,
|
||||
"cursorId": id,
|
||||
"limit": input.Limit,
|
||||
}).Info("fetched notified")
|
||||
var endCursor *db.GetNotificationsForUserIDCursorRow
|
||||
if len(n) != 0 {
|
||||
endCursor = &n[len(n)-1]
|
||||
if len(n) == input.Limit+1 {
|
||||
hasNextPage = true
|
||||
n = n[:len(n)-1]
|
||||
endCursor = &n[len(n)-1]
|
||||
}
|
||||
}
|
||||
userNotifications := []Notified{}
|
||||
for _, notified := range n {
|
||||
var readAt *time.Time
|
||||
if notified.ReadAt.Valid {
|
||||
readAt = ¬ified.ReadAt.Time
|
||||
}
|
||||
n := Notified{
|
||||
ID: notified.NotifiedID,
|
||||
Read: notified.Read,
|
||||
ReadAt: readAt,
|
||||
Notification: &db.Notification{
|
||||
NotificationID: notified.NotificationID,
|
||||
CausedBy: notified.CausedBy,
|
||||
ActionType: notified.ActionType,
|
||||
Data: notified.Data,
|
||||
CreatedOn: notified.CreatedOn,
|
||||
},
|
||||
}
|
||||
userNotifications = append(userNotifications, n)
|
||||
}
|
||||
var endCursorEncoded *string
|
||||
if endCursor != nil {
|
||||
eCur := utils.EncodeCursor(endCursor.CreatedOn, endCursor.NotificationID)
|
||||
endCursorEncoded = &eCur
|
||||
}
|
||||
pageInfo := &PageInfo{
|
||||
HasNextPage: hasNextPage,
|
||||
EndCursor: endCursorEncoded,
|
||||
}
|
||||
log.WithField("pageInfo", pageInfo).Info("created page info")
|
||||
return &NotifiedResult{
|
||||
TotalCount: len(n) - 1,
|
||||
PageInfo: pageInfo,
|
||||
Notified: userNotifications,
|
||||
}, nil
|
||||
}
|
||||
enableRead := false
|
||||
enableActionType := false
|
||||
actionTypes := []string{}
|
||||
switch input.Filter {
|
||||
case NotificationFilterUnread:
|
||||
enableRead = true
|
||||
break
|
||||
case NotificationFilterMentioned:
|
||||
enableActionType = true
|
||||
actionTypes = []string{"COMMENT_MENTIONED"}
|
||||
break
|
||||
case NotificationFilterAssigned:
|
||||
enableActionType = true
|
||||
actionTypes = []string{"TASK_ASSIGNED"}
|
||||
break
|
||||
}
|
||||
n, err := r.Repository.GetNotificationsForUserIDPaged(ctx, db.GetNotificationsForUserIDPagedParams{
|
||||
LimitRows: int32(input.Limit + 1),
|
||||
EnableUnread: enableRead,
|
||||
EnableActionType: enableActionType,
|
||||
ActionType: actionTypes,
|
||||
UserID: userID,
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error decoding fetching notifications")
|
||||
return &NotifiedResult{}, err
|
||||
}
|
||||
hasNextPage := false
|
||||
log.WithFields(log.Fields{
|
||||
"nLen": len(n),
|
||||
"limit": input.Limit,
|
||||
}).Info("fetched notified")
|
||||
var endCursor *db.GetNotificationsForUserIDPagedRow
|
||||
if len(n) != 0 {
|
||||
endCursor = &n[len(n)-1]
|
||||
if len(n) == input.Limit+1 {
|
||||
hasNextPage = true
|
||||
n = n[:len(n)-1]
|
||||
endCursor = &n[len(n)-1]
|
||||
}
|
||||
}
|
||||
userNotifications := []Notified{}
|
||||
for _, notified := range n {
|
||||
var readAt *time.Time
|
||||
if notified.ReadAt.Valid {
|
||||
readAt = ¬ified.ReadAt.Time
|
||||
}
|
||||
n := Notified{
|
||||
ID: notified.NotifiedID,
|
||||
Read: notified.Read,
|
||||
ReadAt: readAt,
|
||||
Notification: &db.Notification{
|
||||
NotificationID: notified.NotificationID,
|
||||
CausedBy: notified.CausedBy,
|
||||
ActionType: notified.ActionType,
|
||||
Data: notified.Data,
|
||||
CreatedOn: notified.CreatedOn,
|
||||
},
|
||||
}
|
||||
userNotifications = append(userNotifications, n)
|
||||
}
|
||||
var endCursorEncoded *string
|
||||
if endCursor != nil {
|
||||
eCur := utils.EncodeCursor(endCursor.CreatedOn, endCursor.NotificationID)
|
||||
endCursorEncoded = &eCur
|
||||
}
|
||||
pageInfo := &PageInfo{
|
||||
HasNextPage: hasNextPage,
|
||||
EndCursor: endCursorEncoded,
|
||||
}
|
||||
log.WithField("pageInfo", pageInfo).Info("created page info")
|
||||
return &NotifiedResult{
|
||||
TotalCount: len(n),
|
||||
PageInfo: pageInfo,
|
||||
Notified: userNotifications,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) HasUnreadNotifications(ctx context.Context) (*HasUnreadNotificationsResult, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return &HasUnreadNotificationsResult{}, errors.New("userID is missing")
|
||||
}
|
||||
unread, err := r.Repository.HasUnreadNotification(ctx, userID)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while fetching unread notifications")
|
||||
return &HasUnreadNotificationsResult{}, err
|
||||
}
|
||||
return &HasUnreadNotificationsResult{
|
||||
Unread: unread,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *subscriptionResolver) NotificationAdded(ctx context.Context) (<-chan *Notified, error) {
|
||||
notified := make(chan *Notified, 1)
|
||||
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return notified, errors.New("userID is not found")
|
||||
}
|
||||
|
||||
id := uuid.New().String()
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
r.Notifications.Mu.Lock()
|
||||
if _, ok := r.Notifications.Subscribers[userID.String()]; ok {
|
||||
delete(r.Notifications.Subscribers[userID.String()], id)
|
||||
}
|
||||
r.Notifications.Mu.Unlock()
|
||||
}()
|
||||
|
||||
r.Notifications.Mu.Lock()
|
||||
if _, ok := r.Notifications.Subscribers[userID.String()]; !ok {
|
||||
r.Notifications.Subscribers[userID.String()] = make(map[string]chan *Notified)
|
||||
}
|
||||
log.WithField("userID", userID).WithField("id", id).Info("adding new channel")
|
||||
r.Notifications.Subscribers[userID.String()][id] = notified
|
||||
r.Notifications.Mu.Unlock()
|
||||
return notified, nil
|
||||
}
|
||||
|
||||
// Notification returns NotificationResolver implementation.
|
||||
func (r *Resolver) Notification() NotificationResolver { return ¬ificationResolver{r} }
|
||||
|
||||
type notificationResolver struct{ *Resolver }
|
@ -1,439 +0,0 @@
|
||||
package graph
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/jordanknott/taskcafe/internal/logger"
|
||||
"github.com/jordanknott/taskcafe/internal/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
func (r *labelColorResolver) ID(ctx context.Context, obj *db.LabelColor) (uuid.UUID, error) {
|
||||
return obj.LabelColorID, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) CreateProjectLabel(ctx context.Context, input NewProjectLabel) (*db.ProjectLabel, error) {
|
||||
createdAt := time.Now().UTC()
|
||||
|
||||
var name sql.NullString
|
||||
if input.Name != nil {
|
||||
name = sql.NullString{
|
||||
*input.Name,
|
||||
true,
|
||||
}
|
||||
} else {
|
||||
name = sql.NullString{
|
||||
"",
|
||||
false,
|
||||
}
|
||||
}
|
||||
projectLabel, err := r.Repository.CreateProjectLabel(ctx, db.CreateProjectLabelParams{input.ProjectID, input.LabelColorID, createdAt, name})
|
||||
return &projectLabel, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteProjectLabel(ctx context.Context, input DeleteProjectLabel) (*db.ProjectLabel, error) {
|
||||
label, err := r.Repository.GetProjectLabelByID(ctx, input.ProjectLabelID)
|
||||
if err != nil {
|
||||
return &db.ProjectLabel{}, err
|
||||
}
|
||||
err = r.Repository.DeleteProjectLabelByID(ctx, input.ProjectLabelID)
|
||||
return &label, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateProjectLabel(ctx context.Context, input UpdateProjectLabel) (*db.ProjectLabel, error) {
|
||||
label, err := r.Repository.UpdateProjectLabel(ctx, db.UpdateProjectLabelParams{ProjectLabelID: input.ProjectLabelID, LabelColorID: input.LabelColorID, Name: sql.NullString{String: input.Name, Valid: true}})
|
||||
return &label, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateProjectLabelName(ctx context.Context, input UpdateProjectLabelName) (*db.ProjectLabel, error) {
|
||||
label, err := r.Repository.UpdateProjectLabelName(ctx, db.UpdateProjectLabelNameParams{ProjectLabelID: input.ProjectLabelID, Name: sql.NullString{String: input.Name, Valid: true}})
|
||||
return &label, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateProjectLabelColor(ctx context.Context, input UpdateProjectLabelColor) (*db.ProjectLabel, error) {
|
||||
label, err := r.Repository.UpdateProjectLabelColor(ctx, db.UpdateProjectLabelColorParams{ProjectLabelID: input.ProjectLabelID, LabelColorID: input.LabelColorID})
|
||||
return &label, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) InviteProjectMembers(ctx context.Context, input InviteProjectMembers) (*InviteProjectMembersPayload, error) {
|
||||
members := []Member{}
|
||||
invitedMembers := []InvitedMember{}
|
||||
for _, invitedMember := range input.Members {
|
||||
if invitedMember.Email != nil && invitedMember.UserID != nil {
|
||||
return &InviteProjectMembersPayload{Ok: false}, &gqlerror.Error{
|
||||
Message: "Both email and userID can not be used to invite a project member",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "403",
|
||||
},
|
||||
}
|
||||
} else if invitedMember.Email == nil && invitedMember.UserID == nil {
|
||||
return &InviteProjectMembersPayload{Ok: false}, &gqlerror.Error{
|
||||
Message: "Either email or userID must be set to invite a project member",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "403",
|
||||
},
|
||||
}
|
||||
}
|
||||
if invitedMember.UserID != nil {
|
||||
// Invite by user ID
|
||||
addedAt := time.Now().UTC()
|
||||
_, err := r.Repository.CreateProjectMember(ctx, db.CreateProjectMemberParams{ProjectID: input.ProjectID, UserID: *invitedMember.UserID, AddedAt: addedAt, RoleCode: "member"})
|
||||
if err != nil {
|
||||
return &InviteProjectMembersPayload{Ok: false}, err
|
||||
}
|
||||
user, err := r.Repository.GetUserAccountByID(ctx, *invitedMember.UserID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return &InviteProjectMembersPayload{Ok: false}, err
|
||||
|
||||
}
|
||||
var url *string
|
||||
if user.ProfileAvatarUrl.Valid {
|
||||
url = &user.ProfileAvatarUrl.String
|
||||
}
|
||||
profileIcon := &ProfileIcon{url, &user.Initials, &user.ProfileBgColor}
|
||||
|
||||
role, err := r.Repository.GetRoleForProjectMemberByUserID(ctx, db.GetRoleForProjectMemberByUserIDParams{UserID: *invitedMember.UserID, ProjectID: input.ProjectID})
|
||||
if err != nil {
|
||||
return &InviteProjectMembersPayload{Ok: false}, err
|
||||
}
|
||||
members = append(members, Member{
|
||||
ID: *invitedMember.UserID,
|
||||
FullName: user.FullName,
|
||||
Username: user.Username,
|
||||
ProfileIcon: profileIcon,
|
||||
Role: &db.Role{Code: role.Code, Name: role.Name},
|
||||
})
|
||||
} else {
|
||||
// Invite by email
|
||||
|
||||
// if invited user does not exist, create entry
|
||||
invitedUser, err := r.Repository.GetInvitedUserByEmail(ctx, *invitedMember.Email)
|
||||
now := time.Now().UTC()
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
invitedUser, err = r.Repository.CreateInvitedUser(ctx, *invitedMember.Email)
|
||||
if err != nil {
|
||||
return &InviteProjectMembersPayload{Ok: false}, err
|
||||
}
|
||||
confirmToken, err := r.Repository.CreateConfirmToken(ctx, *invitedMember.Email)
|
||||
if err != nil {
|
||||
return &InviteProjectMembersPayload{Ok: false}, err
|
||||
}
|
||||
invite := utils.EmailInvite{To: *invitedMember.Email, FullName: *invitedMember.Email, ConfirmToken: confirmToken.ConfirmTokenID.String()}
|
||||
err = utils.SendEmailInvite(r.AppConfig.Email, invite)
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("issue sending email")
|
||||
return &InviteProjectMembersPayload{Ok: false}, err
|
||||
}
|
||||
} else {
|
||||
return &InviteProjectMembersPayload{Ok: false}, err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = r.Repository.CreateInvitedProjectMember(ctx, db.CreateInvitedProjectMemberParams{
|
||||
ProjectID: input.ProjectID,
|
||||
UserAccountInvitedID: invitedUser.UserAccountInvitedID,
|
||||
})
|
||||
if err != nil {
|
||||
return &InviteProjectMembersPayload{Ok: false}, err
|
||||
}
|
||||
logger.New(ctx).Info("adding invited member")
|
||||
invitedMembers = append(invitedMembers, InvitedMember{Email: *invitedMember.Email, InvitedOn: now})
|
||||
|
||||
}
|
||||
}
|
||||
return &InviteProjectMembersPayload{Ok: false, ProjectID: input.ProjectID, Members: members, InvitedMembers: invitedMembers}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteProjectMember(ctx context.Context, input DeleteProjectMember) (*DeleteProjectMemberPayload, error) {
|
||||
user, err := r.Repository.GetUserAccountByID(ctx, input.UserID)
|
||||
if err != nil {
|
||||
return &DeleteProjectMemberPayload{Ok: false}, err
|
||||
}
|
||||
var url *string
|
||||
if user.ProfileAvatarUrl.Valid {
|
||||
url = &user.ProfileAvatarUrl.String
|
||||
}
|
||||
profileIcon := &ProfileIcon{url, &user.Initials, &user.ProfileBgColor}
|
||||
role, err := r.Repository.GetRoleForProjectMemberByUserID(ctx, db.GetRoleForProjectMemberByUserIDParams{UserID: input.UserID, ProjectID: input.ProjectID})
|
||||
if err != nil {
|
||||
return &DeleteProjectMemberPayload{Ok: false}, err
|
||||
}
|
||||
err = r.Repository.DeleteProjectMember(ctx, db.DeleteProjectMemberParams{UserID: input.UserID, ProjectID: input.ProjectID})
|
||||
if err != nil {
|
||||
return &DeleteProjectMemberPayload{Ok: false}, err
|
||||
}
|
||||
return &DeleteProjectMemberPayload{Ok: true, Member: &Member{
|
||||
ID: input.UserID,
|
||||
FullName: user.FullName,
|
||||
ProfileIcon: profileIcon,
|
||||
Role: &db.Role{Code: role.Code, Name: role.Name},
|
||||
}, ProjectID: input.ProjectID}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateProjectMemberRole(ctx context.Context, input UpdateProjectMemberRole) (*UpdateProjectMemberRolePayload, error) {
|
||||
user, err := r.Repository.GetUserAccountByID(ctx, input.UserID)
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("get user account")
|
||||
return &UpdateProjectMemberRolePayload{Ok: false}, err
|
||||
}
|
||||
_, err = r.Repository.UpdateProjectMemberRole(ctx, db.UpdateProjectMemberRoleParams{ProjectID: input.ProjectID,
|
||||
UserID: input.UserID, RoleCode: input.RoleCode.String()})
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("update project member role")
|
||||
return &UpdateProjectMemberRolePayload{Ok: false}, err
|
||||
}
|
||||
role, err := r.Repository.GetRoleForProjectMemberByUserID(ctx, db.GetRoleForProjectMemberByUserIDParams{UserID: user.UserID, ProjectID: input.ProjectID})
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("get role for project member")
|
||||
return &UpdateProjectMemberRolePayload{Ok: false}, err
|
||||
}
|
||||
var url *string
|
||||
if user.ProfileAvatarUrl.Valid {
|
||||
url = &user.ProfileAvatarUrl.String
|
||||
}
|
||||
profileIcon := &ProfileIcon{url, &user.Initials, &user.ProfileBgColor}
|
||||
if user.ProfileAvatarUrl.Valid {
|
||||
url = &user.ProfileAvatarUrl.String
|
||||
}
|
||||
member := Member{ID: user.UserID, FullName: user.FullName, ProfileIcon: profileIcon,
|
||||
Role: &db.Role{Code: role.Code, Name: role.Name},
|
||||
}
|
||||
return &UpdateProjectMemberRolePayload{Ok: true, Member: &member}, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteInvitedProjectMember(ctx context.Context, input DeleteInvitedProjectMember) (*DeleteInvitedProjectMemberPayload, error) {
|
||||
member, err := r.Repository.GetProjectMemberInvitedIDByEmail(ctx, input.Email)
|
||||
if err != nil {
|
||||
return &DeleteInvitedProjectMemberPayload{}, err
|
||||
}
|
||||
err = r.Repository.DeleteInvitedProjectMemberByID(ctx, member.ProjectMemberInvitedID)
|
||||
if err != nil {
|
||||
return &DeleteInvitedProjectMemberPayload{}, err
|
||||
}
|
||||
return &DeleteInvitedProjectMemberPayload{
|
||||
InvitedMember: &InvitedMember{Email: member.Email, InvitedOn: member.InvitedOn},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) CreateProject(ctx context.Context, input NewProject) (*db.Project, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return &db.Project{}, errors.New("user id is missing")
|
||||
}
|
||||
createdAt := time.Now().UTC()
|
||||
logger.New(ctx).WithFields(log.Fields{"name": input.Name, "teamID": input.TeamID}).Info("creating new project")
|
||||
var project db.Project
|
||||
var err error
|
||||
if input.TeamID == nil {
|
||||
project, err = r.Repository.CreatePersonalProject(ctx, db.CreatePersonalProjectParams{
|
||||
CreatedAt: createdAt,
|
||||
Name: input.Name,
|
||||
})
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("error while creating project")
|
||||
return &db.Project{}, err
|
||||
}
|
||||
logger.New(ctx).WithField("projectID", project.ProjectID).Info("creating personal project link")
|
||||
} else {
|
||||
project, err = r.Repository.CreateTeamProject(ctx, db.CreateTeamProjectParams{
|
||||
CreatedAt: createdAt,
|
||||
Name: input.Name,
|
||||
TeamID: *input.TeamID,
|
||||
})
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("error while creating project")
|
||||
return &db.Project{}, err
|
||||
}
|
||||
}
|
||||
_, err = r.Repository.CreateProjectMember(ctx, db.CreateProjectMemberParams{ProjectID: project.ProjectID, UserID: userID, AddedAt: createdAt, RoleCode: "admin"})
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("error while creating initial project member")
|
||||
return &db.Project{}, err
|
||||
}
|
||||
return &project, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteProject(ctx context.Context, input DeleteProject) (*DeleteProjectPayload, error) {
|
||||
project, err := r.Repository.GetProjectByID(ctx, input.ProjectID)
|
||||
if err != nil {
|
||||
return &DeleteProjectPayload{Ok: false}, err
|
||||
}
|
||||
err = r.Repository.DeleteProjectByID(ctx, input.ProjectID)
|
||||
if err != nil {
|
||||
return &DeleteProjectPayload{Ok: false}, err
|
||||
}
|
||||
return &DeleteProjectPayload{Project: &project, Ok: true}, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateProjectName(ctx context.Context, input *UpdateProjectName) (*db.Project, error) {
|
||||
project, err := r.Repository.UpdateProjectNameByID(ctx, db.UpdateProjectNameByIDParams{ProjectID: input.ProjectID, Name: input.Name})
|
||||
if err != nil {
|
||||
return &db.Project{}, err
|
||||
}
|
||||
return &project, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) ToggleProjectVisibility(ctx context.Context, input ToggleProjectVisibility) (*ToggleProjectVisibilityPayload, error) {
|
||||
if input.IsPublic {
|
||||
project, err := r.Repository.SetPublicOn(ctx, db.SetPublicOnParams{ProjectID: input.ProjectID, PublicOn: sql.NullTime{Valid: true, Time: time.Now().UTC()}})
|
||||
return &ToggleProjectVisibilityPayload{Project: &project}, err
|
||||
}
|
||||
project, err := r.Repository.SetPublicOn(ctx, db.SetPublicOnParams{ProjectID: input.ProjectID, PublicOn: sql.NullTime{Valid: false, Time: time.Time{}}})
|
||||
return &ToggleProjectVisibilityPayload{Project: &project}, err
|
||||
}
|
||||
|
||||
func (r *projectResolver) ID(ctx context.Context, obj *db.Project) (uuid.UUID, error) {
|
||||
return obj.ProjectID, nil
|
||||
}
|
||||
|
||||
func (r *projectResolver) Team(ctx context.Context, obj *db.Project) (*db.Team, error) {
|
||||
team, err := r.Repository.GetTeamByID(ctx, obj.TeamID)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
logger.New(ctx).WithFields(log.Fields{"teamID": obj.TeamID, "projectID": obj.ProjectID}).WithError(err).Error("issue while getting team for project")
|
||||
return &team, err
|
||||
}
|
||||
return &team, nil
|
||||
}
|
||||
|
||||
func (r *projectResolver) TaskGroups(ctx context.Context, obj *db.Project) ([]db.TaskGroup, error) {
|
||||
return r.Repository.GetTaskGroupsForProject(ctx, obj.ProjectID)
|
||||
}
|
||||
|
||||
func (r *projectResolver) Members(ctx context.Context, obj *db.Project) ([]Member, error) {
|
||||
members := []Member{}
|
||||
projectMembers, err := r.Repository.GetProjectMembersForProjectID(ctx, obj.ProjectID)
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("get project members for project id")
|
||||
return members, err
|
||||
}
|
||||
|
||||
for _, projectMember := range projectMembers {
|
||||
user, err := r.Repository.GetUserAccountByID(ctx, projectMember.UserID)
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("get user account by ID")
|
||||
return members, err
|
||||
}
|
||||
var url *string
|
||||
if user.ProfileAvatarUrl.Valid {
|
||||
url = &user.ProfileAvatarUrl.String
|
||||
}
|
||||
role, err := r.Repository.GetRoleForProjectMemberByUserID(ctx, db.GetRoleForProjectMemberByUserIDParams{UserID: user.UserID, ProjectID: obj.ProjectID})
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("get role for projet member by user ID")
|
||||
return members, err
|
||||
}
|
||||
profileIcon := &ProfileIcon{url, &user.Initials, &user.ProfileBgColor}
|
||||
members = append(members, Member{ID: user.UserID, FullName: user.FullName, ProfileIcon: profileIcon,
|
||||
Username: user.Username, Role: &db.Role{Code: role.Code, Name: role.Name},
|
||||
})
|
||||
}
|
||||
return members, nil
|
||||
}
|
||||
|
||||
func (r *projectResolver) InvitedMembers(ctx context.Context, obj *db.Project) ([]InvitedMember, error) {
|
||||
members, err := r.Repository.GetInvitedMembersForProjectID(ctx, obj.ProjectID)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
return []InvitedMember{}, nil
|
||||
}
|
||||
invited := []InvitedMember{}
|
||||
for _, member := range members {
|
||||
invited = append(invited, InvitedMember{Email: member.Email, InvitedOn: member.InvitedOn})
|
||||
}
|
||||
return invited, err
|
||||
}
|
||||
|
||||
func (r *projectResolver) PublicOn(ctx context.Context, obj *db.Project) (*time.Time, error) {
|
||||
if obj.PublicOn.Valid {
|
||||
return &obj.PublicOn.Time, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *projectResolver) Permission(ctx context.Context, obj *db.Project) (*ProjectPermission, error) {
|
||||
panic(fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
func (r *projectResolver) Labels(ctx context.Context, obj *db.Project) ([]db.ProjectLabel, error) {
|
||||
labels, err := r.Repository.GetProjectLabelsForProject(ctx, obj.ProjectID)
|
||||
return labels, err
|
||||
}
|
||||
|
||||
func (r *projectLabelResolver) ID(ctx context.Context, obj *db.ProjectLabel) (uuid.UUID, error) {
|
||||
return obj.ProjectLabelID, nil
|
||||
}
|
||||
|
||||
func (r *projectLabelResolver) LabelColor(ctx context.Context, obj *db.ProjectLabel) (*db.LabelColor, error) {
|
||||
labelColor, err := r.Repository.GetLabelColorByID(ctx, obj.LabelColorID)
|
||||
if err != nil {
|
||||
return &db.LabelColor{}, err
|
||||
}
|
||||
return &labelColor, nil
|
||||
}
|
||||
|
||||
func (r *projectLabelResolver) Name(ctx context.Context, obj *db.ProjectLabel) (*string, error) {
|
||||
var name *string
|
||||
if obj.Name.Valid {
|
||||
name = &obj.Name.String
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) FindProject(ctx context.Context, input FindProject) (*db.Project, error) {
|
||||
_, isLoggedIn := GetUser(ctx)
|
||||
var projectID uuid.UUID
|
||||
var err error
|
||||
if input.ProjectID != nil {
|
||||
projectID = *input.ProjectID
|
||||
} else if input.ProjectShortID != nil {
|
||||
projectID, err = r.Repository.GetProjectIDByShortID(ctx, *input.ProjectShortID)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while getting project id by short id")
|
||||
return &db.Project{}, err
|
||||
}
|
||||
} else {
|
||||
return &db.Project{}, errors.New("FindProject requires either ProjectID or ProjectShortID to be set")
|
||||
}
|
||||
if !isLoggedIn {
|
||||
isPublic, _ := IsProjectPublic(ctx, r.Repository, projectID)
|
||||
if !isPublic {
|
||||
return &db.Project{}, NotAuthorized()
|
||||
}
|
||||
}
|
||||
project, err := r.Repository.GetProjectByID(ctx, projectID)
|
||||
if err == sql.ErrNoRows {
|
||||
return &db.Project{}, &gqlerror.Error{
|
||||
Message: "Project not found",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "NOT_FOUND",
|
||||
},
|
||||
}
|
||||
}
|
||||
return &project, nil
|
||||
}
|
||||
|
||||
// LabelColor returns LabelColorResolver implementation.
|
||||
func (r *Resolver) LabelColor() LabelColorResolver { return &labelColorResolver{r} }
|
||||
|
||||
// Project returns ProjectResolver implementation.
|
||||
func (r *Resolver) Project() ProjectResolver { return &projectResolver{r} }
|
||||
|
||||
// ProjectLabel returns ProjectLabelResolver implementation.
|
||||
func (r *Resolver) ProjectLabel() ProjectLabelResolver { return &projectLabelResolver{r} }
|
||||
|
||||
type labelColorResolver struct{ *Resolver }
|
||||
type projectResolver struct{ *Resolver }
|
||||
type projectLabelResolver struct{ *Resolver }
|
@ -1,70 +0,0 @@
|
||||
//go:generate sh ../scripts/genSchema.sh
|
||||
//go:generate go run github.com/99designs/gqlgen
|
||||
|
||||
package graph
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/jordanknott/taskcafe/internal/jobs"
|
||||
"github.com/jordanknott/taskcafe/internal/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Resolver handles resolving GraphQL queries & mutations
|
||||
type Resolver struct {
|
||||
Repository db.Repository
|
||||
AppConfig config.AppConfig
|
||||
Notifications *NotificationObservers
|
||||
Job jobs.JobQueue
|
||||
Redis *redis.Client
|
||||
}
|
||||
|
||||
func (r Resolver) SubscribeRedis() {
|
||||
ctx := context.Background()
|
||||
go func() {
|
||||
subscriber := r.Redis.Subscribe(ctx, "notification-created")
|
||||
log.Info("Stream starting...")
|
||||
for {
|
||||
|
||||
msg, err := subscriber.ReceiveMessage(ctx)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("while receiving message")
|
||||
panic(err)
|
||||
}
|
||||
var message utils.NotificationCreatedMessage
|
||||
|
||||
if err := json.Unmarshal([]byte(msg.Payload), &message); err != nil {
|
||||
log.WithError(err).Error("while unmarshalling notifiction created message")
|
||||
panic(err)
|
||||
}
|
||||
log.WithField("notID", message.NotifiedID).Info("received notification message")
|
||||
|
||||
notified, err := r.Repository.GetNotifiedByIDNoExtra(ctx, uuid.MustParse(message.NotifiedID))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("while getting notified by id")
|
||||
panic(err)
|
||||
}
|
||||
notification, err := r.Repository.GetNotificationByID(ctx, uuid.MustParse(message.NotificationID))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("while getting notified by id")
|
||||
panic(err)
|
||||
}
|
||||
for _, observers := range r.Notifications.Subscribers {
|
||||
for _, ochan := range observers {
|
||||
ochan <- &Notified{
|
||||
ID: notified.NotifiedID,
|
||||
Read: notified.Read,
|
||||
ReadAt: ¬ified.ReadAt.Time,
|
||||
Notification: ¬ification,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package graph
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"strconv"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// MarshalUUID converts a UUID to JSON string
|
||||
func MarshalUUID(uuid uuid.UUID) graphql.Marshaler {
|
||||
return graphql.WriterFunc(func(w io.Writer) {
|
||||
w.Write([]byte(strconv.Quote(uuid.String())))
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalUUID converts a String to a UUID
|
||||
func UnmarshalUUID(v interface{}) (uuid.UUID, error) {
|
||||
if uuidRaw, ok := v.(string); ok {
|
||||
return uuid.Parse(uuidRaw)
|
||||
}
|
||||
return uuid.UUID{}, errors.New("uuid must be a string")
|
||||
}
|
@ -1,298 +0,0 @@
|
||||
package graph
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jinzhu/now"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/jordanknott/taskcafe/internal/logger"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
func (r *organizationResolver) ID(ctx context.Context, obj *db.Organization) (uuid.UUID, error) {
|
||||
return obj.OrganizationID, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Organizations(ctx context.Context) ([]db.Organization, error) {
|
||||
return r.Repository.GetAllOrganizations(ctx)
|
||||
}
|
||||
|
||||
func (r *queryResolver) Users(ctx context.Context) ([]db.UserAccount, error) {
|
||||
return r.Repository.GetAllUserAccounts(ctx)
|
||||
}
|
||||
|
||||
func (r *queryResolver) InvitedUsers(ctx context.Context) ([]InvitedUserAccount, error) {
|
||||
invitedMembers, err := r.Repository.GetInvitedUserAccounts(ctx)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return []InvitedUserAccount{}, nil
|
||||
}
|
||||
return []InvitedUserAccount{}, err
|
||||
}
|
||||
members := []InvitedUserAccount{}
|
||||
for _, invitedMember := range invitedMembers {
|
||||
members = append(members, InvitedUserAccount{
|
||||
ID: invitedMember.UserAccountInvitedID,
|
||||
Email: invitedMember.Email,
|
||||
InvitedOn: invitedMember.InvitedOn,
|
||||
})
|
||||
}
|
||||
return members, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) FindUser(ctx context.Context, input FindUser) (*db.UserAccount, error) {
|
||||
account, err := r.Repository.GetUserAccountByID(ctx, input.UserID)
|
||||
if err == sql.ErrNoRows {
|
||||
return &db.UserAccount{}, &gqlerror.Error{
|
||||
Message: "User not found",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "10-404",
|
||||
},
|
||||
}
|
||||
}
|
||||
return &account, err
|
||||
}
|
||||
|
||||
func (r *queryResolver) Projects(ctx context.Context, input *ProjectsFilter) ([]db.Project, error) {
|
||||
userID, ok := GetUser(ctx)
|
||||
if !ok {
|
||||
logger.New(ctx).Info("user id was not found from middleware")
|
||||
return []db.Project{}, nil
|
||||
}
|
||||
logger.New(ctx).Info("fetching projects")
|
||||
|
||||
if input != nil {
|
||||
return r.Repository.GetAllProjectsForTeam(ctx, *input.TeamID)
|
||||
}
|
||||
|
||||
var teams []db.Team
|
||||
var err error
|
||||
teams, err = r.Repository.GetTeamsForUserIDWhereAdmin(ctx, userID)
|
||||
|
||||
projects := make(map[string]db.Project)
|
||||
for _, team := range teams {
|
||||
logger.New(ctx).WithField("teamID", team.TeamID).Info("found team")
|
||||
teamProjects, err := r.Repository.GetAllProjectsForTeam(ctx, team.TeamID)
|
||||
if err != sql.ErrNoRows && err != nil {
|
||||
log.Info("issue getting team projects")
|
||||
return []db.Project{}, nil
|
||||
}
|
||||
for _, project := range teamProjects {
|
||||
logger.New(ctx).WithField("projectID", project.ProjectID).Info("adding team project")
|
||||
projects[project.ProjectID.String()] = project
|
||||
}
|
||||
}
|
||||
|
||||
visibleProjects, err := r.Repository.GetAllVisibleProjectsForUserID(ctx, userID)
|
||||
if err != nil {
|
||||
logger.New(ctx).Info("error getting visible projects for user")
|
||||
return []db.Project{}, nil
|
||||
}
|
||||
for _, project := range visibleProjects {
|
||||
logger.New(ctx).WithField("projectID", project.ProjectID).Info("found visible project")
|
||||
if _, ok := projects[project.ProjectID.String()]; !ok {
|
||||
logger.New(ctx).WithField("projectID", project.ProjectID).Info("adding visible project")
|
||||
projects[project.ProjectID.String()] = project
|
||||
}
|
||||
}
|
||||
logger.New(ctx).WithField("projectLength", len(projects)).Info("making projects")
|
||||
allProjects := make([]db.Project, 0, len(projects))
|
||||
for _, project := range projects {
|
||||
logger.New(ctx).WithField("projectID", project.ProjectID).Info("adding project to final list")
|
||||
allProjects = append(allProjects, project)
|
||||
}
|
||||
return allProjects, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Teams(ctx context.Context) ([]db.Team, error) {
|
||||
userID, ok := GetUser(ctx)
|
||||
if !ok {
|
||||
logger.New(ctx).Error("userID or org role does not exist")
|
||||
return []db.Team{}, errors.New("internal error")
|
||||
}
|
||||
|
||||
teams := make(map[string]db.Team)
|
||||
adminTeams, err := r.Repository.GetTeamsForUserIDWhereAdmin(ctx, userID)
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("error while getting teams for user ID")
|
||||
return []db.Team{}, err
|
||||
}
|
||||
|
||||
for _, team := range adminTeams {
|
||||
teams[team.TeamID.String()] = team
|
||||
}
|
||||
|
||||
visibleProjects, err := r.Repository.GetAllVisibleProjectsForUserID(ctx, userID)
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("error while getting visible projects for user ID")
|
||||
return []db.Team{}, err
|
||||
}
|
||||
for _, project := range visibleProjects {
|
||||
logger.New(ctx).WithField("projectID", project.ProjectID).Info("found visible project")
|
||||
if _, ok := teams[project.ProjectID.String()]; !ok {
|
||||
logger.New(ctx).WithField("projectID", project.ProjectID).Info("adding visible project")
|
||||
team, err := r.Repository.GetTeamByID(ctx, project.TeamID)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
continue
|
||||
}
|
||||
logger.New(ctx).WithField("teamID", project.TeamID).WithError(err).Error("error getting team by id")
|
||||
return []db.Team{}, err
|
||||
}
|
||||
teams[project.TeamID.String()] = team
|
||||
}
|
||||
}
|
||||
foundTeams := make([]db.Team, 0, len(teams))
|
||||
for _, team := range teams {
|
||||
foundTeams = append(foundTeams, team)
|
||||
}
|
||||
return foundTeams, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) FindTeam(ctx context.Context, input FindTeam) (*db.Team, error) {
|
||||
team, err := r.Repository.GetTeamByID(ctx, input.TeamID)
|
||||
if err != nil {
|
||||
return &db.Team{}, err
|
||||
}
|
||||
return &team, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) MyTasks(ctx context.Context, input MyTasks) (*MyTasksPayload, error) {
|
||||
userID, _ := GetUserID(ctx)
|
||||
projects := []ProjectTaskMapping{}
|
||||
var tasks []db.Task
|
||||
var err error
|
||||
showAll := false
|
||||
if input.Status == MyTasksStatusAll {
|
||||
showAll = true
|
||||
}
|
||||
complete := false
|
||||
completedAt := sql.NullTime{Valid: false, Time: time.Time{}}
|
||||
switch input.Status {
|
||||
case MyTasksStatusCompleteAll:
|
||||
complete = true
|
||||
completedAt = sql.NullTime{Valid: true, Time: time.Time{}}
|
||||
case MyTasksStatusCompleteToday:
|
||||
complete = true
|
||||
completedAt = sql.NullTime{Valid: true, Time: now.BeginningOfDay()}
|
||||
case MyTasksStatusCompleteYesterday:
|
||||
complete = true
|
||||
completedAt = sql.NullTime{Valid: true, Time: now.With(time.Now().AddDate(0, 0, -1)).BeginningOfDay()}
|
||||
case MyTasksStatusCompleteOneWeek:
|
||||
complete = true
|
||||
completedAt = sql.NullTime{Valid: true, Time: now.With(time.Now().AddDate(0, 0, -7)).BeginningOfDay()}
|
||||
case MyTasksStatusCompleteTwoWeek:
|
||||
complete = true
|
||||
completedAt = sql.NullTime{Valid: true, Time: now.With(time.Now().AddDate(0, 0, -14)).BeginningOfDay()}
|
||||
case MyTasksStatusCompleteThreeWeek:
|
||||
complete = true
|
||||
completedAt = sql.NullTime{Valid: true, Time: now.With(time.Now().AddDate(0, 0, -21)).BeginningOfDay()}
|
||||
}
|
||||
|
||||
if input.Sort == MyTasksSortNone {
|
||||
tasks, err = r.Repository.GetRecentlyAssignedTaskForUserID(ctx, db.GetRecentlyAssignedTaskForUserIDParams{
|
||||
UserID: userID,
|
||||
Complete: complete,
|
||||
CompletedAt: completedAt,
|
||||
Column4: showAll,
|
||||
})
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return &MyTasksPayload{}, err
|
||||
}
|
||||
} else if input.Sort == MyTasksSortProject {
|
||||
tasks, err = r.Repository.GetAssignedTasksProjectForUserID(ctx, db.GetAssignedTasksProjectForUserIDParams{
|
||||
UserID: userID,
|
||||
Complete: complete,
|
||||
CompletedAt: completedAt,
|
||||
Column4: showAll,
|
||||
})
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return &MyTasksPayload{}, err
|
||||
}
|
||||
} else if input.Sort == MyTasksSortDueDate {
|
||||
tasks, err = r.Repository.GetAssignedTasksDueDateForUserID(ctx, db.GetAssignedTasksDueDateForUserIDParams{
|
||||
UserID: userID,
|
||||
Complete: complete,
|
||||
CompletedAt: completedAt,
|
||||
Column4: showAll,
|
||||
})
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return &MyTasksPayload{}, err
|
||||
}
|
||||
}
|
||||
taskIds := []uuid.UUID{}
|
||||
for _, task := range tasks {
|
||||
taskIds = append(taskIds, task.TaskID)
|
||||
}
|
||||
mappings, err := r.Repository.GetProjectIdMappings(ctx, taskIds)
|
||||
for _, mapping := range mappings {
|
||||
projects = append(projects, ProjectTaskMapping{ProjectID: mapping.ProjectID, TaskID: mapping.TaskID})
|
||||
}
|
||||
return &MyTasksPayload{Tasks: tasks, Projects: projects}, err
|
||||
}
|
||||
|
||||
func (r *queryResolver) LabelColors(ctx context.Context) ([]db.LabelColor, error) {
|
||||
return r.Repository.GetLabelColors(ctx)
|
||||
}
|
||||
|
||||
func (r *queryResolver) TaskGroups(ctx context.Context) ([]db.TaskGroup, error) {
|
||||
return r.Repository.GetAllTaskGroups(ctx)
|
||||
}
|
||||
|
||||
func (r *queryResolver) Me(ctx context.Context) (*MePayload, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
user, err := r.Repository.GetUserAccountByID(ctx, userID)
|
||||
if err == sql.ErrNoRows {
|
||||
logger.New(ctx).Warning("can not find user for me query")
|
||||
return &MePayload{}, nil
|
||||
} else if err != nil {
|
||||
return &MePayload{}, err
|
||||
}
|
||||
var projectRoles []ProjectRole
|
||||
projects, err := r.Repository.GetProjectRolesForUserID(ctx, userID)
|
||||
if err != nil {
|
||||
return &MePayload{}, err
|
||||
}
|
||||
for _, project := range projects {
|
||||
projectRoles = append(projectRoles, ProjectRole{ProjectID: project.ProjectID, RoleCode: ConvertToRoleCode("admin")})
|
||||
// projectRoles = append(projectRoles, ProjectRole{ProjectID: project.ProjectID, RoleCode: ConvertToRoleCode(project.RoleCode)})
|
||||
}
|
||||
var teamRoles []TeamRole
|
||||
teams, err := r.Repository.GetTeamRolesForUserID(ctx, userID)
|
||||
if err != nil {
|
||||
return &MePayload{}, err
|
||||
}
|
||||
for _, team := range teams {
|
||||
// teamRoles = append(teamRoles, TeamRole{TeamID: team.TeamID, RoleCode: ConvertToRoleCode(team.RoleCode)})
|
||||
teamRoles = append(teamRoles, TeamRole{TeamID: team.TeamID, RoleCode: ConvertToRoleCode("admin")})
|
||||
}
|
||||
return &MePayload{User: &user, TeamRoles: teamRoles, ProjectRoles: projectRoles}, err
|
||||
}
|
||||
|
||||
// Mutation returns MutationResolver implementation.
|
||||
func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} }
|
||||
|
||||
// Organization returns OrganizationResolver implementation.
|
||||
func (r *Resolver) Organization() OrganizationResolver { return &organizationResolver{r} }
|
||||
|
||||
// Query returns QueryResolver implementation.
|
||||
func (r *Resolver) Query() QueryResolver { return &queryResolver{r} }
|
||||
|
||||
// Subscription returns SubscriptionResolver implementation.
|
||||
func (r *Resolver) Subscription() SubscriptionResolver { return &subscriptionResolver{r} }
|
||||
|
||||
type mutationResolver struct{ *Resolver }
|
||||
type organizationResolver struct{ *Resolver }
|
||||
type queryResolver struct{ *Resolver }
|
||||
type subscriptionResolver struct{ *Resolver }
|
@ -1,93 +0,0 @@
|
||||
extend type Subscription {
|
||||
notificationAdded: Notified!
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
notifications: [Notified!]!
|
||||
notified(input: NotifiedInput!): NotifiedResult!
|
||||
hasUnreadNotifications: HasUnreadNotificationsResult!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
notificationToggleRead(input: NotificationToggleReadInput!): Notified!
|
||||
notificationMarkAllRead: NotificationMarkAllAsReadResult!
|
||||
}
|
||||
type NotificationMarkAllAsReadResult {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type HasUnreadNotificationsResult {
|
||||
unread: Boolean!
|
||||
}
|
||||
input NotificationToggleReadInput {
|
||||
notifiedID: UUID!
|
||||
}
|
||||
|
||||
input NotifiedInput {
|
||||
limit: Int!
|
||||
cursor: String
|
||||
filter: NotificationFilter!
|
||||
}
|
||||
|
||||
type PageInfo {
|
||||
endCursor: String
|
||||
hasNextPage: Boolean!
|
||||
}
|
||||
|
||||
type NotifiedResult {
|
||||
totalCount: Int!
|
||||
notified: [Notified!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
enum ActionType {
|
||||
TEAM_ADDED
|
||||
TEAM_REMOVED
|
||||
PROJECT_ADDED
|
||||
PROJECT_REMOVED
|
||||
PROJECT_ARCHIVED
|
||||
DUE_DATE_ADDED
|
||||
DUE_DATE_REMOVED
|
||||
DUE_DATE_CHANGED
|
||||
DUE_DATE_REMINDER
|
||||
TASK_ASSIGNED
|
||||
TASK_MOVED
|
||||
TASK_ARCHIVED
|
||||
TASK_ATTACHMENT_UPLOADED
|
||||
COMMENT_MENTIONED
|
||||
COMMENT_OTHER
|
||||
}
|
||||
|
||||
enum NotificationFilter {
|
||||
ALL
|
||||
UNREAD
|
||||
ASSIGNED
|
||||
MENTIONED
|
||||
}
|
||||
|
||||
type NotificationData {
|
||||
key: String!
|
||||
value: String!
|
||||
}
|
||||
|
||||
type NotificationCausedBy {
|
||||
fullname: String!
|
||||
username: String!
|
||||
id: ID!
|
||||
}
|
||||
|
||||
type Notification {
|
||||
id: ID!
|
||||
actionType: ActionType!
|
||||
causedBy: NotificationCausedBy
|
||||
data: [NotificationData!]!
|
||||
createdAt: Time!
|
||||
}
|
||||
|
||||
type Notified {
|
||||
id: ID!
|
||||
notification: Notification!
|
||||
read: Boolean!
|
||||
readAt: Time
|
||||
}
|
||||
|
@ -1,92 +0,0 @@
|
||||
extend type Subscription {
|
||||
notificationAdded: Notified!
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
notifications: [Notified!]!
|
||||
notified(input: NotifiedInput!): NotifiedResult!
|
||||
hasUnreadNotifications: HasUnreadNotificationsResult!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
notificationToggleRead(input: NotificationToggleReadInput!): Notified!
|
||||
notificationMarkAllRead: NotificationMarkAllAsReadResult!
|
||||
}
|
||||
type NotificationMarkAllAsReadResult {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type HasUnreadNotificationsResult {
|
||||
unread: Boolean!
|
||||
}
|
||||
input NotificationToggleReadInput {
|
||||
notifiedID: UUID!
|
||||
}
|
||||
|
||||
input NotifiedInput {
|
||||
limit: Int!
|
||||
cursor: String
|
||||
filter: NotificationFilter!
|
||||
}
|
||||
|
||||
type PageInfo {
|
||||
endCursor: String
|
||||
hasNextPage: Boolean!
|
||||
}
|
||||
|
||||
type NotifiedResult {
|
||||
totalCount: Int!
|
||||
notified: [Notified!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
enum ActionType {
|
||||
TEAM_ADDED
|
||||
TEAM_REMOVED
|
||||
PROJECT_ADDED
|
||||
PROJECT_REMOVED
|
||||
PROJECT_ARCHIVED
|
||||
DUE_DATE_ADDED
|
||||
DUE_DATE_REMOVED
|
||||
DUE_DATE_CHANGED
|
||||
DUE_DATE_REMINDER
|
||||
TASK_ASSIGNED
|
||||
TASK_MOVED
|
||||
TASK_ARCHIVED
|
||||
TASK_ATTACHMENT_UPLOADED
|
||||
COMMENT_MENTIONED
|
||||
COMMENT_OTHER
|
||||
}
|
||||
|
||||
enum NotificationFilter {
|
||||
ALL
|
||||
UNREAD
|
||||
ASSIGNED
|
||||
MENTIONED
|
||||
}
|
||||
|
||||
type NotificationData {
|
||||
key: String!
|
||||
value: String!
|
||||
}
|
||||
|
||||
type NotificationCausedBy {
|
||||
fullname: String!
|
||||
username: String!
|
||||
id: ID!
|
||||
}
|
||||
|
||||
type Notification {
|
||||
id: ID!
|
||||
actionType: ActionType!
|
||||
causedBy: NotificationCausedBy
|
||||
data: [NotificationData!]!
|
||||
createdAt: Time!
|
||||
}
|
||||
|
||||
type Notified {
|
||||
id: ID!
|
||||
notification: Notification!
|
||||
read: Boolean!
|
||||
readAt: Time
|
||||
}
|
@ -1,194 +0,0 @@
|
||||
type ProjectPermission {
|
||||
team: RoleCode!
|
||||
project: RoleCode!
|
||||
org: RoleCode!
|
||||
}
|
||||
|
||||
type Project {
|
||||
id: ID!
|
||||
shortId: String!
|
||||
createdAt: Time!
|
||||
name: String!
|
||||
team: Team
|
||||
taskGroups: [TaskGroup!]!
|
||||
members: [Member!]!
|
||||
invitedMembers: [InvitedMember!]!
|
||||
publicOn: Time
|
||||
permission: ProjectPermission!
|
||||
labels: [ProjectLabel!]!
|
||||
}
|
||||
|
||||
type ProjectLabel {
|
||||
id: ID!
|
||||
createdDate: Time!
|
||||
labelColor: LabelColor!
|
||||
name: String
|
||||
}
|
||||
|
||||
type LabelColor {
|
||||
id: ID!
|
||||
name: String!
|
||||
position: Float!
|
||||
colorHex: String!
|
||||
}
|
||||
|
||||
type Member {
|
||||
id: ID!
|
||||
role: Role!
|
||||
fullName: String!
|
||||
username: String!
|
||||
profileIcon: ProfileIcon!
|
||||
owned: OwnedList!
|
||||
member: MemberList!
|
||||
}
|
||||
|
||||
type InvitedMember {
|
||||
email: String!
|
||||
invitedOn: Time!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createProjectLabel(input: NewProjectLabel!):
|
||||
ProjectLabel! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)
|
||||
deleteProjectLabel(input: DeleteProjectLabel!):
|
||||
ProjectLabel! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)
|
||||
updateProjectLabel(input: UpdateProjectLabel!):
|
||||
ProjectLabel! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)
|
||||
updateProjectLabelName(input: UpdateProjectLabelName!):
|
||||
ProjectLabel! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)
|
||||
updateProjectLabelColor(input: UpdateProjectLabelColor!):
|
||||
ProjectLabel! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)
|
||||
}
|
||||
|
||||
input NewProjectLabel {
|
||||
projectID: UUID!
|
||||
labelColorID: UUID!
|
||||
name: String
|
||||
}
|
||||
|
||||
input DeleteProjectLabel {
|
||||
projectLabelID: UUID!
|
||||
}
|
||||
|
||||
input UpdateProjectLabelName {
|
||||
projectLabelID: UUID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
input UpdateProjectLabel {
|
||||
projectLabelID: UUID!
|
||||
labelColorID: UUID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
input UpdateProjectLabelColor {
|
||||
projectLabelID: UUID!
|
||||
labelColorID: UUID!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
inviteProjectMembers(input: InviteProjectMembers!):
|
||||
InviteProjectMembersPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
deleteProjectMember(input: DeleteProjectMember!):
|
||||
DeleteProjectMemberPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
updateProjectMemberRole(input: UpdateProjectMemberRole!):
|
||||
UpdateProjectMemberRolePayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
|
||||
deleteInvitedProjectMember(input: DeleteInvitedProjectMember!):
|
||||
DeleteInvitedProjectMemberPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
}
|
||||
|
||||
input DeleteInvitedProjectMember {
|
||||
projectID: UUID!
|
||||
email: String!
|
||||
}
|
||||
|
||||
type DeleteInvitedProjectMemberPayload {
|
||||
invitedMember: InvitedMember!
|
||||
}
|
||||
|
||||
input MemberInvite {
|
||||
userID: UUID
|
||||
email: String
|
||||
}
|
||||
|
||||
input InviteProjectMembers {
|
||||
projectID: UUID!
|
||||
members: [MemberInvite!]!
|
||||
}
|
||||
|
||||
type InviteProjectMembersPayload {
|
||||
ok: Boolean!
|
||||
projectID: UUID!
|
||||
members: [Member!]!
|
||||
invitedMembers: [InvitedMember!]!
|
||||
}
|
||||
|
||||
input DeleteProjectMember {
|
||||
projectID: UUID!
|
||||
userID: UUID!
|
||||
}
|
||||
|
||||
type DeleteProjectMemberPayload {
|
||||
ok: Boolean!
|
||||
member: Member!
|
||||
projectID: UUID!
|
||||
}
|
||||
|
||||
input UpdateProjectMemberRole {
|
||||
projectID: UUID!
|
||||
userID: UUID!
|
||||
roleCode: RoleCode!
|
||||
}
|
||||
|
||||
type UpdateProjectMemberRolePayload {
|
||||
ok: Boolean!
|
||||
member: Member!
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
findProject(input: FindProject!): Project!
|
||||
}
|
||||
|
||||
input FindProject {
|
||||
projectID: UUID
|
||||
projectShortID: String
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createProject(input: NewProject!): Project! @hasRole(roles: [ADMIN], level: TEAM, type: TEAM)
|
||||
deleteProject(input: DeleteProject!):
|
||||
DeleteProjectPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
updateProjectName(input: UpdateProjectName):
|
||||
Project! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
toggleProjectVisibility(input: ToggleProjectVisibility!): ToggleProjectVisibilityPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
}
|
||||
|
||||
input ToggleProjectVisibility {
|
||||
projectID: UUID!
|
||||
isPublic: Boolean!
|
||||
}
|
||||
|
||||
type ToggleProjectVisibilityPayload {
|
||||
project: Project!
|
||||
}
|
||||
|
||||
input NewProject {
|
||||
teamID: UUID
|
||||
name: String!
|
||||
}
|
||||
|
||||
input UpdateProjectName {
|
||||
projectID: UUID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
input DeleteProject {
|
||||
projectID: UUID!
|
||||
}
|
||||
|
||||
type DeleteProjectPayload {
|
||||
ok: Boolean!
|
||||
project: Project!
|
||||
}
|
||||
|
@ -1,48 +0,0 @@
|
||||
type ProjectPermission {
|
||||
team: RoleCode!
|
||||
project: RoleCode!
|
||||
org: RoleCode!
|
||||
}
|
||||
|
||||
type Project {
|
||||
id: ID!
|
||||
shortId: String!
|
||||
createdAt: Time!
|
||||
name: String!
|
||||
team: Team
|
||||
taskGroups: [TaskGroup!]!
|
||||
members: [Member!]!
|
||||
invitedMembers: [InvitedMember!]!
|
||||
publicOn: Time
|
||||
permission: ProjectPermission!
|
||||
labels: [ProjectLabel!]!
|
||||
}
|
||||
|
||||
type ProjectLabel {
|
||||
id: ID!
|
||||
createdDate: Time!
|
||||
labelColor: LabelColor!
|
||||
name: String
|
||||
}
|
||||
|
||||
type LabelColor {
|
||||
id: ID!
|
||||
name: String!
|
||||
position: Float!
|
||||
colorHex: String!
|
||||
}
|
||||
|
||||
type Member {
|
||||
id: ID!
|
||||
role: Role!
|
||||
fullName: String!
|
||||
username: String!
|
||||
profileIcon: ProfileIcon!
|
||||
owned: OwnedList!
|
||||
member: MemberList!
|
||||
}
|
||||
|
||||
type InvitedMember {
|
||||
email: String!
|
||||
invitedOn: Time!
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
extend type Mutation {
|
||||
createProjectLabel(input: NewProjectLabel!):
|
||||
ProjectLabel! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)
|
||||
deleteProjectLabel(input: DeleteProjectLabel!):
|
||||
ProjectLabel! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)
|
||||
updateProjectLabel(input: UpdateProjectLabel!):
|
||||
ProjectLabel! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)
|
||||
updateProjectLabelName(input: UpdateProjectLabelName!):
|
||||
ProjectLabel! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)
|
||||
updateProjectLabelColor(input: UpdateProjectLabelColor!):
|
||||
ProjectLabel! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)
|
||||
}
|
||||
|
||||
input NewProjectLabel {
|
||||
projectID: UUID!
|
||||
labelColorID: UUID!
|
||||
name: String
|
||||
}
|
||||
|
||||
input DeleteProjectLabel {
|
||||
projectLabelID: UUID!
|
||||
}
|
||||
|
||||
input UpdateProjectLabelName {
|
||||
projectLabelID: UUID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
input UpdateProjectLabel {
|
||||
projectLabelID: UUID!
|
||||
labelColorID: UUID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
input UpdateProjectLabelColor {
|
||||
projectLabelID: UUID!
|
||||
labelColorID: UUID!
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
extend type Mutation {
|
||||
inviteProjectMembers(input: InviteProjectMembers!):
|
||||
InviteProjectMembersPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
deleteProjectMember(input: DeleteProjectMember!):
|
||||
DeleteProjectMemberPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
updateProjectMemberRole(input: UpdateProjectMemberRole!):
|
||||
UpdateProjectMemberRolePayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
|
||||
deleteInvitedProjectMember(input: DeleteInvitedProjectMember!):
|
||||
DeleteInvitedProjectMemberPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
}
|
||||
|
||||
input DeleteInvitedProjectMember {
|
||||
projectID: UUID!
|
||||
email: String!
|
||||
}
|
||||
|
||||
type DeleteInvitedProjectMemberPayload {
|
||||
invitedMember: InvitedMember!
|
||||
}
|
||||
|
||||
input MemberInvite {
|
||||
userID: UUID
|
||||
email: String
|
||||
}
|
||||
|
||||
input InviteProjectMembers {
|
||||
projectID: UUID!
|
||||
members: [MemberInvite!]!
|
||||
}
|
||||
|
||||
type InviteProjectMembersPayload {
|
||||
ok: Boolean!
|
||||
projectID: UUID!
|
||||
members: [Member!]!
|
||||
invitedMembers: [InvitedMember!]!
|
||||
}
|
||||
|
||||
input DeleteProjectMember {
|
||||
projectID: UUID!
|
||||
userID: UUID!
|
||||
}
|
||||
|
||||
type DeleteProjectMemberPayload {
|
||||
ok: Boolean!
|
||||
member: Member!
|
||||
projectID: UUID!
|
||||
}
|
||||
|
||||
input UpdateProjectMemberRole {
|
||||
projectID: UUID!
|
||||
userID: UUID!
|
||||
roleCode: RoleCode!
|
||||
}
|
||||
|
||||
type UpdateProjectMemberRolePayload {
|
||||
ok: Boolean!
|
||||
member: Member!
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
extend type Query {
|
||||
findProject(input: FindProject!): Project!
|
||||
}
|
||||
|
||||
input FindProject {
|
||||
projectID: UUID
|
||||
projectShortID: String
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createProject(input: NewProject!): Project! @hasRole(roles: [ADMIN], level: TEAM, type: TEAM)
|
||||
deleteProject(input: DeleteProject!):
|
||||
DeleteProjectPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
updateProjectName(input: UpdateProjectName):
|
||||
Project! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
toggleProjectVisibility(input: ToggleProjectVisibility!): ToggleProjectVisibilityPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
|
||||
}
|
||||
|
||||
input ToggleProjectVisibility {
|
||||
projectID: UUID!
|
||||
isPublic: Boolean!
|
||||
}
|
||||
|
||||
type ToggleProjectVisibilityPayload {
|
||||
project: Project!
|
||||
}
|
||||
|
||||
input NewProject {
|
||||
teamID: UUID
|
||||
name: String!
|
||||
}
|
||||
|
||||
input UpdateProjectName {
|
||||
projectID: UUID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
input DeleteProject {
|
||||
projectID: UUID!
|
||||
}
|
||||
|
||||
type DeleteProjectPayload {
|
||||
ok: Boolean!
|
||||
project: Project!
|
||||
}
|
@ -1,151 +0,0 @@
|
||||
scalar Time
|
||||
scalar UUID
|
||||
scalar Upload
|
||||
|
||||
enum RoleCode {
|
||||
owner
|
||||
admin
|
||||
member
|
||||
observer
|
||||
}
|
||||
|
||||
type Role {
|
||||
code: String!
|
||||
name: String!
|
||||
}
|
||||
|
||||
type ProfileIcon {
|
||||
url: String
|
||||
initials: String
|
||||
bgColor: String
|
||||
}
|
||||
|
||||
type OwnersList {
|
||||
projects: [UUID!]!
|
||||
teams: [UUID!]!
|
||||
}
|
||||
|
||||
type OwnedList {
|
||||
teams: [Team!]!
|
||||
projects: [Project!]!
|
||||
}
|
||||
|
||||
type MemberList {
|
||||
teams: [Team!]!
|
||||
projects: [Project!]!
|
||||
}
|
||||
|
||||
type Organization {
|
||||
id: ID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
enum ShareStatus {
|
||||
INVITED
|
||||
JOINED
|
||||
}
|
||||
|
||||
enum RoleLevel {
|
||||
ADMIN
|
||||
MEMBER
|
||||
}
|
||||
|
||||
enum ActionLevel {
|
||||
ORG
|
||||
TEAM
|
||||
PROJECT
|
||||
}
|
||||
|
||||
enum ObjectType {
|
||||
ORG
|
||||
TEAM
|
||||
PROJECT
|
||||
TASK
|
||||
TASK_GROUP
|
||||
TASK_CHECKLIST
|
||||
TASK_CHECKLIST_ITEM
|
||||
}
|
||||
|
||||
directive @hasRole(roles: [RoleLevel!]!, level: ActionLevel!, type: ObjectType!) on FIELD_DEFINITION
|
||||
|
||||
directive @requiresUser on FIELD_DEFINITION
|
||||
|
||||
type Query {
|
||||
organizations: [Organization!]!
|
||||
users: [UserAccount!]!
|
||||
invitedUsers: [InvitedUserAccount!]!
|
||||
findUser(input: FindUser!): UserAccount!
|
||||
projects(input: ProjectsFilter): [Project!]!
|
||||
teams: [Team!]!
|
||||
findTeam(input: FindTeam!): Team!
|
||||
myTasks(input: MyTasks!): MyTasksPayload!
|
||||
labelColors: [LabelColor!]!
|
||||
taskGroups: [TaskGroup!]!
|
||||
me: MePayload
|
||||
}
|
||||
|
||||
|
||||
type Subscription
|
||||
type Mutation
|
||||
|
||||
enum MyTasksStatus {
|
||||
ALL
|
||||
INCOMPLETE
|
||||
COMPLETE_ALL
|
||||
COMPLETE_TODAY
|
||||
COMPLETE_YESTERDAY
|
||||
COMPLETE_ONE_WEEK
|
||||
COMPLETE_TWO_WEEK
|
||||
COMPLETE_THREE_WEEK
|
||||
}
|
||||
|
||||
enum MyTasksSort {
|
||||
NONE
|
||||
PROJECT
|
||||
DUE_DATE
|
||||
}
|
||||
|
||||
input MyTasks {
|
||||
status: MyTasksStatus!
|
||||
sort: MyTasksSort!
|
||||
}
|
||||
|
||||
type ProjectTaskMapping {
|
||||
projectID: UUID!
|
||||
taskID: UUID!
|
||||
}
|
||||
|
||||
type MyTasksPayload {
|
||||
tasks: [Task!]!
|
||||
projects: [ProjectTaskMapping!]!
|
||||
}
|
||||
|
||||
type TeamRole {
|
||||
teamID: UUID!
|
||||
roleCode: RoleCode!
|
||||
}
|
||||
|
||||
type ProjectRole {
|
||||
projectID: UUID!
|
||||
roleCode: RoleCode!
|
||||
}
|
||||
|
||||
type MePayload {
|
||||
user: UserAccount!
|
||||
organization: RoleCode
|
||||
teamRoles: [TeamRole!]!
|
||||
projectRoles: [ProjectRole!]!
|
||||
}
|
||||
|
||||
input ProjectsFilter {
|
||||
teamID: UUID
|
||||
}
|
||||
|
||||
input FindUser {
|
||||
userID: UUID!
|
||||
}
|
||||
|
||||
|
||||
input FindTeam {
|
||||
teamID: UUID!
|
||||
}
|
@ -1,491 +0,0 @@
|
||||
enum DueDateNotificationDuration {
|
||||
MINUTE
|
||||
HOUR
|
||||
DAY
|
||||
WEEK
|
||||
}
|
||||
|
||||
type TaskLabel {
|
||||
id: ID!
|
||||
projectLabel: ProjectLabel!
|
||||
assignedDate: Time!
|
||||
}
|
||||
|
||||
type ChecklistBadge {
|
||||
complete: Int!
|
||||
total: Int!
|
||||
}
|
||||
|
||||
type CommentsBadge {
|
||||
total: Int!
|
||||
unread: Boolean!
|
||||
}
|
||||
|
||||
type TaskBadges {
|
||||
checklist: ChecklistBadge
|
||||
comments: CommentsBadge
|
||||
}
|
||||
|
||||
type DueDateNotification {
|
||||
id: ID!
|
||||
period: Int!
|
||||
duration: DueDateNotificationDuration!
|
||||
}
|
||||
|
||||
type DueDate {
|
||||
at: Time
|
||||
notifications: [DueDateNotification!]!
|
||||
}
|
||||
|
||||
|
||||
type Task {
|
||||
id: ID!
|
||||
shortId: String!
|
||||
taskGroup: TaskGroup!
|
||||
createdAt: Time!
|
||||
name: String!
|
||||
position: Float!
|
||||
description: String
|
||||
watched: Boolean!
|
||||
dueDate: DueDate!
|
||||
hasTime: Boolean!
|
||||
complete: Boolean!
|
||||
completedAt: Time
|
||||
assigned: [Member!]!
|
||||
labels: [TaskLabel!]!
|
||||
checklists: [TaskChecklist!]!
|
||||
badges: TaskBadges!
|
||||
activity: [TaskActivity!]!
|
||||
comments: [TaskComment!]!
|
||||
}
|
||||
|
||||
type TaskActivityData {
|
||||
name: String!
|
||||
value: String!
|
||||
}
|
||||
|
||||
enum ActivityType {
|
||||
TASK_ADDED
|
||||
TASK_MOVED
|
||||
TASK_MARKED_COMPLETE
|
||||
TASK_MARKED_INCOMPLETE
|
||||
TASK_DUE_DATE_CHANGED
|
||||
TASK_DUE_DATE_ADDED
|
||||
TASK_DUE_DATE_REMOVED
|
||||
TASK_CHECKLIST_CHANGED
|
||||
TASK_CHECKLIST_ADDED
|
||||
TASK_CHECKLIST_REMOVED
|
||||
}
|
||||
|
||||
type TaskActivity {
|
||||
id: ID!
|
||||
type: ActivityType!
|
||||
data: [TaskActivityData!]!
|
||||
causedBy: CausedBy!
|
||||
createdAt: Time!
|
||||
}
|
||||
|
||||
type CausedBy {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
profileIcon: ProfileIcon
|
||||
}
|
||||
|
||||
|
||||
type CreatedBy {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
profileIcon: ProfileIcon!
|
||||
}
|
||||
|
||||
type TaskComment {
|
||||
id: ID!
|
||||
createdAt: Time!
|
||||
updatedAt: Time
|
||||
message: String!
|
||||
createdBy: CreatedBy!
|
||||
pinned: Boolean!
|
||||
}
|
||||
|
||||
type TaskChecklistItem {
|
||||
id: ID!
|
||||
name: String!
|
||||
taskChecklistID: UUID!
|
||||
complete: Boolean!
|
||||
position: Float!
|
||||
dueDate: Time!
|
||||
}
|
||||
|
||||
type TaskChecklist {
|
||||
id: ID!
|
||||
name: String!
|
||||
position: Float!
|
||||
items: [TaskChecklistItem!]!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createTaskChecklist(input: CreateTaskChecklist!):
|
||||
TaskChecklist! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
deleteTaskChecklist(input: DeleteTaskChecklist!):
|
||||
DeleteTaskChecklistPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST)
|
||||
updateTaskChecklistName(input: UpdateTaskChecklistName!):
|
||||
TaskChecklist! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST)
|
||||
createTaskChecklistItem(input: CreateTaskChecklistItem!):
|
||||
TaskChecklistItem! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST)
|
||||
updateTaskChecklistLocation(input: UpdateTaskChecklistLocation!):
|
||||
UpdateTaskChecklistLocationPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST)
|
||||
|
||||
updateTaskChecklistItemName(input: UpdateTaskChecklistItemName!):
|
||||
TaskChecklistItem! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST_ITEM)
|
||||
setTaskChecklistItemComplete(input: SetTaskChecklistItemComplete!):
|
||||
TaskChecklistItem! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST_ITEM)
|
||||
deleteTaskChecklistItem(input: DeleteTaskChecklistItem!):
|
||||
DeleteTaskChecklistItemPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST_ITEM)
|
||||
updateTaskChecklistItemLocation(input: UpdateTaskChecklistItemLocation!):
|
||||
UpdateTaskChecklistItemLocationPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST_ITEM)
|
||||
|
||||
}
|
||||
|
||||
input UpdateTaskChecklistItemLocation {
|
||||
taskChecklistID: UUID!
|
||||
taskChecklistItemID: UUID!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type UpdateTaskChecklistItemLocationPayload {
|
||||
taskChecklistID: UUID!
|
||||
prevChecklistID: UUID!
|
||||
checklistItem: TaskChecklistItem!
|
||||
}
|
||||
|
||||
input UpdateTaskChecklistLocation {
|
||||
taskChecklistID: UUID!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type UpdateTaskChecklistLocationPayload {
|
||||
checklist: TaskChecklist!
|
||||
}
|
||||
|
||||
input CreateTaskChecklist {
|
||||
taskID: UUID!
|
||||
name: String!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type DeleteTaskChecklistItemPayload {
|
||||
ok: Boolean!
|
||||
taskChecklistItem: TaskChecklistItem!
|
||||
}
|
||||
|
||||
input CreateTaskChecklistItem {
|
||||
taskChecklistID: UUID!
|
||||
name: String!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
input SetTaskChecklistItemComplete {
|
||||
taskChecklistItemID: UUID!
|
||||
complete: Boolean!
|
||||
}
|
||||
|
||||
input DeleteTaskChecklistItem {
|
||||
taskChecklistItemID: UUID!
|
||||
}
|
||||
|
||||
input UpdateTaskChecklistItemName {
|
||||
taskChecklistItemID: UUID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
input UpdateTaskChecklistName {
|
||||
taskChecklistID: UUID!
|
||||
name: String!
|
||||
}
|
||||
input DeleteTaskChecklist {
|
||||
taskChecklistID: UUID!
|
||||
}
|
||||
type DeleteTaskChecklistPayload {
|
||||
ok: Boolean!
|
||||
taskChecklist: TaskChecklist!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createTaskComment(input: CreateTaskComment):
|
||||
CreateTaskCommentPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
deleteTaskComment(input: DeleteTaskComment):
|
||||
DeleteTaskCommentPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
updateTaskComment(input: UpdateTaskComment):
|
||||
UpdateTaskCommentPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
}
|
||||
|
||||
input CreateTaskComment {
|
||||
taskID: UUID!
|
||||
message: String!
|
||||
}
|
||||
|
||||
type CreateTaskCommentPayload {
|
||||
taskID: UUID!
|
||||
comment: TaskComment!
|
||||
}
|
||||
|
||||
input UpdateTaskComment {
|
||||
commentID: UUID!
|
||||
message: String!
|
||||
}
|
||||
|
||||
type UpdateTaskCommentPayload {
|
||||
taskID: UUID!
|
||||
comment: TaskComment!
|
||||
}
|
||||
|
||||
input DeleteTaskComment {
|
||||
commentID: UUID!
|
||||
}
|
||||
|
||||
type DeleteTaskCommentPayload {
|
||||
taskID: UUID!
|
||||
commentID: UUID!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createTaskGroup(input: NewTaskGroup!):
|
||||
TaskGroup! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)
|
||||
updateTaskGroupLocation(input: NewTaskGroupLocation!):
|
||||
TaskGroup! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
updateTaskGroupName(input: UpdateTaskGroupName!):
|
||||
TaskGroup! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
deleteTaskGroup(input: DeleteTaskGroupInput!):
|
||||
DeleteTaskGroupPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
duplicateTaskGroup(input: DuplicateTaskGroup!):
|
||||
DuplicateTaskGroupPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
sortTaskGroup(input: SortTaskGroup!):
|
||||
SortTaskGroupPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
deleteTaskGroupTasks(input: DeleteTaskGroupTasks!):
|
||||
DeleteTaskGroupTasksPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
}
|
||||
|
||||
input DeleteTaskGroupTasks {
|
||||
taskGroupID: UUID!
|
||||
}
|
||||
|
||||
type DeleteTaskGroupTasksPayload {
|
||||
taskGroupID: UUID!
|
||||
tasks: [UUID!]!
|
||||
}
|
||||
|
||||
input TaskPositionUpdate {
|
||||
taskID: UUID!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type SortTaskGroupPayload {
|
||||
taskGroupID: UUID!
|
||||
tasks: [Task!]!
|
||||
}
|
||||
|
||||
input SortTaskGroup {
|
||||
taskGroupID: UUID!
|
||||
tasks: [TaskPositionUpdate!]!
|
||||
}
|
||||
|
||||
input DuplicateTaskGroup {
|
||||
projectID: UUID!
|
||||
taskGroupID: UUID!
|
||||
name: String!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type DuplicateTaskGroupPayload {
|
||||
taskGroup: TaskGroup!
|
||||
}
|
||||
|
||||
input NewTaskGroupLocation {
|
||||
taskGroupID: UUID!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
input UpdateTaskGroupName {
|
||||
taskGroupID: UUID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
input DeleteTaskGroupInput {
|
||||
taskGroupID: UUID!
|
||||
}
|
||||
|
||||
type DeleteTaskGroupPayload {
|
||||
ok: Boolean!
|
||||
affectedRows: Int!
|
||||
taskGroup: TaskGroup!
|
||||
}
|
||||
|
||||
input NewTaskGroup {
|
||||
projectID: UUID!
|
||||
name: String!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
addTaskLabel(input: AddTaskLabelInput):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
removeTaskLabel(input: RemoveTaskLabelInput):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
toggleTaskLabel(input: ToggleTaskLabelInput!):
|
||||
ToggleTaskLabelPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
|
||||
}
|
||||
|
||||
input AddTaskLabelInput {
|
||||
taskID: UUID!
|
||||
projectLabelID: UUID!
|
||||
}
|
||||
|
||||
input RemoveTaskLabelInput {
|
||||
taskID: UUID!
|
||||
taskLabelID: UUID!
|
||||
}
|
||||
|
||||
input ToggleTaskLabelInput {
|
||||
taskID: UUID!
|
||||
projectLabelID: UUID!
|
||||
}
|
||||
|
||||
type ToggleTaskLabelPayload {
|
||||
active: Boolean!
|
||||
task: Task!
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
findTask(input: FindTask!): Task!
|
||||
}
|
||||
|
||||
input FindTask {
|
||||
taskID: UUID
|
||||
taskShortID: String
|
||||
}
|
||||
|
||||
|
||||
extend type Mutation {
|
||||
createTask(input: NewTask!):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
deleteTask(input: DeleteTaskInput!):
|
||||
DeleteTaskPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
|
||||
updateTaskDescription(input: UpdateTaskDescriptionInput!):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
updateTaskLocation(input: NewTaskLocation!):
|
||||
UpdateTaskLocationPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
updateTaskName(input: UpdateTaskName!):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
setTaskComplete(input: SetTaskComplete!):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
updateTaskDueDate(input: UpdateTaskDueDate!):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
toggleTaskWatch(input: ToggleTaskWatch!):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
|
||||
assignTask(input: AssignTaskInput):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
unassignTask(input: UnassignTaskInput):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
|
||||
|
||||
createTaskDueDateNotifications(input: [CreateTaskDueDateNotification!]!):
|
||||
CreateTaskDueDateNotificationsResult!
|
||||
updateTaskDueDateNotifications(input: [UpdateTaskDueDateNotification!]!):
|
||||
UpdateTaskDueDateNotificationsResult!
|
||||
deleteTaskDueDateNotifications(input: [DeleteTaskDueDateNotification!]!):
|
||||
DeleteTaskDueDateNotificationsResult!
|
||||
}
|
||||
|
||||
input DeleteTaskDueDateNotification {
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
type DeleteTaskDueDateNotificationsResult {
|
||||
notifications: [UUID!]!
|
||||
}
|
||||
|
||||
input UpdateTaskDueDateNotification {
|
||||
id: UUID!
|
||||
period: Int!
|
||||
duration: DueDateNotificationDuration!
|
||||
}
|
||||
|
||||
type UpdateTaskDueDateNotificationsResult {
|
||||
notifications: [DueDateNotification!]!
|
||||
}
|
||||
|
||||
input CreateTaskDueDateNotification {
|
||||
taskID: UUID!
|
||||
period: Int!
|
||||
duration: DueDateNotificationDuration!
|
||||
}
|
||||
|
||||
type CreateTaskDueDateNotificationsResult {
|
||||
notifications: [DueDateNotification!]!
|
||||
}
|
||||
|
||||
|
||||
input ToggleTaskWatch {
|
||||
taskID: UUID!
|
||||
}
|
||||
|
||||
input NewTask {
|
||||
taskGroupID: UUID!
|
||||
name: String!
|
||||
position: Float!
|
||||
assigned: [UUID!]
|
||||
}
|
||||
|
||||
input AssignTaskInput {
|
||||
taskID: UUID!
|
||||
userID: UUID!
|
||||
}
|
||||
|
||||
input UnassignTaskInput {
|
||||
taskID: UUID!
|
||||
userID: UUID!
|
||||
}
|
||||
|
||||
input UpdateTaskDescriptionInput {
|
||||
taskID: UUID!
|
||||
description: String!
|
||||
}
|
||||
|
||||
type UpdateTaskLocationPayload {
|
||||
previousTaskGroupID: UUID!
|
||||
task: Task!
|
||||
}
|
||||
|
||||
input UpdateTaskDueDate {
|
||||
taskID: UUID!
|
||||
hasTime: Boolean!
|
||||
dueDate: Time
|
||||
}
|
||||
|
||||
input SetTaskComplete {
|
||||
taskID: UUID!
|
||||
complete: Boolean!
|
||||
}
|
||||
|
||||
input NewTaskLocation {
|
||||
taskID: UUID!
|
||||
taskGroupID: UUID!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
input DeleteTaskInput {
|
||||
taskID: UUID!
|
||||
}
|
||||
|
||||
type DeleteTaskPayload {
|
||||
taskID: UUID!
|
||||
}
|
||||
|
||||
input UpdateTaskName {
|
||||
taskID: UUID!
|
||||
name: String!
|
||||
}
|
||||
|
@ -1,124 +0,0 @@
|
||||
enum DueDateNotificationDuration {
|
||||
MINUTE
|
||||
HOUR
|
||||
DAY
|
||||
WEEK
|
||||
}
|
||||
|
||||
type TaskLabel {
|
||||
id: ID!
|
||||
projectLabel: ProjectLabel!
|
||||
assignedDate: Time!
|
||||
}
|
||||
|
||||
type ChecklistBadge {
|
||||
complete: Int!
|
||||
total: Int!
|
||||
}
|
||||
|
||||
type CommentsBadge {
|
||||
total: Int!
|
||||
unread: Boolean!
|
||||
}
|
||||
|
||||
type TaskBadges {
|
||||
checklist: ChecklistBadge
|
||||
comments: CommentsBadge
|
||||
}
|
||||
|
||||
type DueDateNotification {
|
||||
id: ID!
|
||||
period: Int!
|
||||
duration: DueDateNotificationDuration!
|
||||
}
|
||||
|
||||
type DueDate {
|
||||
at: Time
|
||||
notifications: [DueDateNotification!]!
|
||||
}
|
||||
|
||||
|
||||
type Task {
|
||||
id: ID!
|
||||
shortId: String!
|
||||
taskGroup: TaskGroup!
|
||||
createdAt: Time!
|
||||
name: String!
|
||||
position: Float!
|
||||
description: String
|
||||
watched: Boolean!
|
||||
dueDate: DueDate!
|
||||
hasTime: Boolean!
|
||||
complete: Boolean!
|
||||
completedAt: Time
|
||||
assigned: [Member!]!
|
||||
labels: [TaskLabel!]!
|
||||
checklists: [TaskChecklist!]!
|
||||
badges: TaskBadges!
|
||||
activity: [TaskActivity!]!
|
||||
comments: [TaskComment!]!
|
||||
}
|
||||
|
||||
type TaskActivityData {
|
||||
name: String!
|
||||
value: String!
|
||||
}
|
||||
|
||||
enum ActivityType {
|
||||
TASK_ADDED
|
||||
TASK_MOVED
|
||||
TASK_MARKED_COMPLETE
|
||||
TASK_MARKED_INCOMPLETE
|
||||
TASK_DUE_DATE_CHANGED
|
||||
TASK_DUE_DATE_ADDED
|
||||
TASK_DUE_DATE_REMOVED
|
||||
TASK_CHECKLIST_CHANGED
|
||||
TASK_CHECKLIST_ADDED
|
||||
TASK_CHECKLIST_REMOVED
|
||||
}
|
||||
|
||||
type TaskActivity {
|
||||
id: ID!
|
||||
type: ActivityType!
|
||||
data: [TaskActivityData!]!
|
||||
causedBy: CausedBy!
|
||||
createdAt: Time!
|
||||
}
|
||||
|
||||
type CausedBy {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
profileIcon: ProfileIcon
|
||||
}
|
||||
|
||||
|
||||
type CreatedBy {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
profileIcon: ProfileIcon!
|
||||
}
|
||||
|
||||
type TaskComment {
|
||||
id: ID!
|
||||
createdAt: Time!
|
||||
updatedAt: Time
|
||||
message: String!
|
||||
createdBy: CreatedBy!
|
||||
pinned: Boolean!
|
||||
}
|
||||
|
||||
type TaskChecklistItem {
|
||||
id: ID!
|
||||
name: String!
|
||||
taskChecklistID: UUID!
|
||||
complete: Boolean!
|
||||
position: Float!
|
||||
dueDate: Time!
|
||||
}
|
||||
|
||||
type TaskChecklist {
|
||||
id: ID!
|
||||
name: String!
|
||||
position: Float!
|
||||
items: [TaskChecklistItem!]!
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
extend type Mutation {
|
||||
createTaskChecklist(input: CreateTaskChecklist!):
|
||||
TaskChecklist! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
deleteTaskChecklist(input: DeleteTaskChecklist!):
|
||||
DeleteTaskChecklistPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST)
|
||||
updateTaskChecklistName(input: UpdateTaskChecklistName!):
|
||||
TaskChecklist! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST)
|
||||
createTaskChecklistItem(input: CreateTaskChecklistItem!):
|
||||
TaskChecklistItem! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST)
|
||||
updateTaskChecklistLocation(input: UpdateTaskChecklistLocation!):
|
||||
UpdateTaskChecklistLocationPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST)
|
||||
|
||||
updateTaskChecklistItemName(input: UpdateTaskChecklistItemName!):
|
||||
TaskChecklistItem! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST_ITEM)
|
||||
setTaskChecklistItemComplete(input: SetTaskChecklistItemComplete!):
|
||||
TaskChecklistItem! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST_ITEM)
|
||||
deleteTaskChecklistItem(input: DeleteTaskChecklistItem!):
|
||||
DeleteTaskChecklistItemPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST_ITEM)
|
||||
updateTaskChecklistItemLocation(input: UpdateTaskChecklistItemLocation!):
|
||||
UpdateTaskChecklistItemLocationPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_CHECKLIST_ITEM)
|
||||
|
||||
}
|
||||
|
||||
input UpdateTaskChecklistItemLocation {
|
||||
taskChecklistID: UUID!
|
||||
taskChecklistItemID: UUID!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type UpdateTaskChecklistItemLocationPayload {
|
||||
taskChecklistID: UUID!
|
||||
prevChecklistID: UUID!
|
||||
checklistItem: TaskChecklistItem!
|
||||
}
|
||||
|
||||
input UpdateTaskChecklistLocation {
|
||||
taskChecklistID: UUID!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type UpdateTaskChecklistLocationPayload {
|
||||
checklist: TaskChecklist!
|
||||
}
|
||||
|
||||
input CreateTaskChecklist {
|
||||
taskID: UUID!
|
||||
name: String!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type DeleteTaskChecklistItemPayload {
|
||||
ok: Boolean!
|
||||
taskChecklistItem: TaskChecklistItem!
|
||||
}
|
||||
|
||||
input CreateTaskChecklistItem {
|
||||
taskChecklistID: UUID!
|
||||
name: String!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
input SetTaskChecklistItemComplete {
|
||||
taskChecklistItemID: UUID!
|
||||
complete: Boolean!
|
||||
}
|
||||
|
||||
input DeleteTaskChecklistItem {
|
||||
taskChecklistItemID: UUID!
|
||||
}
|
||||
|
||||
input UpdateTaskChecklistItemName {
|
||||
taskChecklistItemID: UUID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
input UpdateTaskChecklistName {
|
||||
taskChecklistID: UUID!
|
||||
name: String!
|
||||
}
|
||||
input DeleteTaskChecklist {
|
||||
taskChecklistID: UUID!
|
||||
}
|
||||
type DeleteTaskChecklistPayload {
|
||||
ok: Boolean!
|
||||
taskChecklist: TaskChecklist!
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
extend type Mutation {
|
||||
createTaskComment(input: CreateTaskComment):
|
||||
CreateTaskCommentPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
deleteTaskComment(input: DeleteTaskComment):
|
||||
DeleteTaskCommentPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
updateTaskComment(input: UpdateTaskComment):
|
||||
UpdateTaskCommentPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
}
|
||||
|
||||
input CreateTaskComment {
|
||||
taskID: UUID!
|
||||
message: String!
|
||||
}
|
||||
|
||||
type CreateTaskCommentPayload {
|
||||
taskID: UUID!
|
||||
comment: TaskComment!
|
||||
}
|
||||
|
||||
input UpdateTaskComment {
|
||||
commentID: UUID!
|
||||
message: String!
|
||||
}
|
||||
|
||||
type UpdateTaskCommentPayload {
|
||||
taskID: UUID!
|
||||
comment: TaskComment!
|
||||
}
|
||||
|
||||
input DeleteTaskComment {
|
||||
commentID: UUID!
|
||||
}
|
||||
|
||||
type DeleteTaskCommentPayload {
|
||||
taskID: UUID!
|
||||
commentID: UUID!
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
extend type Mutation {
|
||||
createTaskGroup(input: NewTaskGroup!):
|
||||
TaskGroup! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: PROJECT)
|
||||
updateTaskGroupLocation(input: NewTaskGroupLocation!):
|
||||
TaskGroup! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
updateTaskGroupName(input: UpdateTaskGroupName!):
|
||||
TaskGroup! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
deleteTaskGroup(input: DeleteTaskGroupInput!):
|
||||
DeleteTaskGroupPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
duplicateTaskGroup(input: DuplicateTaskGroup!):
|
||||
DuplicateTaskGroupPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
sortTaskGroup(input: SortTaskGroup!):
|
||||
SortTaskGroupPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
deleteTaskGroupTasks(input: DeleteTaskGroupTasks!):
|
||||
DeleteTaskGroupTasksPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
}
|
||||
|
||||
input DeleteTaskGroupTasks {
|
||||
taskGroupID: UUID!
|
||||
}
|
||||
|
||||
type DeleteTaskGroupTasksPayload {
|
||||
taskGroupID: UUID!
|
||||
tasks: [UUID!]!
|
||||
}
|
||||
|
||||
input TaskPositionUpdate {
|
||||
taskID: UUID!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type SortTaskGroupPayload {
|
||||
taskGroupID: UUID!
|
||||
tasks: [Task!]!
|
||||
}
|
||||
|
||||
input SortTaskGroup {
|
||||
taskGroupID: UUID!
|
||||
tasks: [TaskPositionUpdate!]!
|
||||
}
|
||||
|
||||
input DuplicateTaskGroup {
|
||||
projectID: UUID!
|
||||
taskGroupID: UUID!
|
||||
name: String!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
type DuplicateTaskGroupPayload {
|
||||
taskGroup: TaskGroup!
|
||||
}
|
||||
|
||||
input NewTaskGroupLocation {
|
||||
taskGroupID: UUID!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
input UpdateTaskGroupName {
|
||||
taskGroupID: UUID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
input DeleteTaskGroupInput {
|
||||
taskGroupID: UUID!
|
||||
}
|
||||
|
||||
type DeleteTaskGroupPayload {
|
||||
ok: Boolean!
|
||||
affectedRows: Int!
|
||||
taskGroup: TaskGroup!
|
||||
}
|
||||
|
||||
input NewTaskGroup {
|
||||
projectID: UUID!
|
||||
name: String!
|
||||
position: Float!
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
extend type Mutation {
|
||||
addTaskLabel(input: AddTaskLabelInput):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
removeTaskLabel(input: RemoveTaskLabelInput):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
toggleTaskLabel(input: ToggleTaskLabelInput!):
|
||||
ToggleTaskLabelPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
|
||||
}
|
||||
|
||||
input AddTaskLabelInput {
|
||||
taskID: UUID!
|
||||
projectLabelID: UUID!
|
||||
}
|
||||
|
||||
input RemoveTaskLabelInput {
|
||||
taskID: UUID!
|
||||
taskLabelID: UUID!
|
||||
}
|
||||
|
||||
input ToggleTaskLabelInput {
|
||||
taskID: UUID!
|
||||
projectLabelID: UUID!
|
||||
}
|
||||
|
||||
type ToggleTaskLabelPayload {
|
||||
active: Boolean!
|
||||
task: Task!
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
extend type Query {
|
||||
findTask(input: FindTask!): Task!
|
||||
}
|
||||
|
||||
input FindTask {
|
||||
taskID: UUID
|
||||
taskShortID: String
|
||||
}
|
||||
|
||||
|
||||
extend type Mutation {
|
||||
createTask(input: NewTask!):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK_GROUP)
|
||||
deleteTask(input: DeleteTaskInput!):
|
||||
DeleteTaskPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
|
||||
updateTaskDescription(input: UpdateTaskDescriptionInput!):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
updateTaskLocation(input: NewTaskLocation!):
|
||||
UpdateTaskLocationPayload! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
updateTaskName(input: UpdateTaskName!):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
setTaskComplete(input: SetTaskComplete!):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
updateTaskDueDate(input: UpdateTaskDueDate!):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
toggleTaskWatch(input: ToggleTaskWatch!):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
|
||||
assignTask(input: AssignTaskInput):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
unassignTask(input: UnassignTaskInput):
|
||||
Task! @hasRole(roles: [ADMIN, MEMBER], level: PROJECT, type: TASK)
|
||||
|
||||
|
||||
createTaskDueDateNotifications(input: [CreateTaskDueDateNotification!]!):
|
||||
CreateTaskDueDateNotificationsResult!
|
||||
updateTaskDueDateNotifications(input: [UpdateTaskDueDateNotification!]!):
|
||||
UpdateTaskDueDateNotificationsResult!
|
||||
deleteTaskDueDateNotifications(input: [DeleteTaskDueDateNotification!]!):
|
||||
DeleteTaskDueDateNotificationsResult!
|
||||
}
|
||||
|
||||
input DeleteTaskDueDateNotification {
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
type DeleteTaskDueDateNotificationsResult {
|
||||
notifications: [UUID!]!
|
||||
}
|
||||
|
||||
input UpdateTaskDueDateNotification {
|
||||
id: UUID!
|
||||
period: Int!
|
||||
duration: DueDateNotificationDuration!
|
||||
}
|
||||
|
||||
type UpdateTaskDueDateNotificationsResult {
|
||||
notifications: [DueDateNotification!]!
|
||||
}
|
||||
|
||||
input CreateTaskDueDateNotification {
|
||||
taskID: UUID!
|
||||
period: Int!
|
||||
duration: DueDateNotificationDuration!
|
||||
}
|
||||
|
||||
type CreateTaskDueDateNotificationsResult {
|
||||
notifications: [DueDateNotification!]!
|
||||
}
|
||||
|
||||
|
||||
input ToggleTaskWatch {
|
||||
taskID: UUID!
|
||||
}
|
||||
|
||||
input NewTask {
|
||||
taskGroupID: UUID!
|
||||
name: String!
|
||||
position: Float!
|
||||
assigned: [UUID!]
|
||||
}
|
||||
|
||||
input AssignTaskInput {
|
||||
taskID: UUID!
|
||||
userID: UUID!
|
||||
}
|
||||
|
||||
input UnassignTaskInput {
|
||||
taskID: UUID!
|
||||
userID: UUID!
|
||||
}
|
||||
|
||||
input UpdateTaskDescriptionInput {
|
||||
taskID: UUID!
|
||||
description: String!
|
||||
}
|
||||
|
||||
type UpdateTaskLocationPayload {
|
||||
previousTaskGroupID: UUID!
|
||||
task: Task!
|
||||
}
|
||||
|
||||
input UpdateTaskDueDate {
|
||||
taskID: UUID!
|
||||
hasTime: Boolean!
|
||||
dueDate: Time
|
||||
}
|
||||
|
||||
input SetTaskComplete {
|
||||
taskID: UUID!
|
||||
complete: Boolean!
|
||||
}
|
||||
|
||||
input NewTaskLocation {
|
||||
taskID: UUID!
|
||||
taskGroupID: UUID!
|
||||
position: Float!
|
||||
}
|
||||
|
||||
input DeleteTaskInput {
|
||||
taskID: UUID!
|
||||
}
|
||||
|
||||
type DeleteTaskPayload {
|
||||
taskID: UUID!
|
||||
}
|
||||
|
||||
input UpdateTaskName {
|
||||
taskID: UUID!
|
||||
name: String!
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
type TaskGroup {
|
||||
id: ID!
|
||||
projectID: String!
|
||||
createdAt: Time!
|
||||
name: String!
|
||||
position: Float!
|
||||
tasks: [Task!]!
|
||||
}
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
type TaskGroup {
|
||||
id: ID!
|
||||
projectID: String!
|
||||
createdAt: Time!
|
||||
name: String!
|
||||
position: Float!
|
||||
tasks: [Task!]!
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
type Team {
|
||||
id: ID!
|
||||
createdAt: Time!
|
||||
name: String!
|
||||
permission: TeamPermission!
|
||||
members: [Member!]!
|
||||
}
|
||||
|
||||
type TeamPermission {
|
||||
team: RoleCode!
|
||||
org: RoleCode!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createTeamMember(input: CreateTeamMember!):
|
||||
CreateTeamMemberPayload! @hasRole(roles: [ADMIN], level: TEAM, type: TEAM)
|
||||
updateTeamMemberRole(input: UpdateTeamMemberRole!):
|
||||
UpdateTeamMemberRolePayload! @hasRole(roles: [ADMIN], level: TEAM, type: TEAM)
|
||||
deleteTeamMember(input: DeleteTeamMember!):
|
||||
DeleteTeamMemberPayload! @hasRole(roles: [ADMIN], level: TEAM, type: TEAM)
|
||||
|
||||
}
|
||||
|
||||
input DeleteTeamMember {
|
||||
teamID: UUID!
|
||||
userID: UUID!
|
||||
newOwnerID: UUID
|
||||
}
|
||||
|
||||
type DeleteTeamMemberPayload {
|
||||
teamID: UUID!
|
||||
userID: UUID!
|
||||
affectedProjects: [Project!]!
|
||||
}
|
||||
|
||||
input CreateTeamMember {
|
||||
userID: UUID!
|
||||
teamID: UUID!
|
||||
}
|
||||
|
||||
type CreateTeamMemberPayload {
|
||||
team: Team!
|
||||
teamMember: Member!
|
||||
}
|
||||
|
||||
input UpdateTeamMemberRole {
|
||||
teamID: UUID!
|
||||
userID: UUID!
|
||||
roleCode: RoleCode!
|
||||
}
|
||||
|
||||
type UpdateTeamMemberRolePayload {
|
||||
ok: Boolean!
|
||||
teamID: UUID!
|
||||
member: Member!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
deleteTeam(input: DeleteTeam!):
|
||||
DeleteTeamPayload! @hasRole(roles:[ ADMIN], level: TEAM, type: TEAM)
|
||||
createTeam(input: NewTeam!):
|
||||
Team! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
|
||||
}
|
||||
|
||||
input NewTeam {
|
||||
name: String!
|
||||
organizationID: UUID!
|
||||
}
|
||||
|
||||
input DeleteTeam {
|
||||
teamID: UUID!
|
||||
}
|
||||
|
||||
type DeleteTeamPayload {
|
||||
ok: Boolean!
|
||||
team: Team!
|
||||
projects: [Project!]!
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
type Team {
|
||||
id: ID!
|
||||
createdAt: Time!
|
||||
name: String!
|
||||
permission: TeamPermission!
|
||||
members: [Member!]!
|
||||
}
|
||||
|
||||
type TeamPermission {
|
||||
team: RoleCode!
|
||||
org: RoleCode!
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
extend type Mutation {
|
||||
createTeamMember(input: CreateTeamMember!):
|
||||
CreateTeamMemberPayload! @hasRole(roles: [ADMIN], level: TEAM, type: TEAM)
|
||||
updateTeamMemberRole(input: UpdateTeamMemberRole!):
|
||||
UpdateTeamMemberRolePayload! @hasRole(roles: [ADMIN], level: TEAM, type: TEAM)
|
||||
deleteTeamMember(input: DeleteTeamMember!):
|
||||
DeleteTeamMemberPayload! @hasRole(roles: [ADMIN], level: TEAM, type: TEAM)
|
||||
|
||||
}
|
||||
|
||||
input DeleteTeamMember {
|
||||
teamID: UUID!
|
||||
userID: UUID!
|
||||
newOwnerID: UUID
|
||||
}
|
||||
|
||||
type DeleteTeamMemberPayload {
|
||||
teamID: UUID!
|
||||
userID: UUID!
|
||||
affectedProjects: [Project!]!
|
||||
}
|
||||
|
||||
input CreateTeamMember {
|
||||
userID: UUID!
|
||||
teamID: UUID!
|
||||
}
|
||||
|
||||
type CreateTeamMemberPayload {
|
||||
team: Team!
|
||||
teamMember: Member!
|
||||
}
|
||||
|
||||
input UpdateTeamMemberRole {
|
||||
teamID: UUID!
|
||||
userID: UUID!
|
||||
roleCode: RoleCode!
|
||||
}
|
||||
|
||||
type UpdateTeamMemberRolePayload {
|
||||
ok: Boolean!
|
||||
teamID: UUID!
|
||||
member: Member!
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
extend type Mutation {
|
||||
deleteTeam(input: DeleteTeam!):
|
||||
DeleteTeamPayload! @hasRole(roles:[ ADMIN], level: TEAM, type: TEAM)
|
||||
createTeam(input: NewTeam!):
|
||||
Team! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
|
||||
}
|
||||
|
||||
input NewTeam {
|
||||
name: String!
|
||||
organizationID: UUID!
|
||||
}
|
||||
|
||||
input DeleteTeam {
|
||||
teamID: UUID!
|
||||
}
|
||||
|
||||
type DeleteTeamPayload {
|
||||
ok: Boolean!
|
||||
team: Team!
|
||||
projects: [Project!]!
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
type UserAccount {
|
||||
id: ID!
|
||||
email: String!
|
||||
createdAt: Time!
|
||||
fullName: String!
|
||||
initials: String!
|
||||
bio: String!
|
||||
role: Role!
|
||||
username: String!
|
||||
profileIcon: ProfileIcon!
|
||||
owned: OwnedList!
|
||||
member: MemberList!
|
||||
}
|
||||
|
||||
type InvitedUserAccount {
|
||||
id: ID!
|
||||
email: String!
|
||||
invitedOn: Time!
|
||||
member: MemberList!
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createUserAccount(input: NewUserAccount!):
|
||||
UserAccount! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
|
||||
deleteUserAccount(input: DeleteUserAccount!):
|
||||
DeleteUserAccountPayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
|
||||
deleteInvitedUserAccount(input: DeleteInvitedUserAccount!):
|
||||
DeleteInvitedUserAccountPayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
|
||||
|
||||
logoutUser(input: LogoutUser!): Boolean!
|
||||
clearProfileAvatar: UserAccount!
|
||||
|
||||
updateUserPassword(input: UpdateUserPassword!): UpdateUserPasswordPayload!
|
||||
updateUserRole(input: UpdateUserRole!):
|
||||
UpdateUserRolePayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
|
||||
updateUserInfo(input: UpdateUserInfo!):
|
||||
UpdateUserInfoPayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
searchMembers(input: MemberSearchFilter!): [MemberSearchResult!]!
|
||||
}
|
||||
|
||||
input DeleteInvitedUserAccount {
|
||||
invitedUserID: UUID!
|
||||
}
|
||||
|
||||
type DeleteInvitedUserAccountPayload {
|
||||
invitedUser: InvitedUserAccount!
|
||||
}
|
||||
|
||||
input MemberSearchFilter {
|
||||
searchFilter: String!
|
||||
projectID: UUID
|
||||
}
|
||||
|
||||
|
||||
type MemberSearchResult {
|
||||
similarity: Int!
|
||||
id: String!
|
||||
user: UserAccount
|
||||
status: ShareStatus!
|
||||
}
|
||||
|
||||
type UpdateUserInfoPayload {
|
||||
user: UserAccount!
|
||||
}
|
||||
|
||||
input UpdateUserInfo {
|
||||
name: String!
|
||||
initials: String!
|
||||
email: String!
|
||||
bio: String!
|
||||
}
|
||||
|
||||
input UpdateUserPassword {
|
||||
userID: UUID!
|
||||
password: String!
|
||||
}
|
||||
|
||||
type UpdateUserPasswordPayload {
|
||||
ok: Boolean!
|
||||
user: UserAccount!
|
||||
}
|
||||
|
||||
input UpdateUserRole {
|
||||
userID: UUID!
|
||||
roleCode: RoleCode!
|
||||
}
|
||||
|
||||
type UpdateUserRolePayload {
|
||||
user: UserAccount!
|
||||
}
|
||||
|
||||
input NewUserAccount {
|
||||
username: String!
|
||||
email: String!
|
||||
fullName: String!
|
||||
initials: String!
|
||||
password: String!
|
||||
roleCode: String!
|
||||
}
|
||||
|
||||
input LogoutUser {
|
||||
userID: UUID!
|
||||
}
|
||||
|
||||
input DeleteUserAccount {
|
||||
userID: UUID!
|
||||
newOwnerID: UUID
|
||||
}
|
||||
|
||||
type DeleteUserAccountPayload {
|
||||
ok: Boolean!
|
||||
userAccount: UserAccount!
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
type UserAccount {
|
||||
id: ID!
|
||||
email: String!
|
||||
createdAt: Time!
|
||||
fullName: String!
|
||||
initials: String!
|
||||
bio: String!
|
||||
role: Role!
|
||||
username: String!
|
||||
profileIcon: ProfileIcon!
|
||||
owned: OwnedList!
|
||||
member: MemberList!
|
||||
}
|
||||
|
||||
type InvitedUserAccount {
|
||||
id: ID!
|
||||
email: String!
|
||||
invitedOn: Time!
|
||||
member: MemberList!
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
extend type Mutation {
|
||||
createUserAccount(input: NewUserAccount!):
|
||||
UserAccount! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
|
||||
deleteUserAccount(input: DeleteUserAccount!):
|
||||
DeleteUserAccountPayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
|
||||
deleteInvitedUserAccount(input: DeleteInvitedUserAccount!):
|
||||
DeleteInvitedUserAccountPayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
|
||||
|
||||
logoutUser(input: LogoutUser!): Boolean!
|
||||
clearProfileAvatar: UserAccount!
|
||||
|
||||
updateUserPassword(input: UpdateUserPassword!): UpdateUserPasswordPayload!
|
||||
updateUserRole(input: UpdateUserRole!):
|
||||
UpdateUserRolePayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
|
||||
updateUserInfo(input: UpdateUserInfo!):
|
||||
UpdateUserInfoPayload! @hasRole(roles: [ADMIN], level: ORG, type: ORG)
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
searchMembers(input: MemberSearchFilter!): [MemberSearchResult!]!
|
||||
}
|
||||
|
||||
input DeleteInvitedUserAccount {
|
||||
invitedUserID: UUID!
|
||||
}
|
||||
|
||||
type DeleteInvitedUserAccountPayload {
|
||||
invitedUser: InvitedUserAccount!
|
||||
}
|
||||
|
||||
input MemberSearchFilter {
|
||||
searchFilter: String!
|
||||
projectID: UUID
|
||||
}
|
||||
|
||||
|
||||
type MemberSearchResult {
|
||||
similarity: Int!
|
||||
id: String!
|
||||
user: UserAccount
|
||||
status: ShareStatus!
|
||||
}
|
||||
|
||||
type UpdateUserInfoPayload {
|
||||
user: UserAccount!
|
||||
}
|
||||
|
||||
input UpdateUserInfo {
|
||||
name: String!
|
||||
initials: String!
|
||||
email: String!
|
||||
bio: String!
|
||||
}
|
||||
|
||||
input UpdateUserPassword {
|
||||
userID: UUID!
|
||||
password: String!
|
||||
}
|
||||
|
||||
type UpdateUserPasswordPayload {
|
||||
ok: Boolean!
|
||||
user: UserAccount!
|
||||
}
|
||||
|
||||
input UpdateUserRole {
|
||||
userID: UUID!
|
||||
roleCode: RoleCode!
|
||||
}
|
||||
|
||||
type UpdateUserRolePayload {
|
||||
user: UserAccount!
|
||||
}
|
||||
|
||||
input NewUserAccount {
|
||||
username: String!
|
||||
email: String!
|
||||
fullName: String!
|
||||
initials: String!
|
||||
password: String!
|
||||
roleCode: String!
|
||||
}
|
||||
|
||||
input LogoutUser {
|
||||
userID: UUID!
|
||||
}
|
||||
|
||||
input DeleteUserAccount {
|
||||
userID: UUID!
|
||||
newOwnerID: UUID
|
||||
}
|
||||
|
||||
type DeleteUserAccountPayload {
|
||||
ok: Boolean!
|
||||
userAccount: UserAccount!
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,29 +0,0 @@
|
||||
package graph
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
)
|
||||
|
||||
func (r *taskGroupResolver) ID(ctx context.Context, obj *db.TaskGroup) (uuid.UUID, error) {
|
||||
return obj.TaskGroupID, nil
|
||||
}
|
||||
|
||||
func (r *taskGroupResolver) ProjectID(ctx context.Context, obj *db.TaskGroup) (string, error) {
|
||||
return obj.ProjectID.String(), nil
|
||||
}
|
||||
|
||||
func (r *taskGroupResolver) Tasks(ctx context.Context, obj *db.TaskGroup) ([]db.Task, error) {
|
||||
tasks, err := r.Repository.GetTasksForTaskGroupID(ctx, obj.TaskGroupID)
|
||||
return tasks, err
|
||||
}
|
||||
|
||||
// TaskGroup returns TaskGroupResolver implementation.
|
||||
func (r *Resolver) TaskGroup() TaskGroupResolver { return &taskGroupResolver{r} }
|
||||
|
||||
type taskGroupResolver struct{ *Resolver }
|
@ -1,192 +0,0 @@
|
||||
package graph
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/jordanknott/taskcafe/internal/logger"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
func (r *mutationResolver) CreateTeamMember(ctx context.Context, input CreateTeamMember) (*CreateTeamMemberPayload, error) {
|
||||
addedDate := time.Now().UTC()
|
||||
team, err := r.Repository.GetTeamByID(ctx, input.TeamID)
|
||||
if err != nil {
|
||||
return &CreateTeamMemberPayload{}, err
|
||||
}
|
||||
_, err = r.Repository.CreateTeamMember(ctx, db.CreateTeamMemberParams{TeamID: input.TeamID, UserID: input.UserID, Addeddate: addedDate, RoleCode: RoleCodeMember.String()})
|
||||
user, err := r.Repository.GetUserAccountByID(ctx, input.UserID)
|
||||
if err != nil {
|
||||
return &CreateTeamMemberPayload{}, err
|
||||
}
|
||||
var url *string
|
||||
if user.ProfileAvatarUrl.Valid {
|
||||
url = &user.ProfileAvatarUrl.String
|
||||
}
|
||||
profileIcon := &ProfileIcon{url, &user.Initials, &user.ProfileBgColor}
|
||||
return &CreateTeamMemberPayload{
|
||||
Team: &team,
|
||||
TeamMember: &Member{
|
||||
ID: user.UserID,
|
||||
Username: user.Username,
|
||||
FullName: user.FullName,
|
||||
ProfileIcon: profileIcon,
|
||||
Role: &db.Role{Code: "member", Name: "Member"},
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateTeamMemberRole(ctx context.Context, input UpdateTeamMemberRole) (*UpdateTeamMemberRolePayload, error) {
|
||||
user, err := r.Repository.GetUserAccountByID(ctx, input.UserID)
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("get user account")
|
||||
return &UpdateTeamMemberRolePayload{Ok: false}, err
|
||||
}
|
||||
_, err = r.Repository.UpdateTeamMemberRole(ctx, db.UpdateTeamMemberRoleParams{TeamID: input.TeamID,
|
||||
UserID: input.UserID, RoleCode: input.RoleCode.String()})
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("update project member role")
|
||||
return &UpdateTeamMemberRolePayload{Ok: false}, err
|
||||
}
|
||||
role, err := r.Repository.GetRoleForTeamMember(ctx, db.GetRoleForTeamMemberParams{UserID: user.UserID, TeamID: input.TeamID})
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("get role for project member")
|
||||
return &UpdateTeamMemberRolePayload{Ok: false}, err
|
||||
}
|
||||
var url *string
|
||||
if user.ProfileAvatarUrl.Valid {
|
||||
url = &user.ProfileAvatarUrl.String
|
||||
}
|
||||
profileIcon := &ProfileIcon{url, &user.Initials, &user.ProfileBgColor}
|
||||
if user.ProfileAvatarUrl.Valid {
|
||||
url = &user.ProfileAvatarUrl.String
|
||||
}
|
||||
member := Member{ID: user.UserID, FullName: user.FullName, ProfileIcon: profileIcon,
|
||||
Role: &db.Role{Code: role.Code, Name: role.Name},
|
||||
}
|
||||
return &UpdateTeamMemberRolePayload{Ok: true, Member: &member, TeamID: input.TeamID}, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteTeamMember(ctx context.Context, input DeleteTeamMember) (*DeleteTeamMemberPayload, error) {
|
||||
err := r.Repository.DeleteTeamMember(ctx, db.DeleteTeamMemberParams{TeamID: input.TeamID, UserID: input.UserID})
|
||||
return &DeleteTeamMemberPayload{TeamID: input.TeamID, UserID: input.UserID}, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteTeam(ctx context.Context, input DeleteTeam) (*DeleteTeamPayload, error) {
|
||||
team, err := r.Repository.GetTeamByID(ctx, input.TeamID)
|
||||
if err != nil {
|
||||
logger.New(ctx).Error(err)
|
||||
return &DeleteTeamPayload{Ok: false}, err
|
||||
}
|
||||
projects, err := r.Repository.GetAllProjectsForTeam(ctx, input.TeamID)
|
||||
if err != nil {
|
||||
logger.New(ctx).Error(err)
|
||||
return &DeleteTeamPayload{Ok: false}, err
|
||||
}
|
||||
err = r.Repository.DeleteTeamByID(ctx, input.TeamID)
|
||||
if err != nil {
|
||||
logger.New(ctx).Error(err)
|
||||
return &DeleteTeamPayload{Ok: false}, err
|
||||
}
|
||||
|
||||
return &DeleteTeamPayload{Ok: true, Team: &team, Projects: projects}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) CreateTeam(ctx context.Context, input NewTeam) (*db.Team, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return &db.Team{}, nil
|
||||
}
|
||||
role, err := r.Repository.GetRoleForUserID(ctx, userID)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("while creating team")
|
||||
return &db.Team{}, nil
|
||||
}
|
||||
if ConvertToRoleCode(role.Code) != RoleCodeAdmin {
|
||||
return &db.Team{}, &gqlerror.Error{
|
||||
Message: "Must be an organization admin",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "0-400",
|
||||
},
|
||||
}
|
||||
}
|
||||
createdAt := time.Now().UTC()
|
||||
team, err := r.Repository.CreateTeam(ctx, db.CreateTeamParams{OrganizationID: input.OrganizationID, CreatedAt: createdAt, Name: input.Name})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("while creating team")
|
||||
return &db.Team{}, nil
|
||||
}
|
||||
_, err = r.Repository.CreateTeamMember(ctx, db.CreateTeamMemberParams{
|
||||
UserID: userID,
|
||||
TeamID: team.TeamID,
|
||||
Addeddate: createdAt,
|
||||
RoleCode: "admin",
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while creating team member")
|
||||
return &db.Team{}, nil
|
||||
}
|
||||
|
||||
return &team, nil
|
||||
}
|
||||
|
||||
func (r *teamResolver) ID(ctx context.Context, obj *db.Team) (uuid.UUID, error) {
|
||||
return obj.TeamID, nil
|
||||
}
|
||||
|
||||
func (r *teamResolver) Permission(ctx context.Context, obj *db.Team) (*TeamPermission, error) {
|
||||
panic(fmt.Errorf("not implemented"))
|
||||
}
|
||||
|
||||
func (r *teamResolver) Members(ctx context.Context, obj *db.Team) ([]Member, error) {
|
||||
members := []Member{}
|
||||
|
||||
teamMembers, err := r.Repository.GetTeamMembersForTeamID(ctx, obj.TeamID)
|
||||
if err != nil {
|
||||
logger.New(ctx).Error("get project members for project id")
|
||||
return members, err
|
||||
}
|
||||
|
||||
for _, teamMember := range teamMembers {
|
||||
user, err := r.Repository.GetUserAccountByID(ctx, teamMember.UserID)
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("get user account by ID")
|
||||
return members, err
|
||||
}
|
||||
var url *string
|
||||
if user.ProfileAvatarUrl.Valid {
|
||||
url = &user.ProfileAvatarUrl.String
|
||||
}
|
||||
profileIcon := &ProfileIcon{url, &user.Initials, &user.ProfileBgColor}
|
||||
role, err := r.Repository.GetRoleForTeamMember(ctx, db.GetRoleForTeamMemberParams{UserID: user.UserID, TeamID: obj.TeamID})
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("get role for projet member by user ID")
|
||||
return members, err
|
||||
}
|
||||
|
||||
ownedList, err := GetOwnedList(ctx, r.Repository, user)
|
||||
if err != nil {
|
||||
return members, err
|
||||
}
|
||||
memberList, err := GetMemberList(ctx, r.Repository, user)
|
||||
if err != nil {
|
||||
return members, err
|
||||
}
|
||||
|
||||
members = append(members, Member{ID: user.UserID, FullName: user.FullName, ProfileIcon: profileIcon,
|
||||
Username: user.Username, Owned: ownedList, Member: memberList, Role: &db.Role{Code: role.Code, Name: role.Name},
|
||||
})
|
||||
}
|
||||
return members, nil
|
||||
}
|
||||
|
||||
// Team returns TeamResolver implementation.
|
||||
func (r *Resolver) Team() TeamResolver { return &teamResolver{r} }
|
||||
|
||||
type teamResolver struct{ *Resolver }
|
@ -1,302 +0,0 @@
|
||||
package graph
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/jordanknott/taskcafe/internal/logger"
|
||||
"github.com/lithammer/fuzzysearch/fuzzy"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func (r *mutationResolver) CreateUserAccount(ctx context.Context, input NewUserAccount) (*db.UserAccount, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return &db.UserAccount{}, nil
|
||||
}
|
||||
role, err := r.Repository.GetRoleForUserID(ctx, userID)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("while creating user account")
|
||||
return &db.UserAccount{}, nil
|
||||
}
|
||||
if ConvertToRoleCode(role.Code) != RoleCodeAdmin {
|
||||
return &db.UserAccount{}, &gqlerror.Error{
|
||||
Message: "Must be an organization admin",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "0-400",
|
||||
},
|
||||
}
|
||||
}
|
||||
createdAt := time.Now().UTC()
|
||||
hashedPwd, err := bcrypt.GenerateFromPassword([]byte(input.Password), 14)
|
||||
if err != nil {
|
||||
return &db.UserAccount{}, err
|
||||
}
|
||||
|
||||
userExists, err := r.Repository.DoesUserExist(ctx, db.DoesUserExistParams{Username: input.Username, Email: input.Email})
|
||||
if err != nil {
|
||||
return &db.UserAccount{}, err
|
||||
}
|
||||
if userExists {
|
||||
return &db.UserAccount{}, &gqlerror.Error{
|
||||
Message: "User with that username or email already exists",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "0-300",
|
||||
},
|
||||
}
|
||||
}
|
||||
userAccount, err := r.Repository.CreateUserAccount(ctx, db.CreateUserAccountParams{
|
||||
FullName: input.FullName,
|
||||
RoleCode: input.RoleCode,
|
||||
Initials: input.Initials,
|
||||
Email: input.Email,
|
||||
Username: input.Username,
|
||||
CreatedAt: createdAt,
|
||||
Active: true,
|
||||
PasswordHash: string(hashedPwd),
|
||||
})
|
||||
return &userAccount, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteUserAccount(ctx context.Context, input DeleteUserAccount) (*DeleteUserAccountPayload, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return &DeleteUserAccountPayload{Ok: false}, nil
|
||||
}
|
||||
role, err := r.Repository.GetRoleForUserID(ctx, userID)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("while deleting user account")
|
||||
return &DeleteUserAccountPayload{}, nil
|
||||
}
|
||||
if ConvertToRoleCode(role.Code) != RoleCodeAdmin {
|
||||
return &DeleteUserAccountPayload{}, &gqlerror.Error{
|
||||
Message: "Must be an organization admin",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "0-400",
|
||||
},
|
||||
}
|
||||
}
|
||||
user, err := r.Repository.GetUserAccountByID(ctx, input.UserID)
|
||||
if err != nil {
|
||||
return &DeleteUserAccountPayload{Ok: false}, err
|
||||
}
|
||||
|
||||
err = r.Repository.DeleteUserAccountByID(ctx, input.UserID)
|
||||
if err != nil {
|
||||
return &DeleteUserAccountPayload{Ok: false}, err
|
||||
}
|
||||
return &DeleteUserAccountPayload{UserAccount: &user, Ok: true}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) DeleteInvitedUserAccount(ctx context.Context, input DeleteInvitedUserAccount) (*DeleteInvitedUserAccountPayload, error) {
|
||||
user, err := r.Repository.DeleteInvitedUserAccount(ctx, input.InvitedUserID)
|
||||
if err != nil {
|
||||
return &DeleteInvitedUserAccountPayload{}, err
|
||||
}
|
||||
err = r.Repository.DeleteConfirmTokenForEmail(ctx, user.Email)
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("issue deleting confirm token")
|
||||
return &DeleteInvitedUserAccountPayload{}, err
|
||||
}
|
||||
return &DeleteInvitedUserAccountPayload{
|
||||
InvitedUser: &InvitedUserAccount{
|
||||
Email: user.Email,
|
||||
ID: user.UserAccountInvitedID,
|
||||
InvitedOn: user.InvitedOn,
|
||||
},
|
||||
}, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) LogoutUser(ctx context.Context, input LogoutUser) (bool, error) {
|
||||
err := r.Repository.DeleteAuthTokenByUserID(ctx, input.UserID)
|
||||
return true, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) ClearProfileAvatar(ctx context.Context) (*db.UserAccount, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return &db.UserAccount{}, fmt.Errorf("internal server error")
|
||||
}
|
||||
user, err := r.Repository.UpdateUserAccountProfileAvatarURL(ctx, db.UpdateUserAccountProfileAvatarURLParams{UserID: userID, ProfileAvatarUrl: sql.NullString{Valid: false, String: ""}})
|
||||
if err != nil {
|
||||
return &db.UserAccount{}, err
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateUserPassword(ctx context.Context, input UpdateUserPassword) (*UpdateUserPasswordPayload, error) {
|
||||
hashedPwd, err := bcrypt.GenerateFromPassword([]byte(input.Password), 14)
|
||||
if err != nil {
|
||||
return &UpdateUserPasswordPayload{}, err
|
||||
}
|
||||
user, err := r.Repository.SetUserPassword(ctx, db.SetUserPasswordParams{UserID: input.UserID, PasswordHash: string(hashedPwd)})
|
||||
if err != nil {
|
||||
return &UpdateUserPasswordPayload{}, err
|
||||
}
|
||||
return &UpdateUserPasswordPayload{Ok: true, User: &user}, err
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateUserRole(ctx context.Context, input UpdateUserRole) (*UpdateUserRolePayload, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return &UpdateUserRolePayload{}, nil
|
||||
}
|
||||
role, err := r.Repository.GetRoleForUserID(ctx, userID)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("while updating user role")
|
||||
return &UpdateUserRolePayload{}, nil
|
||||
}
|
||||
if ConvertToRoleCode(role.Code) != RoleCodeAdmin {
|
||||
return &UpdateUserRolePayload{}, &gqlerror.Error{
|
||||
Message: "Must be an organization admin",
|
||||
Extensions: map[string]interface{}{
|
||||
"code": "0-400",
|
||||
},
|
||||
}
|
||||
}
|
||||
user, err := r.Repository.UpdateUserRole(ctx, db.UpdateUserRoleParams{RoleCode: input.RoleCode.String(), UserID: input.UserID})
|
||||
if err != nil {
|
||||
return &UpdateUserRolePayload{}, err
|
||||
}
|
||||
return &UpdateUserRolePayload{User: &user}, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateUserInfo(ctx context.Context, input UpdateUserInfo) (*UpdateUserInfoPayload, error) {
|
||||
userID, ok := GetUserID(ctx)
|
||||
if !ok {
|
||||
return &UpdateUserInfoPayload{}, errors.New("invalid user ID")
|
||||
}
|
||||
user, err := r.Repository.UpdateUserAccountInfo(ctx, db.UpdateUserAccountInfoParams{
|
||||
Bio: input.Bio, FullName: input.Name, Initials: input.Initials, Email: input.Email, UserID: userID,
|
||||
})
|
||||
return &UpdateUserInfoPayload{User: &user}, err
|
||||
}
|
||||
|
||||
func (r *queryResolver) SearchMembers(ctx context.Context, input MemberSearchFilter) ([]MemberSearchResult, error) {
|
||||
availableMembers, err := r.Repository.GetMemberData(ctx, *input.ProjectID)
|
||||
if err != nil {
|
||||
logger.New(ctx).WithField("projectID", input.ProjectID).WithError(err).Error("error while getting member data")
|
||||
return []MemberSearchResult{}, err
|
||||
}
|
||||
|
||||
invitedMembers, err := r.Repository.GetInvitedMembersForProjectID(ctx, *input.ProjectID)
|
||||
if err != nil {
|
||||
logger.New(ctx).WithField("projectID", input.ProjectID).WithError(err).Error("error while getting member data")
|
||||
return []MemberSearchResult{}, err
|
||||
}
|
||||
|
||||
sortList := []string{}
|
||||
masterList := map[string]MasterEntry{}
|
||||
for _, member := range availableMembers {
|
||||
sortList = append(sortList, member.Username)
|
||||
sortList = append(sortList, member.Email)
|
||||
masterList[member.Username] = MasterEntry{ID: member.UserID, MemberType: MemberTypeJoined}
|
||||
masterList[member.Email] = MasterEntry{ID: member.UserID, MemberType: MemberTypeJoined}
|
||||
}
|
||||
for _, member := range invitedMembers {
|
||||
sortList = append(sortList, member.Email)
|
||||
logger.New(ctx).WithField("Email", member.Email).Info("adding member")
|
||||
masterList[member.Email] = MasterEntry{ID: member.UserAccountInvitedID, MemberType: MemberTypeInvited}
|
||||
}
|
||||
|
||||
logger.New(ctx).WithField("searchFilter", input.SearchFilter).Info(sortList)
|
||||
rankedList := fuzzy.RankFind(input.SearchFilter, sortList)
|
||||
logger.New(ctx).Info(rankedList)
|
||||
results := []MemberSearchResult{}
|
||||
memberList := map[uuid.UUID]bool{}
|
||||
for _, rank := range rankedList {
|
||||
entry, _ := masterList[rank.Target]
|
||||
_, ok := memberList[entry.ID]
|
||||
logger.New(ctx).WithField("ok", ok).WithField("target", rank.Target).Info("checking rank")
|
||||
if !ok {
|
||||
if entry.MemberType == MemberTypeJoined {
|
||||
logger.New(ctx).WithFields(log.Fields{"source": rank.Source, "target": rank.Target}).Info("searching")
|
||||
entry := masterList[rank.Target]
|
||||
user, err := r.Repository.GetUserAccountByID(ctx, entry.ID)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
continue
|
||||
}
|
||||
return []MemberSearchResult{}, err
|
||||
}
|
||||
results = append(results, MemberSearchResult{ID: user.UserID.String(), User: &user, Status: ShareStatusJoined, Similarity: rank.Distance})
|
||||
} else {
|
||||
logger.New(ctx).WithField("id", rank.Target).Info("adding target")
|
||||
results = append(results, MemberSearchResult{ID: rank.Target, Status: ShareStatusInvited, Similarity: rank.Distance})
|
||||
|
||||
}
|
||||
memberList[entry.ID] = true
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (r *userAccountResolver) ID(ctx context.Context, obj *db.UserAccount) (uuid.UUID, error) {
|
||||
return obj.UserID, nil
|
||||
}
|
||||
|
||||
func (r *userAccountResolver) Role(ctx context.Context, obj *db.UserAccount) (*db.Role, error) {
|
||||
role, err := r.Repository.GetRoleForUserID(ctx, obj.UserID)
|
||||
if err != nil {
|
||||
logger.New(ctx).WithError(err).Error("get role for user id")
|
||||
return &db.Role{}, err
|
||||
}
|
||||
return &db.Role{Code: role.Code, Name: role.Name}, nil
|
||||
}
|
||||
|
||||
func (r *userAccountResolver) ProfileIcon(ctx context.Context, obj *db.UserAccount) (*ProfileIcon, error) {
|
||||
var url *string
|
||||
if obj.ProfileAvatarUrl.Valid {
|
||||
url = &obj.ProfileAvatarUrl.String
|
||||
}
|
||||
profileIcon := &ProfileIcon{url, &obj.Initials, &obj.ProfileBgColor}
|
||||
return profileIcon, nil
|
||||
}
|
||||
|
||||
func (r *userAccountResolver) Owned(ctx context.Context, obj *db.UserAccount) (*OwnedList, error) {
|
||||
return &OwnedList{}, nil // TODO(jordanknott)
|
||||
}
|
||||
|
||||
func (r *userAccountResolver) Member(ctx context.Context, obj *db.UserAccount) (*MemberList, error) {
|
||||
projectMemberIDs, err := r.Repository.GetMemberProjectIDsForUserID(ctx, obj.UserID)
|
||||
if err != sql.ErrNoRows && err != nil {
|
||||
return &MemberList{}, err
|
||||
}
|
||||
var projects []db.Project
|
||||
for _, projectID := range projectMemberIDs {
|
||||
project, err := r.Repository.GetProjectByID(ctx, projectID)
|
||||
if err != nil {
|
||||
return &MemberList{}, err
|
||||
}
|
||||
projects = append(projects, project)
|
||||
}
|
||||
teamMemberIDs, err := r.Repository.GetMemberTeamIDsForUserID(ctx, obj.UserID)
|
||||
if err != sql.ErrNoRows && err != nil {
|
||||
return &MemberList{}, err
|
||||
}
|
||||
var teams []db.Team
|
||||
for _, teamID := range teamMemberIDs {
|
||||
team, err := r.Repository.GetTeamByID(ctx, teamID)
|
||||
if err != nil {
|
||||
return &MemberList{}, err
|
||||
}
|
||||
teams = append(teams, team)
|
||||
}
|
||||
|
||||
return &MemberList{Teams: teams, Projects: projects}, err
|
||||
}
|
||||
|
||||
// UserAccount returns UserAccountResolver implementation.
|
||||
func (r *Resolver) UserAccount() UserAccountResolver { return &userAccountResolver{r} }
|
||||
|
||||
type userAccountResolver struct{ *Resolver }
|
@ -1,172 +0,0 @@
|
||||
package jobs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/RichardKnop/machinery/v1"
|
||||
mTasks "github.com/RichardKnop/machinery/v1/tasks"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/jinzhu/now"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jordanknott/taskcafe/internal/config"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
"github.com/jordanknott/taskcafe/internal/utils"
|
||||
)
|
||||
|
||||
type NotifiedData struct {
|
||||
Data map[string]string
|
||||
}
|
||||
|
||||
func RegisterTasks(server *machinery.Server, repo db.Repository, appConfig config.AppConfig, messageQueue *redis.Client) {
|
||||
tasks := JobTasks{Repository: repo, Server: server, AppConfig: appConfig, MessageQueue: messageQueue}
|
||||
server.RegisterTasks(map[string]interface{}{
|
||||
"dueDateNotification": tasks.DueDateNotification,
|
||||
"scheduleDueDateNotifications": tasks.ScheduleDueDateNotifications,
|
||||
})
|
||||
}
|
||||
|
||||
type JobTasks struct {
|
||||
AppConfig config.AppConfig
|
||||
Repository db.Repository
|
||||
Server *machinery.Server
|
||||
MessageQueue *redis.Client
|
||||
}
|
||||
|
||||
func (t *JobTasks) ScheduleDueDateNotifications() (bool, error) {
|
||||
ctx := context.Background()
|
||||
// tomorrow := now.With(time.Now().UTC().AddDate(0, 0, 1))
|
||||
today := now.With(time.Now().UTC())
|
||||
start := today.BeginningOfDay()
|
||||
log.WithFields(log.Fields{
|
||||
"start": start,
|
||||
}).Info("fetching duration")
|
||||
reminders, err := t.Repository.GetDueDateRemindersForDuration(ctx, start)
|
||||
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while getting due date reminder")
|
||||
}
|
||||
for _, rem := range reminders {
|
||||
log.WithField("id", rem.DueDateReminderID).Info("found reminder")
|
||||
signature := &mTasks.Signature{
|
||||
UUID: "due_date_reminder_" + rem.DueDateReminderID.String(),
|
||||
Name: "dueDateNotification",
|
||||
ETA: &rem.RemindAt,
|
||||
Args: []mTasks.Arg{{
|
||||
Type: "string",
|
||||
Value: rem.DueDateReminderID.String(),
|
||||
}, {
|
||||
Type: "string",
|
||||
Value: rem.TaskID.String(),
|
||||
}},
|
||||
}
|
||||
log.WithField("nanoTime", signature.ETA.UnixNano()).Info("rem time")
|
||||
etaNano := strconv.FormatInt(signature.ETA.UnixNano(), 10)
|
||||
result, err := t.MessageQueue.ZRangeByScore(ctx, "delayed_tasks", &redis.ZRangeBy{Max: etaNano, Min: etaNano}).Result()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while getting due date reminder")
|
||||
}
|
||||
log.WithField("result", result).Info("result raw")
|
||||
if len(result) == 0 {
|
||||
log.Info("task not found, sending task")
|
||||
t.Server.SendTask(signature)
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (t *JobTasks) DueDateNotification(dueDateIDEncoded string, taskIDEncoded string) (bool, error) {
|
||||
ctx := context.Background()
|
||||
dueDateID, err := uuid.Parse(dueDateIDEncoded)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("while parsing task ID")
|
||||
return false, err
|
||||
}
|
||||
taskID, err := uuid.Parse(taskIDEncoded)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("while parsing task ID")
|
||||
return false, err
|
||||
}
|
||||
dueAt, err := t.Repository.GetDueDateReminderByID(ctx, dueDateID)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("while getting task by id")
|
||||
return false, err
|
||||
}
|
||||
task, err := t.Repository.GetTaskByID(ctx, taskID)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("while getting task by id")
|
||||
return false, err
|
||||
}
|
||||
projectInfo, err := t.Repository.GetProjectInfoForTask(ctx, taskID)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while getting project info for task")
|
||||
return false, err
|
||||
}
|
||||
data := map[string]string{
|
||||
"TaskID": task.ShortID,
|
||||
"TaskName": task.Name,
|
||||
"ProjectID": projectInfo.ProjectShortID,
|
||||
"ProjectName": projectInfo.Name,
|
||||
"DueAt": dueAt.RemindAt.String(),
|
||||
}
|
||||
|
||||
now := time.Now().UTC()
|
||||
raw, err := json.Marshal(NotifiedData{Data: data})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while marshal json data for notification")
|
||||
return false, err
|
||||
}
|
||||
n, err := t.Repository.CreateNotification(ctx, db.CreateNotificationParams{
|
||||
CausedBy: uuid.UUID{},
|
||||
ActionType: "DUE_DATE_REMINDER",
|
||||
CreatedOn: now,
|
||||
Data: json.RawMessage(raw),
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while creating notification")
|
||||
return false, err
|
||||
}
|
||||
watchers, err := t.Repository.GetTaskWatchersForTask(ctx, taskID)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("while getting watchers")
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, watcher := range watchers {
|
||||
notified, err := t.Repository.CreateNotificationNotifed(ctx, db.CreateNotificationNotifedParams{
|
||||
UserID: watcher.UserID,
|
||||
NotificationID: n.NotificationID,
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error while creating notification notified object")
|
||||
return false, err
|
||||
}
|
||||
payload, err := json.Marshal(utils.NotificationCreatedMessage{
|
||||
NotifiedID: notified.NotifiedID.String(),
|
||||
NotificationID: n.NotificationID.String(),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := t.MessageQueue.Publish(context.Background(), "notification-created", payload).Err(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
type JobQueue struct {
|
||||
AppConfig config.AppConfig
|
||||
Repository db.Repository
|
||||
Server *machinery.Server
|
||||
}
|
||||
|
||||
func (q *JobQueue) DueDateNotification(notificationId uuid.UUID) error {
|
||||
return nil
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package jobs
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// MachineryLogger is a customer logger for machinery worker
|
||||
type MachineryLogger struct{}
|
||||
|
||||
// Print sends to logrus.Info
|
||||
func (m *MachineryLogger) Print(args ...interface{}) {
|
||||
log.Info(args...)
|
||||
}
|
||||
|
||||
// Printf sends to logrus.Infof
|
||||
func (m *MachineryLogger) Printf(format string, args ...interface{}) {
|
||||
log.Infof(format, args...)
|
||||
}
|
||||
|
||||
// Println sends to logrus.Info
|
||||
func (m *MachineryLogger) Println(args ...interface{}) {
|
||||
log.Info(args...)
|
||||
}
|
||||
|
||||
// Fatal sends to logrus.Fatal
|
||||
func (m *MachineryLogger) Fatal(args ...interface{}) {
|
||||
log.Fatal(args...)
|
||||
}
|
||||
|
||||
// Fatalf sends to logrus.Fatalf
|
||||
func (m *MachineryLogger) Fatalf(format string, args ...interface{}) {
|
||||
log.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
// Fatalln sends to logrus.Fatal
|
||||
func (m *MachineryLogger) Fatalln(args ...interface{}) {
|
||||
log.Fatal(args...)
|
||||
}
|
||||
|
||||
// Panic sends to logrus.Panic
|
||||
func (m *MachineryLogger) Panic(args ...interface{}) {
|
||||
log.Panic(args...)
|
||||
}
|
||||
|
||||
// Panicf sends to logrus.Panic
|
||||
func (m *MachineryLogger) Panicf(format string, args ...interface{}) {
|
||||
log.Panic(args...)
|
||||
}
|
||||
|
||||
// Panicln sends to logrus.Panic
|
||||
func (m *MachineryLogger) Panicln(args ...interface{}) {
|
||||
log.Panic(args...)
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jordanknott/taskcafe/internal/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// New returns a log entry with the reqID and userID fields populated if they exist
|
||||
func New(ctx context.Context) *log.Entry {
|
||||
entry := log.NewEntry(log.StandardLogger())
|
||||
if reqID, ok := ctx.Value(utils.ReqIDKey).(uuid.UUID); ok {
|
||||
entry = entry.WithField("reqID", reqID)
|
||||
}
|
||||
if userID, ok := ctx.Value(utils.UserIDKey).(uuid.UUID); ok {
|
||||
entry = entry.WithField("userID", userID)
|
||||
}
|
||||
return entry
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/middleware"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// NewStructuredLogger creates a new logger for chi router
|
||||
func NewStructuredLogger(logger *logrus.Logger) func(next http.Handler) http.Handler {
|
||||
return middleware.RequestLogger(&StructuredLogger{logger})
|
||||
}
|
||||
|
||||
// StructuredLogger is a logger for chi router
|
||||
type StructuredLogger struct {
|
||||
Logger *logrus.Logger
|
||||
}
|
||||
|
||||
// NewLogEntry creates a new log entry for the given HTTP request
|
||||
func (l *StructuredLogger) NewLogEntry(r *http.Request) middleware.LogEntry {
|
||||
entry := &StructuredLoggerEntry{Logger: logrus.NewEntry(l.Logger)}
|
||||
logFields := logrus.Fields{}
|
||||
|
||||
if reqID := middleware.GetReqID(r.Context()); reqID != "" {
|
||||
logFields["req_id"] = reqID
|
||||
}
|
||||
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
logFields["http_scheme"] = scheme
|
||||
logFields["http_proto"] = r.Proto
|
||||
logFields["http_method"] = r.Method
|
||||
|
||||
logFields["remote_addr"] = r.RemoteAddr
|
||||
logFields["user_agent"] = r.UserAgent()
|
||||
|
||||
logFields["uri"] = fmt.Sprintf("%s://%s%s", scheme, r.Host, r.RequestURI)
|
||||
|
||||
entry.Logger = entry.Logger.WithFields(logFields)
|
||||
|
||||
return entry
|
||||
}
|
||||
|
||||
// StructuredLoggerEntry is a log entry will all relevant information about a specific http request
|
||||
type StructuredLoggerEntry struct {
|
||||
Logger logrus.FieldLogger
|
||||
}
|
||||
|
||||
// Write logs information about http request response body
|
||||
func (l *StructuredLoggerEntry) Write(status, bytes int, elapsed time.Duration) {
|
||||
l.Logger = l.Logger.WithFields(logrus.Fields{
|
||||
"resp_status": status, "resp_bytes_length": bytes,
|
||||
"resp_elapsed_ms": float64(elapsed.Nanoseconds()) / 1000000.0,
|
||||
})
|
||||
l.Logger.Debugln("request complete")
|
||||
}
|
||||
|
||||
// Panic logs if the request panics
|
||||
func (l *StructuredLoggerEntry) Panic(v interface{}, stack []byte) {
|
||||
l.Logger = l.Logger.WithFields(logrus.Fields{
|
||||
"stack": string(stack),
|
||||
"panic": fmt.Sprintf("%+v", v),
|
||||
})
|
||||
}
|
||||
|
||||
// GetLogEntry helper function for getting log entry for request
|
||||
func GetLogEntry(r *http.Request) logrus.FieldLogger {
|
||||
entry := middleware.GetLogEntry(r).(*StructuredLoggerEntry)
|
||||
return entry.Logger
|
||||
}
|
||||
|
||||
// LogEntrySetField sets a key's value
|
||||
func LogEntrySetField(r *http.Request, key string, value interface{}) {
|
||||
if entry, ok := r.Context().Value(middleware.LogEntryCtxKey).(*StructuredLoggerEntry); ok {
|
||||
entry.Logger = entry.Logger.WithField(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// LogEntrySetFields sets the log entry's fields
|
||||
func LogEntrySetFields(r *http.Request, fields map[string]interface{}) {
|
||||
if entry, ok := r.Context().Value(middleware.LogEntryCtxKey).(*StructuredLoggerEntry); ok {
|
||||
entry.Logger = entry.Logger.WithFields(fields)
|
||||
}
|
||||
}
|
@ -1,352 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jordanknott/taskcafe/internal/db"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
type authResource struct{}
|
||||
|
||||
// LoginRequestData is the request data when a user logs in
|
||||
type LoginRequestData struct {
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
// NewUserAccount is the request data for a new user
|
||||
type NewUserAccount struct {
|
||||
FullName string `json:"fullname"`
|
||||
Username string
|
||||
Password string
|
||||
Initials string
|
||||
Email string
|
||||
}
|
||||
|
||||
// RegisterUserRequestData is the request data for registering a new user (duh)
|
||||
type RegisterUserRequestData struct {
|
||||
User NewUserAccount
|
||||
}
|
||||
|
||||
type RegisteredUserResponseData struct {
|
||||
Setup bool `json:"setup"`
|
||||
}
|
||||
|
||||
// ConfirmUserRequestData is the request data for upgrading an invited user to a normal user
|
||||
type ConfirmUserRequestData struct {
|
||||
ConfirmToken string
|
||||
}
|
||||
|
||||
// InstallRequestData is the request data for installing new Taskcafe app
|
||||
type InstallRequestData struct {
|
||||
User NewUserAccount
|
||||
}
|
||||
|
||||
type Setup struct {
|
||||
ConfirmToken string `json:"confirmToken"`
|
||||
}
|
||||
|
||||
type ValidateAuthTokenResponse struct {
|
||||
Valid bool `json:"valid"`
|
||||
UserID string `json:"userID"`
|
||||
}
|
||||
|
||||
// LoginResponseData is the response data for when a user logs in
|
||||
type LoginResponseData struct {
|
||||
UserID string `json:"userID"`
|
||||
Complete bool `json:"complete"`
|
||||
}
|
||||
|
||||
// LogoutResponseData is the response data for when a user logs out
|
||||
type LogoutResponseData struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// AuthTokenResponseData is the response data for when an access token is refreshed
|
||||
type AuthTokenResponseData struct {
|
||||
AccessToken string `json:"accessToken"`
|
||||
}
|
||||
|
||||
// AvatarUploadResponseData is the response data for a user profile is uploaded
|
||||
type AvatarUploadResponseData struct {
|
||||
UserID string `json:"userID"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
// LogoutHandler removes all refresh tokens to log out user
|
||||
func (h *TaskcafeHandler) LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := r.Cookie("authToken")
|
||||
if err != nil {
|
||||
if err == http.ErrNoCookie {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
refreshTokenID := uuid.MustParse(c.Value)
|
||||
err = h.repo.DeleteAuthTokenByID(r.Context(), refreshTokenID)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
json.NewEncoder(w).Encode(LogoutResponseData{Status: "success"})
|
||||
}
|
||||
|
||||
// LoginHandler creates a new refresh & access token for the user if given the correct credentials
|
||||
func (h *TaskcafeHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var requestData LoginRequestData
|
||||
err := json.NewDecoder(r.Body).Decode(&requestData)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
log.Debug("bad request body")
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.repo.GetUserAccountByUsername(r.Context(), requestData.Username)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"username": requestData.Username,
|
||||
}).Warn("user account not found")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if !user.Active {
|
||||
log.WithFields(log.Fields{
|
||||
"username": requestData.Username,
|
||||
}).Warn("attempt to login with inactive user")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(requestData.Password))
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"username": requestData.Username,
|
||||
}).Warn("password incorrect for user")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
authCreatedAt := time.Now().UTC()
|
||||
authExpiresAt := authCreatedAt.AddDate(0, 0, 1)
|
||||
authToken, err := h.repo.CreateAuthToken(r.Context(), db.CreateAuthTokenParams{user.UserID, authCreatedAt, authExpiresAt})
|
||||
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-type", "application/json")
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "authToken",
|
||||
Value: authToken.TokenID.String(),
|
||||
Expires: authExpiresAt,
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
})
|
||||
json.NewEncoder(w).Encode(LoginResponseData{Complete: true, UserID: authToken.UserID.String()})
|
||||
}
|
||||
|
||||
func (h *TaskcafeHandler) ConfirmUser(w http.ResponseWriter, r *http.Request) {
|
||||
usersExist, err := h.repo.HasActiveUser(r.Context())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("issue checking if user accounts exist")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
var user db.UserAccount
|
||||
if !usersExist {
|
||||
log.Info("setting first inactive user to active")
|
||||
user, err = h.repo.SetFirstUserActive(r.Context())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("issue checking if user accounts exist")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
var requestData ConfirmUserRequestData
|
||||
err = json.NewDecoder(r.Body).Decode(&requestData)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("issue decoding request data")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
confirmTokenID, err := uuid.Parse(requestData.ConfirmToken)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("issue parsing confirm token")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
confirmToken, err := h.repo.GetConfirmTokenByID(r.Context(), confirmTokenID)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("issue getting token by id")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user, err = h.repo.SetUserActiveByEmail(r.Context(), confirmToken.Email)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("issue getting account by email")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
now := time.Now().UTC()
|
||||
projects, err := h.repo.GetProjectsForInvitedMember(r.Context(), user.Email)
|
||||
for _, project := range projects {
|
||||
member, err := h.repo.CreateProjectMember(r.Context(),
|
||||
db.CreateProjectMemberParams{
|
||||
ProjectID: project,
|
||||
UserID: user.UserID,
|
||||
AddedAt: now,
|
||||
RoleCode: "member",
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("issue creating project member")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.WithField("memberID", member.ProjectMemberID).Info("creating project member")
|
||||
err = h.repo.DeleteProjectMemberInvitedForEmail(r.Context(), user.Email)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("issue deleting project member invited")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err = h.repo.DeleteUserAccountInvitedForEmail(r.Context(), user.Email)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("issue deleting user account invited")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err = h.repo.DeleteConfirmTokenForEmail(r.Context(), user.Email)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("issue deleting confirm token")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
authCreatedAt := time.Now().UTC()
|
||||
authExpiresAt := authCreatedAt.AddDate(0, 0, 1)
|
||||
authToken, err := h.repo.CreateAuthToken(r.Context(), db.CreateAuthTokenParams{user.UserID, authCreatedAt, authExpiresAt})
|
||||
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-type", "application/json")
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "authToken",
|
||||
Value: authToken.TokenID.String(),
|
||||
Path: "/",
|
||||
Expires: authExpiresAt,
|
||||
HttpOnly: true,
|
||||
})
|
||||
json.NewEncoder(w).Encode(LoginResponseData{Complete: true, UserID: authToken.UserID.String()})
|
||||
}
|
||||
func (h *TaskcafeHandler) ValidateAuthTokenHandler(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := r.Cookie("authToken")
|
||||
if err != nil {
|
||||
if err == http.ErrNoCookie {
|
||||
json.NewEncoder(w).Encode(ValidateAuthTokenResponse{Valid: false, UserID: ""})
|
||||
return
|
||||
}
|
||||
log.WithError(err).Error("unknown error")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
authTokenID := uuid.MustParse(c.Value)
|
||||
token, err := h.repo.GetAuthTokenByID(r.Context(), authTokenID)
|
||||
if err != nil {
|
||||
json.NewEncoder(w).Encode(ValidateAuthTokenResponse{Valid: false, UserID: ""})
|
||||
} else {
|
||||
json.NewEncoder(w).Encode(ValidateAuthTokenResponse{Valid: true, UserID: token.UserID.String()})
|
||||
}
|
||||
}
|
||||
|
||||
func (h *TaskcafeHandler) RegisterUser(w http.ResponseWriter, r *http.Request) {
|
||||
userExists, err := h.repo.HasAnyUser(r.Context())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("issue checking if user accounts exist")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var requestData RegisterUserRequestData
|
||||
err = json.NewDecoder(r.Body).Decode(&requestData)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("issue decoding register user request data")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if userExists {
|
||||
_, err := h.repo.GetInvitedUserByEmail(r.Context(), requestData.User.Email)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
hasActiveUser, err := h.repo.HasActiveUser(r.Context())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("error checking for active user")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if !hasActiveUser {
|
||||
json.NewEncoder(w).Encode(RegisteredUserResponseData{Setup: true})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
log.WithError(err).Error("error while retrieving invited user by email")
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: accept user if public registration is enabled
|
||||
|
||||
createdAt := time.Now().UTC()
|
||||
hashedPwd, err := bcrypt.GenerateFromPassword([]byte(requestData.User.Password), 14)
|
||||
if err != nil {
|
||||
log.Error("issue generating passoed")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
user, err := h.repo.CreateUserAccount(r.Context(), db.CreateUserAccountParams{
|
||||
FullName: requestData.User.FullName,
|
||||
Username: requestData.User.Username,
|
||||
Initials: requestData.User.Initials,
|
||||
Email: requestData.User.Email,
|
||||
PasswordHash: string(hashedPwd),
|
||||
CreatedAt: createdAt,
|
||||
RoleCode: "admin",
|
||||
Active: false,
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("issue registering user account")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.WithField("username", user.UserID).Info("registered new user account")
|
||||
json.NewEncoder(w).Encode(RegisteredUserResponseData{Setup: !userExists})
|
||||
}
|
||||
|
||||
// Routes registers all authentication routes
|
||||
func (rs authResource) Routes(taskcafeHandler TaskcafeHandler) chi.Router {
|
||||
r := chi.NewRouter()
|
||||
r.Post("/login", taskcafeHandler.LoginHandler)
|
||||
r.Post("/logout", taskcafeHandler.LogoutHandler)
|
||||
r.Post("/validate", taskcafeHandler.ValidateAuthTokenHandler)
|
||||
return r
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user