This commit is contained in:
Jordan Knott
2022-05-06 16:41:52 -05:00
parent 4f5aa2deb8
commit 64093e19f6
2156 changed files with 29717 additions and 80267 deletions

78
internal/api/api.go Normal file
View 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
}

View 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
View 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
View 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})
}

View File

@ -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()
}

View 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
}

View 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
View 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
}

View 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
},
}
}

View 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
View 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
}

View File

@ -1,11 +0,0 @@
// +build prod
package commands
import (
"github.com/jordanknott/taskcafe/internal/migrations"
)
func init() {
migration = migrations.Migrations
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
},
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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,

View File

@ -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
}

View File

@ -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"`
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)

View File

@ -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 *;

View File

@ -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;

View File

@ -1,5 +0,0 @@
-- name: GetAllOrganizations :many
SELECT * FROM organization;
-- name: CreateOrganization :one
INSERT INTO organization (created_at, name) VALUES ($1, $2) RETURNING *;

View File

@ -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;

View File

@ -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 *;

View File

@ -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 *;

View File

@ -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;

View File

@ -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
);

View File

@ -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 *;

View File

@ -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;

View File

@ -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 *;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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();

View 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;

View File

@ -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;

View File

@ -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,
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View 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
}

View File

@ -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

View File

@ -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
}

View File

@ -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: &notified.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

View File

@ -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, &notifiedData)
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 = &notified.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 = &notified.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 = &notified.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 &notificationResolver{r} }
type notificationResolver struct{ *Resolver }

View File

@ -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 }

View File

@ -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: &notified.ReadAt.Time,
Notification: &notification,
}
}
}
}
}()
}

View File

@ -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")
}

View File

@ -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 }

View File

@ -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
}

View File

@ -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
}

View File

@ -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!
}

View File

@ -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!
}

View File

@ -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!
}

View File

@ -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!
}

View File

@ -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!
}

View File

@ -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!
}

View File

@ -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!
}

View File

@ -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!]!
}

View File

@ -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!
}

View File

@ -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!
}

View File

@ -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!
}

View File

@ -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!
}

View File

@ -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!
}

View File

@ -1,10 +0,0 @@
type TaskGroup {
id: ID!
projectID: String!
createdAt: Time!
name: String!
position: Float!
tasks: [Task!]!
}

View File

@ -1,8 +0,0 @@
type TaskGroup {
id: ID!
projectID: String!
createdAt: Time!
name: String!
position: Float!
tasks: [Task!]!
}

View File

@ -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!]!
}

View File

@ -1,12 +0,0 @@
type Team {
id: ID!
createdAt: Time!
name: String!
permission: TeamPermission!
members: [Member!]!
}
type TeamPermission {
team: RoleCode!
org: RoleCode!
}

View File

@ -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!
}

View File

@ -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!]!
}

View File

@ -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!
}

View File

@ -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!
}

View File

@ -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

View File

@ -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 }

View File

@ -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 }

View File

@ -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 }

View File

@ -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
}

View File

@ -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...)
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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