Compare commits
151 commits
c72257132c
...
dfefe65ec0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfefe65ec0 | ||
|
|
04f37f87e2 | ||
|
|
db9fe90163 | ||
|
|
acb12c393a | ||
|
|
9d75c2a665 | ||
|
|
f154d42e67 | ||
|
|
37104788e7 | ||
|
|
75c9c5be34 | ||
|
|
f634285909 | ||
|
|
1641ac51a6 | ||
|
|
2eefb46e08 | ||
|
|
fd6218c0ad | ||
|
|
79a589da65 | ||
|
|
2a546dfe3d | ||
|
|
885a6ad7bf | ||
|
|
4c4a503cdc | ||
|
|
0d6e26ab39 | ||
|
|
e85ca0a93f | ||
|
|
8d6f0b1261 | ||
|
|
7dcf6bc039 | ||
|
|
d91774313d | ||
|
|
efab433d5c | ||
|
|
9441014517 | ||
|
|
fbb3fdc70d | ||
|
|
a7c6994062 | ||
|
|
62d46c475c | ||
|
|
5cad4cbd33 | ||
|
|
633c60cdf5 | ||
|
|
ca1de66033 | ||
|
|
b808500a23 | ||
|
|
b2ad889f56 | ||
|
|
a7006b3997 | ||
|
|
d2d8c02a2f | ||
|
|
02a58946f1 | ||
|
|
d736551869 | ||
|
|
e3217fc852 | ||
|
|
c244389971 | ||
|
|
a9319559e1 | ||
|
|
f54d9f8b37 | ||
|
|
062d1f70be | ||
|
|
73098499dd | ||
|
|
6da0fcb7be | ||
|
|
62c53a6b4d | ||
|
|
11def45666 | ||
|
|
ca22f54c89 | ||
|
|
6730b6a319 | ||
|
|
71f7de8771 | ||
|
|
5531e0bec2 | ||
|
|
6a7070a729 | ||
|
|
9acf73a4d9 | ||
|
|
5ebd42d8f9 | ||
|
|
7d85ff0b08 | ||
|
|
afa8b5d2cc | ||
|
|
28abc92e74 | ||
|
|
400b9b36ba | ||
|
|
2c635b5c75 | ||
|
|
30389de16f | ||
|
|
0e204428b6 | ||
|
|
0783709b3c | ||
|
|
a122851717 | ||
|
|
114ed8444c | ||
|
|
f6a96e2025 | ||
|
|
15739cc82e | ||
|
|
e8952e964c | ||
|
|
b1c47426d9 | ||
|
|
97cd9d0fee | ||
|
|
c2b6928fb4 | ||
|
|
5af18e2473 | ||
|
|
81c65fcc30 | ||
|
|
3df20c01a7 | ||
|
|
0879aaf21d | ||
|
|
ba96445704 | ||
|
|
42c7957bf4 | ||
|
|
44da53d99f | ||
|
|
6a3f4b5ff2 | ||
|
|
68b850c87b | ||
|
|
4867b9bab8 | ||
|
|
7eae6309fd | ||
|
|
3026ec218e | ||
|
|
f688bff1d2 | ||
|
|
575bf805e2 | ||
|
|
1f42ce7db8 | ||
|
|
d875747e31 | ||
|
|
fec8698526 | ||
|
|
6d3dfe2531 | ||
|
|
842ddbdc9d | ||
|
|
4f776b76b3 | ||
|
|
96799be6ec | ||
|
|
859925bc45 | ||
|
|
911793ec61 | ||
|
|
19315b894e | ||
|
|
5b73526436 | ||
|
|
baa65ebbfa | ||
|
|
4527d3d2e5 | ||
|
|
2ac7604b43 | ||
|
|
713d3818bb | ||
|
|
26e4d4d16a | ||
|
|
0f800ec3e1 | ||
|
|
c2f1df1a83 | ||
|
|
8c5582f720 | ||
|
|
72ce41c828 | ||
|
|
1018d82d13 | ||
|
|
434d7b44b0 | ||
|
|
d85159c4f0 | ||
|
|
152e2e1037 | ||
|
|
44ab335cf5 | ||
|
|
936e6c9b18 | ||
|
|
55d51c70b8 | ||
|
|
9f6fe5f0b7 | ||
|
|
7f1e057ea2 | ||
|
|
12a177a215 | ||
|
|
c52544caf0 | ||
|
|
fb55c3453b | ||
|
|
0cc95d4c64 | ||
|
|
9f1ed2e5f5 | ||
|
|
8d2a6d9b7a | ||
|
|
aab3c04473 | ||
|
|
8fa6ebb8cf | ||
|
|
acebcf0ba0 | ||
|
|
cd1887124e | ||
|
|
0ca3c2b701 | ||
|
|
5c51b72757 | ||
|
|
8b1bc9b99e | ||
|
|
089c4d7ee1 | ||
|
|
51e44a57a1 | ||
|
|
944a4d941a | ||
|
|
c6a50b3bbf | ||
|
|
83cdbc4395 | ||
|
|
726556e973 | ||
|
|
156e578dd0 | ||
|
|
c43f62a570 | ||
|
|
a82ed9c6d0 | ||
|
|
6546418052 | ||
|
|
7a1a01d43e | ||
|
|
107f2e3262 | ||
|
|
cd4cc1693c | ||
|
|
cb43e08183 | ||
|
|
b269e7d264 | ||
|
|
e0a65ca007 | ||
|
|
09c6df7f52 | ||
|
|
10c0a23c0a | ||
|
|
a6e99058f4 | ||
|
|
c31f30ba5c | ||
|
|
6ec7118c3d | ||
|
|
eda79b6982 | ||
|
|
c391be9e4d | ||
|
|
2ece37eb9c | ||
|
|
328c1a3367 | ||
|
|
182ddc9f52 | ||
|
|
17185bee70 | ||
|
|
a6e131119a |
208 changed files with 11621 additions and 8207 deletions
52
.air.toml
Normal file
52
.air.toml
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
root = "."
|
||||||
|
testdata_dir = "testdata"
|
||||||
|
tmp_dir = "tmp"
|
||||||
|
|
||||||
|
[build]
|
||||||
|
args_bin = []
|
||||||
|
bin = "./tmp/main"
|
||||||
|
cmd = "make build"
|
||||||
|
delay = 1000
|
||||||
|
exclude_dir = ["assets", "tmp", "vendor", "testdata", "uploads", "dbs", "public"]
|
||||||
|
exclude_file = []
|
||||||
|
exclude_regex = ["_test.go"]
|
||||||
|
exclude_unchanged = false
|
||||||
|
follow_symlink = false
|
||||||
|
full_bin = ""
|
||||||
|
include_dir = []
|
||||||
|
include_ext = ["go", "tpl", "tmpl", "html", "css"]
|
||||||
|
include_file = []
|
||||||
|
kill_delay = "0s"
|
||||||
|
log = "build-errors.log"
|
||||||
|
poll = false
|
||||||
|
poll_interval = 0
|
||||||
|
post_cmd = []
|
||||||
|
pre_cmd = []
|
||||||
|
rerun = false
|
||||||
|
rerun_delay = 500
|
||||||
|
send_interrupt = false
|
||||||
|
stop_on_error = true
|
||||||
|
|
||||||
|
[color]
|
||||||
|
app = ""
|
||||||
|
build = "yellow"
|
||||||
|
main = "magenta"
|
||||||
|
runner = "green"
|
||||||
|
watcher = "cyan"
|
||||||
|
|
||||||
|
[log]
|
||||||
|
main_only = false
|
||||||
|
silent = false
|
||||||
|
time = false
|
||||||
|
|
||||||
|
[misc]
|
||||||
|
clean_on_exit = false
|
||||||
|
|
||||||
|
[proxy]
|
||||||
|
app_port = 0
|
||||||
|
enabled = false
|
||||||
|
proxy_port = 0
|
||||||
|
|
||||||
|
[screen]
|
||||||
|
clear_on_rebuild = false
|
||||||
|
keep_scroll = true
|
||||||
31
.github/workflows/test.yml
vendored
Normal file
31
.github/workflows/test.yml
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
name: Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version: 1.23
|
||||||
|
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cache/go-build
|
||||||
|
~/go/pkg/mod
|
||||||
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-go-
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: make test
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -1 +1,6 @@
|
||||||
.idea
|
.idea
|
||||||
|
dbs
|
||||||
|
uploads
|
||||||
|
tmp
|
||||||
|
tailwindcss
|
||||||
|
daisyui*
|
||||||
104
Makefile
104
Makefile
|
|
@ -1,52 +1,82 @@
|
||||||
# Connect to the primary database
|
# Get the OS name in lowercase (linux, darwin)
|
||||||
.PHONY: db
|
OS_SYSNAME := $(shell uname -s | tr A-Z a-z)
|
||||||
db:
|
# Get the machine architecture (x86_64, arm64)
|
||||||
psql postgresql://admin:admin@localhost:5432/app
|
OS_MACHINE := $(shell uname -m)
|
||||||
|
|
||||||
# Connect to the test database
|
# If mac OS, use `macos-arm64` or `macos-x64`
|
||||||
.PHONY: db-test
|
ifeq ($(OS_SYSNAME),darwin)
|
||||||
db-test:
|
OS_SYSNAME = macos
|
||||||
psql postgresql://admin:admin@localhost:5432/app_test
|
ifneq ($(OS_MACHINE),arm64)
|
||||||
|
OS_MACHINE = x64
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
# Connect to the cache
|
# If Linux, use `linux-x64`
|
||||||
.PHONY: cache
|
ifeq ($(OS_SYSNAME),linux)
|
||||||
cache:
|
OS_MACHINE = x64
|
||||||
redis-cli
|
endif
|
||||||
|
|
||||||
|
# The appropriate Tailwind package for your OS will attempt to be automatically determined.
|
||||||
|
# If this is not working, hard-code the package you want using these options:
|
||||||
|
# https://github.com/tailwindlabs/tailwindcss/releases/latest
|
||||||
|
TAILWIND_PACKAGE = tailwindcss-$(OS_SYSNAME)-$(OS_MACHINE)
|
||||||
|
|
||||||
|
.PHONY: help
|
||||||
|
help: ## Print make targets
|
||||||
|
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
||||||
|
.PHONY: install
|
||||||
|
install: ent-install air-install tailwind-install ## Install all dependencies
|
||||||
|
|
||||||
|
.PHONY: tailwind-install
|
||||||
|
tailwind-install: ## Install the Tailwind CSS CLI
|
||||||
|
curl -sLo tailwindcss https://github.com/tailwindlabs/tailwindcss/releases/latest/download/$(TAILWIND_PACKAGE)
|
||||||
|
chmod +x tailwindcss
|
||||||
|
curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui.js
|
||||||
|
curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui-theme.js
|
||||||
|
|
||||||
# Install Ent code-generation module
|
|
||||||
.PHONY: ent-install
|
.PHONY: ent-install
|
||||||
ent-install:
|
ent-install: ## Install Ent code-generation module
|
||||||
go get -d entgo.io/ent/cmd/ent
|
go get entgo.io/ent/cmd/ent
|
||||||
|
|
||||||
|
.PHONY: air-install
|
||||||
|
air-install: ## Install air
|
||||||
|
go install github.com/air-verse/air@latest
|
||||||
|
|
||||||
# Generate Ent code
|
|
||||||
.PHONY: ent-gen
|
.PHONY: ent-gen
|
||||||
ent-gen:
|
ent-gen: ## Generate Ent code
|
||||||
go generate ./ent
|
go generate ./ent
|
||||||
|
|
||||||
# Create a new Ent entity
|
|
||||||
.PHONY: ent-new
|
.PHONY: ent-new
|
||||||
ent-new:
|
ent-new: ## Create a new Ent entity (ie, make ent-new name=MyEntity)
|
||||||
go run entgo.io/ent/cmd/ent init $(name)
|
go run entgo.io/ent/cmd/ent new $(name)
|
||||||
|
|
||||||
# Start the Docker containers
|
.PHONY: admin
|
||||||
.PHONY: up
|
admin: ## Create a new admin user (ie, make admin email=myemail@web.com)
|
||||||
up:
|
go run cmd/admin/main.go --email=$(email)
|
||||||
docker-compose up -d
|
|
||||||
sleep 3
|
|
||||||
|
|
||||||
# Rebuild Docker containers to wipe all data
|
|
||||||
.PHONY: reset
|
|
||||||
reset:
|
|
||||||
docker-compose down
|
|
||||||
make up
|
|
||||||
|
|
||||||
# Run the application
|
|
||||||
.PHONY: run
|
.PHONY: run
|
||||||
run:
|
run: ## Run the application
|
||||||
clear
|
clear
|
||||||
go run main.go
|
go run cmd/web/main.go
|
||||||
|
|
||||||
|
.PHONY: watch
|
||||||
|
watch: ## Run the application and watch for changes with air to automatically rebuild
|
||||||
|
clear
|
||||||
|
air
|
||||||
|
|
||||||
# Run all tests
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test:
|
test: ## Run all tests
|
||||||
go test -p 1 ./...
|
go test ./...
|
||||||
|
|
||||||
|
.PHONY: check-updates
|
||||||
|
check-updates: ## Check for direct dependency updates
|
||||||
|
go list -u -m -f '{{if not .Indirect}}{{.}}{{end}}' all | grep "\["
|
||||||
|
|
||||||
|
.PHONY: css
|
||||||
|
css: ## Build and minify Tailwind CSS
|
||||||
|
./tailwindcss -i tailwind.css -o public/static/main.css -m
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build: css ## Build CSS and compile the application binary
|
||||||
|
go build -o ./tmp/main ./cmd/web
|
||||||
|
|
|
||||||
63
cmd/admin/main.go
Normal file
63
cmd/admin/main.go
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/log"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
// main creates a new admin user with the email passed in via the flag.
|
||||||
|
func main() {
|
||||||
|
// Start a new container.
|
||||||
|
c := services.NewContainer()
|
||||||
|
defer func() {
|
||||||
|
// Gracefully shutdown all services.
|
||||||
|
if err := c.Shutdown(); err != nil {
|
||||||
|
log.Default().Error("shutdown failed", "error", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var email string
|
||||||
|
flag.StringVar(&email, "email", "", "email address for the admin user")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if len(email) == 0 {
|
||||||
|
invalid("email is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a password.
|
||||||
|
pw, err := c.Auth.RandomToken(10)
|
||||||
|
if err != nil {
|
||||||
|
invalid("failed to generate a random password")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the admin user.
|
||||||
|
err = c.ORM.User.
|
||||||
|
Create().
|
||||||
|
SetEmail(email).
|
||||||
|
SetName("Admin").
|
||||||
|
SetAdmin(true).
|
||||||
|
SetVerified(true).
|
||||||
|
SetPassword(pw).
|
||||||
|
Exec(context.Background())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
invalid(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("")
|
||||||
|
fmt.Println("-- ADMIN USER CREATED --")
|
||||||
|
fmt.Printf("Email: %s\n", email)
|
||||||
|
fmt.Printf("Password: %s\n", pw)
|
||||||
|
fmt.Println("----")
|
||||||
|
fmt.Println("")
|
||||||
|
}
|
||||||
|
|
||||||
|
func invalid(msg string) {
|
||||||
|
fmt.Printf("[ERROR] %s\n", msg)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
74
cmd/web/main.go
Normal file
74
cmd/web/main.go
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/handlers"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/log"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/tasks"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Start a new container.
|
||||||
|
c := services.NewContainer()
|
||||||
|
defer func() {
|
||||||
|
// Gracefully shutdown all services.
|
||||||
|
fatal("shutdown failed", c.Shutdown())
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Build the router.
|
||||||
|
if err := handlers.BuildRouter(c); err != nil {
|
||||||
|
fatal("failed to build the router", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register all task queues.
|
||||||
|
tasks.Register(c)
|
||||||
|
|
||||||
|
// Start the task runner to execute queued tasks.
|
||||||
|
c.Tasks.Start(context.Background())
|
||||||
|
|
||||||
|
// Start the server.
|
||||||
|
go func() {
|
||||||
|
srv := http.Server{
|
||||||
|
Addr: fmt.Sprintf("%s:%d", c.Config.HTTP.Hostname, c.Config.HTTP.Port),
|
||||||
|
Handler: c.Web,
|
||||||
|
ReadTimeout: c.Config.HTTP.ReadTimeout,
|
||||||
|
WriteTimeout: c.Config.HTTP.WriteTimeout,
|
||||||
|
IdleTimeout: c.Config.HTTP.IdleTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Config.HTTP.TLS.Enabled {
|
||||||
|
certs, err := tls.LoadX509KeyPair(c.Config.HTTP.TLS.Certificate, c.Config.HTTP.TLS.Key)
|
||||||
|
fatal("cannot load TLS certificate", err)
|
||||||
|
|
||||||
|
srv.TLSConfig = &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{certs},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.Web.StartServer(&srv); errors.Is(err, http.ErrServerClosed) {
|
||||||
|
fatal("shutting down the server", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for interrupt signal to gracefully shut down the web server and task runner.
|
||||||
|
quit := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(quit, os.Interrupt)
|
||||||
|
signal.Notify(quit, os.Kill)
|
||||||
|
<-quit
|
||||||
|
}
|
||||||
|
|
||||||
|
// fatal logs an error and terminates the application, if the error is not nil.
|
||||||
|
func fatal(msg string, err error) {
|
||||||
|
if err != nil {
|
||||||
|
log.Default().Error(msg, "error", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
161
config/config.go
161
config/config.go
|
|
@ -2,115 +2,146 @@ package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/joeshaw/envdecode"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
type environment string
|
||||||
// TemplateDir stores the name of the directory that contains templates
|
|
||||||
TemplateDir = "templates"
|
|
||||||
|
|
||||||
// TemplateExt stores the extension used for the template files
|
|
||||||
TemplateExt = ".gohtml"
|
|
||||||
|
|
||||||
// StaticDir stores the name of the directory that will serve static files
|
|
||||||
StaticDir = "static"
|
|
||||||
|
|
||||||
// StaticPrefix stores the URL prefix used when serving static files
|
|
||||||
StaticPrefix = "files"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Environment string
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
EnvLocal Environment = "local"
|
// EnvLocal represents the local environment.
|
||||||
EnvTest Environment = "test"
|
EnvLocal environment = "local"
|
||||||
EnvDevelop Environment = "dev"
|
|
||||||
EnvStaging Environment = "staging"
|
// EnvTest represents the test environment.
|
||||||
EnvQA Environment = "qa"
|
EnvTest environment = "test"
|
||||||
EnvProduction Environment = "prod"
|
|
||||||
|
// EnvDevelopment represents the development environment.
|
||||||
|
EnvDevelopment environment = "dev"
|
||||||
|
|
||||||
|
// EnvStaging represents the staging environment.
|
||||||
|
EnvStaging environment = "staging"
|
||||||
|
|
||||||
|
// EnvQA represents the qa environment.
|
||||||
|
EnvQA environment = "qa"
|
||||||
|
|
||||||
|
// EnvProduction represents the production environment.
|
||||||
|
EnvProduction environment = "prod"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SwitchEnvironment sets the environment variable used to dictate which environment the application is
|
// SwitchEnvironment sets the environment variable used to dictate which environment the application is
|
||||||
// currently running in.
|
// currently running in.
|
||||||
// This must be called prior to loading the configuration in order for it to take effect.
|
// This must be called prior to loading the configuration in order for it to take effect.
|
||||||
func SwitchEnvironment(env Environment) {
|
func SwitchEnvironment(env environment) {
|
||||||
if err := os.Setenv("APP_ENVIRONMENT", string(env)); err != nil {
|
if err := os.Setenv("PAGODA_APP_ENVIRONMENT", string(env)); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// Config stores complete configuration
|
// Config stores complete configuration.
|
||||||
Config struct {
|
Config struct {
|
||||||
HTTP HTTPConfig
|
HTTP HTTPConfig
|
||||||
App AppConfig
|
App AppConfig
|
||||||
Cache CacheConfig
|
Cache CacheConfig
|
||||||
Database DatabaseConfig
|
Database DatabaseConfig
|
||||||
|
Files FilesConfig
|
||||||
|
Tasks TasksConfig
|
||||||
Mail MailConfig
|
Mail MailConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPConfig stores HTTP configuration
|
// HTTPConfig stores HTTP configuration.
|
||||||
HTTPConfig struct {
|
HTTPConfig struct {
|
||||||
Hostname string `env:"HTTP_HOSTNAME"`
|
Hostname string
|
||||||
Port uint16 `env:"HTTP_PORT,default=8000"`
|
Port uint16
|
||||||
ReadTimeout time.Duration `env:"HTTP_READ_TIMEOUT,default=5s"`
|
ReadTimeout time.Duration
|
||||||
WriteTimeout time.Duration `env:"HTTP_WRITE_TIMEOUT,default=10s"`
|
WriteTimeout time.Duration
|
||||||
IdleTimeout time.Duration `env:"HTTP_IDLE_TIMEOUT,default=2m"`
|
IdleTimeout time.Duration
|
||||||
TLS struct {
|
ShutdownTimeout time.Duration
|
||||||
Enabled bool `env:"HTTP_TLS_ENABLED,default=false"`
|
TLS struct {
|
||||||
Certificate string `env:"HTTP_TLS_CERTIFICATE"`
|
Enabled bool
|
||||||
Key string `env:"HTTP_TLS_KEY"`
|
Certificate string
|
||||||
|
Key string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppConfig stores application configuration
|
// AppConfig stores application configuration.
|
||||||
AppConfig struct {
|
AppConfig struct {
|
||||||
Name string `env:"APP_NAME,default=Goweb"`
|
Name string
|
||||||
Environment Environment `env:"APP_ENVIRONMENT,default=local"`
|
Host string
|
||||||
EncryptionKey string `env:"APP_ENCRYPTION_KEY,default=?E(G+KbPeShVmYq3t6w9z$C&F)J@McQf"`
|
Environment environment
|
||||||
Timeout time.Duration `env:"APP_TIMEOUT,default=20s"`
|
EncryptionKey string
|
||||||
|
Timeout time.Duration
|
||||||
PasswordToken struct {
|
PasswordToken struct {
|
||||||
Expiration time.Duration `env:"APP_PASSWORD_TOKEN_EXPIRATION,default=60m"`
|
Expiration time.Duration
|
||||||
Length int `env:"APP_PASSWORD_TOKEN_LENGTH,default=64"`
|
Length int
|
||||||
}
|
}
|
||||||
|
EmailVerificationTokenExpiration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// CacheConfig stores the cache configuration
|
// CacheConfig stores the cache configuration.
|
||||||
CacheConfig struct {
|
CacheConfig struct {
|
||||||
Hostname string `env:"CACHE_HOSTNAME,default=localhost"`
|
Capacity int
|
||||||
Port uint16 `env:"CACHE_PORT,default=6379"`
|
|
||||||
Password string `env:"CACHE_PASSWORD"`
|
|
||||||
Expiration struct {
|
Expiration struct {
|
||||||
StaticFile time.Duration `env:"CACHE_EXPIRATION_STATIC_FILE,default=4380h"`
|
PublicFile time.Duration
|
||||||
Page time.Duration `env:"CACHE_EXPIRATION_PAGE,default=24h"`
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DatabaseConfig stores the database configuration
|
// DatabaseConfig stores the database configuration.
|
||||||
DatabaseConfig struct {
|
DatabaseConfig struct {
|
||||||
Hostname string `env:"DB_HOSTNAME,default=localhost"`
|
Driver string
|
||||||
Port uint16 `env:"DB_PORT,default=5432"`
|
Connection string
|
||||||
User string `env:"DB_USER,default=admin"`
|
TestConnection string
|
||||||
Password string `env:"DB_PASSWORD,default=admin"`
|
|
||||||
Database string `env:"DB_NAME,default=app"`
|
|
||||||
TestDatabase string `env:"DB_NAME_TEST,default=app_test"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MailConfig stores the mail configuration
|
// FilesConfig stores the file system configuration.
|
||||||
|
FilesConfig struct {
|
||||||
|
Directory string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TasksConfig stores the tasks configuration.
|
||||||
|
TasksConfig struct {
|
||||||
|
Goroutines int
|
||||||
|
ReleaseAfter time.Duration
|
||||||
|
CleanupInterval time.Duration
|
||||||
|
ShutdownTimeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// MailConfig stores the mail configuration.
|
||||||
MailConfig struct {
|
MailConfig struct {
|
||||||
Hostname string `env:"MAIL_HOSTNAME,default=localhost"`
|
Hostname string
|
||||||
Port uint16 `env:"MAIL_PORT,default=25"`
|
Port uint16
|
||||||
User string `env:"MAIL_USER,default=admin"`
|
User string
|
||||||
Password string `env:"MAIL_PASSWORD,default=admin"`
|
Password string
|
||||||
FromAddress string `env:"MAIL_FROM_ADDRESS,default=admin@localhost"`
|
FromAddress string
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetConfig loads and returns configuration
|
// GetConfig loads and returns configuration.
|
||||||
func GetConfig() (Config, error) {
|
func GetConfig() (Config, error) {
|
||||||
var cfg Config
|
var c Config
|
||||||
err := envdecode.StrictDecode(&cfg)
|
|
||||||
return cfg, err
|
// Load the config file.
|
||||||
|
viper.SetConfigName("config")
|
||||||
|
viper.SetConfigType("yaml")
|
||||||
|
viper.AddConfigPath(".")
|
||||||
|
viper.AddConfigPath("config")
|
||||||
|
viper.AddConfigPath("../config")
|
||||||
|
viper.AddConfigPath("../../config")
|
||||||
|
|
||||||
|
// Load env variables.
|
||||||
|
viper.SetEnvPrefix("pagoda")
|
||||||
|
viper.AutomaticEnv()
|
||||||
|
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||||
|
|
||||||
|
if err := viper.ReadInConfig(); err != nil {
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := viper.Unmarshal(&c); err != nil {
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
54
config/config.yaml
Normal file
54
config/config.yaml
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
http:
|
||||||
|
hostname: ""
|
||||||
|
port: 8000
|
||||||
|
readTimeout: "5s"
|
||||||
|
writeTimeout: "10s"
|
||||||
|
idleTimeout: "2m"
|
||||||
|
shutdownTimeout: "10s"
|
||||||
|
tls:
|
||||||
|
enabled: false
|
||||||
|
certificate: ""
|
||||||
|
key: ""
|
||||||
|
|
||||||
|
app:
|
||||||
|
name: "Pagoda"
|
||||||
|
# We manually set this rather than using the HTTP settings in order to build absolute URLs for users
|
||||||
|
# since it's likely your app's HTTP settings are not identical to what is exposed by your server.
|
||||||
|
host: "http://localhost:8000"
|
||||||
|
environment: "local"
|
||||||
|
# Change this on any live environments.
|
||||||
|
encryptionKey: "?E(G+KbPeShVmYq3t6w9z$C&F)J@McQf"
|
||||||
|
timeout: "20s"
|
||||||
|
passwordToken:
|
||||||
|
expiration: "60m"
|
||||||
|
length: 64
|
||||||
|
emailVerificationTokenExpiration: "12h"
|
||||||
|
|
||||||
|
cache:
|
||||||
|
capacity: 100000
|
||||||
|
expiration:
|
||||||
|
publicFile: "4380h"
|
||||||
|
|
||||||
|
database:
|
||||||
|
driver: "sqlite3"
|
||||||
|
connection: "dbs/main.db?_journal=WAL&_timeout=5000&_fk=true"
|
||||||
|
# $RAND will be automatically replaced with a random value.
|
||||||
|
# memdb is more robust for an in-memory database rather than :memory: because the latter has the potential
|
||||||
|
# retain data even after you close and re-open the connection.
|
||||||
|
testConnection: "file:/$RAND?vfs=memdb&_timeout=1000&_fk=true"
|
||||||
|
|
||||||
|
files:
|
||||||
|
directory: "uploads"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
goroutines: 1
|
||||||
|
releaseAfter: "15m"
|
||||||
|
cleanupInterval: "1h"
|
||||||
|
shutdownTimeout: "10s"
|
||||||
|
|
||||||
|
mail:
|
||||||
|
hostname: "localhost"
|
||||||
|
port: 25
|
||||||
|
user: "admin"
|
||||||
|
password: "admin"
|
||||||
|
fromAddress: "admin@localhost"
|
||||||
|
|
@ -11,7 +11,7 @@ func TestGetConfig(t *testing.T) {
|
||||||
_, err := GetConfig()
|
_, err := GetConfig()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var env Environment
|
var env environment
|
||||||
env = "abc"
|
env = "abc"
|
||||||
SwitchEnvironment(env)
|
SwitchEnvironment(env)
|
||||||
cfg, err := GetConfig()
|
cfg, err := GetConfig()
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
package context
|
|
||||||
|
|
||||||
const (
|
|
||||||
// AuthenticatedUserKey is the key value used to store the authenticated user in context
|
|
||||||
AuthenticatedUserKey = "auth_user"
|
|
||||||
|
|
||||||
// UserKey is the key value used to store a user in context
|
|
||||||
UserKey = "user"
|
|
||||||
|
|
||||||
// FormKey is the key value used to store a form in context
|
|
||||||
FormKey = "form"
|
|
||||||
|
|
||||||
// PasswordTokenKey is the key value used to store a password token in context
|
|
||||||
PasswordTokenKey = "password_token"
|
|
||||||
)
|
|
||||||
|
|
@ -1,163 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"goweb/middleware"
|
|
||||||
"goweb/services"
|
|
||||||
|
|
||||||
"github.com/eko/gocache/v2/marshaler"
|
|
||||||
|
|
||||||
"github.com/eko/gocache/v2/store"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Controller provides base functionality and dependencies to routes.
|
|
||||||
// The proposed pattern is to embed a Controller in each individual route struct and to use
|
|
||||||
// the router to inject the container so your routes have access to the services within the container
|
|
||||||
type Controller struct {
|
|
||||||
// Container stores a services container which contains dependencies
|
|
||||||
Container *services.Container
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewController creates a new Controller
|
|
||||||
func NewController(c *services.Container) Controller {
|
|
||||||
return Controller{
|
|
||||||
Container: c,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenderPage renders a Page as an HTTP response
|
|
||||||
func (c *Controller) RenderPage(ctx echo.Context, page Page) error {
|
|
||||||
var buf *bytes.Buffer
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// Page name is required
|
|
||||||
if page.Name == "" {
|
|
||||||
ctx.Logger().Error("page render failed due to missing name")
|
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the app name in configuration if a value was not set
|
|
||||||
if page.AppName == "" {
|
|
||||||
page.AppName = c.Container.Config.App.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if this is an HTMX non-boosted request which indicates that only partial
|
|
||||||
// content should be rendered
|
|
||||||
if page.HTMX.Request.Enabled && !page.HTMX.Request.Boosted {
|
|
||||||
// Parse and execute the templates only for the content portion of the page
|
|
||||||
// The templates used for this partial request will be:
|
|
||||||
// 1. The base htmx template which omits the layout and only includes the content template
|
|
||||||
// 2. The content template specified in Page.Name
|
|
||||||
// 3. All templates within the components directory
|
|
||||||
// Also included is the function map provided by the funcmap package
|
|
||||||
buf, err = c.Container.TemplateRenderer.ParseAndExecute(
|
|
||||||
"page:htmx",
|
|
||||||
page.Name,
|
|
||||||
"htmx",
|
|
||||||
[]string{
|
|
||||||
"htmx",
|
|
||||||
fmt.Sprintf("pages/%s", page.Name),
|
|
||||||
},
|
|
||||||
[]string{"components"},
|
|
||||||
page,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
// Parse and execute the templates for the Page
|
|
||||||
// As mentioned in the documentation for the Page struct, the templates used for the page will be:
|
|
||||||
// 1. The layout/base template specified in Page.Layout
|
|
||||||
// 2. The content template specified in Page.Name
|
|
||||||
// 3. All templates within the components directory
|
|
||||||
// Also included is the function map provided by the funcmap package
|
|
||||||
buf, err = c.Container.TemplateRenderer.ParseAndExecute(
|
|
||||||
"page",
|
|
||||||
page.Name,
|
|
||||||
page.Layout,
|
|
||||||
[]string{
|
|
||||||
fmt.Sprintf("layouts/%s", page.Layout),
|
|
||||||
fmt.Sprintf("pages/%s", page.Name),
|
|
||||||
},
|
|
||||||
[]string{"components"},
|
|
||||||
page,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
ctx.Logger().Errorf("failed to parse and execute templates: %v", err)
|
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the status code
|
|
||||||
ctx.Response().Status = page.StatusCode
|
|
||||||
|
|
||||||
// Set any headers
|
|
||||||
for k, v := range page.Headers {
|
|
||||||
ctx.Response().Header().Set(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the HTMX response, if one
|
|
||||||
if page.HTMX.Response != nil {
|
|
||||||
page.HTMX.Response.Apply(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache this page, if caching was enabled
|
|
||||||
c.cachePage(ctx, page, buf)
|
|
||||||
|
|
||||||
return ctx.HTMLBlob(ctx.Response().Status, buf.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
// cachePage caches the HTML for a given Page if the Page has caching enabled
|
|
||||||
func (c *Controller) cachePage(ctx echo.Context, page Page, html *bytes.Buffer) {
|
|
||||||
if !page.Cache.Enabled {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no expiration time was provided, default to the configuration value
|
|
||||||
if page.Cache.Expiration == 0 {
|
|
||||||
page.Cache.Expiration = c.Container.Config.Cache.Expiration.Page
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the headers
|
|
||||||
headers := make(map[string]string)
|
|
||||||
for k, v := range ctx.Response().Header() {
|
|
||||||
headers[k] = v[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// The request URL is used as the cache key so the middleware can serve the
|
|
||||||
// cached page on matching requests
|
|
||||||
key := ctx.Request().URL.String()
|
|
||||||
opts := &store.Options{
|
|
||||||
Expiration: page.Cache.Expiration,
|
|
||||||
Tags: page.Cache.Tags,
|
|
||||||
}
|
|
||||||
cp := middleware.CachedPage{
|
|
||||||
URL: key,
|
|
||||||
HTML: html.Bytes(),
|
|
||||||
Headers: headers,
|
|
||||||
StatusCode: ctx.Response().Status,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := marshaler.New(c.Container.Cache).Set(ctx.Request().Context(), key, cp, opts)
|
|
||||||
if err != nil {
|
|
||||||
ctx.Logger().Errorf("failed to cache page: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Logger().Infof("cached page")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redirect redirects to a given route name with optional route parameters
|
|
||||||
func (c *Controller) Redirect(ctx echo.Context, route string, routeParams ...interface{}) error {
|
|
||||||
url := ctx.Echo().Reverse(route, routeParams)
|
|
||||||
return ctx.Redirect(http.StatusFound, url)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fail is a helper to fail a request by returning a 500 error and logging the error
|
|
||||||
func (c *Controller) Fail(ctx echo.Context, err error, log string) error {
|
|
||||||
ctx.Logger().Errorf("%s: %v", log, err)
|
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"goweb/config"
|
|
||||||
"goweb/htmx"
|
|
||||||
"goweb/middleware"
|
|
||||||
"goweb/services"
|
|
||||||
"goweb/tests"
|
|
||||||
|
|
||||||
"github.com/eko/gocache/v2/store"
|
|
||||||
|
|
||||||
"github.com/eko/gocache/v2/marshaler"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
c *services.Container
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
// Set the environment to test
|
|
||||||
config.SwitchEnvironment(config.EnvTest)
|
|
||||||
|
|
||||||
// Create a new container
|
|
||||||
c = services.NewContainer()
|
|
||||||
defer func() {
|
|
||||||
if err := c.Shutdown(); err != nil {
|
|
||||||
c.Web.Logger.Fatal(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Run tests
|
|
||||||
exitVal := m.Run()
|
|
||||||
os.Exit(exitVal)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestController_Redirect(t *testing.T) {
|
|
||||||
ctx, _ := tests.NewContext(c.Web, "/abc")
|
|
||||||
ctr := NewController(c)
|
|
||||||
err := ctr.Redirect(ctx, "home")
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, "", ctx.Response().Header().Get(echo.HeaderLocation))
|
|
||||||
assert.Equal(t, http.StatusFound, ctx.Response().Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestController_RenderPage(t *testing.T) {
|
|
||||||
setup := func() (echo.Context, *httptest.ResponseRecorder, Controller, Page) {
|
|
||||||
ctx, rec := tests.NewContext(c.Web, "/test/TestController_RenderPage")
|
|
||||||
tests.InitSession(ctx)
|
|
||||||
ctr := NewController(c)
|
|
||||||
|
|
||||||
p := NewPage(ctx)
|
|
||||||
p.Name = "home"
|
|
||||||
p.Layout = "main"
|
|
||||||
p.Cache.Enabled = false
|
|
||||||
p.Headers["A"] = "b"
|
|
||||||
p.Headers["C"] = "d"
|
|
||||||
p.StatusCode = http.StatusCreated
|
|
||||||
return ctx, rec, ctr, p
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run("missing name", func(t *testing.T) {
|
|
||||||
// Rendering should fail if the Page has no name
|
|
||||||
ctx, _, ctr, p := setup()
|
|
||||||
p.Name = ""
|
|
||||||
err := ctr.RenderPage(ctx, p)
|
|
||||||
assert.Error(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("no page cache", func(t *testing.T) {
|
|
||||||
ctx, _, ctr, p := setup()
|
|
||||||
err := ctr.RenderPage(ctx, p)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Check status code and headers
|
|
||||||
assert.Equal(t, http.StatusCreated, ctx.Response().Status)
|
|
||||||
for k, v := range p.Headers {
|
|
||||||
assert.Equal(t, v, ctx.Response().Header().Get(k))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the template cache
|
|
||||||
parsed, err := c.TemplateRenderer.Load("page", p.Name)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Check that all expected templates were parsed.
|
|
||||||
// This includes the name, layout and all components
|
|
||||||
expectedTemplates := make(map[string]bool)
|
|
||||||
expectedTemplates[p.Name+config.TemplateExt] = true
|
|
||||||
expectedTemplates[p.Layout+config.TemplateExt] = true
|
|
||||||
components, err := ioutil.ReadDir(c.TemplateRenderer.GetTemplatesPath() + "/components")
|
|
||||||
require.NoError(t, err)
|
|
||||||
for _, f := range components {
|
|
||||||
expectedTemplates[f.Name()] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range parsed.Templates() {
|
|
||||||
delete(expectedTemplates, v.Name())
|
|
||||||
}
|
|
||||||
assert.Empty(t, expectedTemplates)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("htmx rendering", func(t *testing.T) {
|
|
||||||
ctx, _, ctr, p := setup()
|
|
||||||
p.HTMX.Request.Enabled = true
|
|
||||||
p.HTMX.Response = &htmx.Response{
|
|
||||||
Trigger: "trigger",
|
|
||||||
}
|
|
||||||
err := ctr.RenderPage(ctx, p)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Check HTMX header
|
|
||||||
assert.Equal(t, "trigger", ctx.Response().Header().Get(htmx.HeaderTrigger))
|
|
||||||
|
|
||||||
// Check the template cache
|
|
||||||
parsed, err := c.TemplateRenderer.Load("page:htmx", p.Name)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Check that all expected templates were parsed.
|
|
||||||
// This includes the name, htmx and all components
|
|
||||||
expectedTemplates := make(map[string]bool)
|
|
||||||
expectedTemplates[p.Name+config.TemplateExt] = true
|
|
||||||
expectedTemplates["htmx"+config.TemplateExt] = true
|
|
||||||
components, err := ioutil.ReadDir(c.TemplateRenderer.GetTemplatesPath() + "/components")
|
|
||||||
require.NoError(t, err)
|
|
||||||
for _, f := range components {
|
|
||||||
expectedTemplates[f.Name()] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range parsed.Templates() {
|
|
||||||
delete(expectedTemplates, v.Name())
|
|
||||||
}
|
|
||||||
assert.Empty(t, expectedTemplates)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("page cache", func(t *testing.T) {
|
|
||||||
ctx, rec, ctr, p := setup()
|
|
||||||
p.Cache.Enabled = true
|
|
||||||
p.Cache.Tags = []string{"tag1"}
|
|
||||||
err := ctr.RenderPage(ctx, p)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Fetch from the cache
|
|
||||||
res, err := marshaler.New(c.Cache).
|
|
||||||
Get(context.Background(), p.URL, new(middleware.CachedPage))
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Compare the cached page
|
|
||||||
cp, ok := res.(*middleware.CachedPage)
|
|
||||||
require.True(t, ok)
|
|
||||||
assert.Equal(t, p.URL, cp.URL)
|
|
||||||
assert.Equal(t, p.Headers, cp.Headers)
|
|
||||||
assert.Equal(t, p.StatusCode, cp.StatusCode)
|
|
||||||
assert.Equal(t, rec.Body.Bytes(), cp.HTML)
|
|
||||||
|
|
||||||
// Clear the tag
|
|
||||||
err = c.Cache.Invalidate(context.Background(), store.InvalidateOptions{
|
|
||||||
Tags: []string{p.Cache.Tags[0]},
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Refetch from the cache and expect no results
|
|
||||||
_, err = marshaler.New(c.Cache).
|
|
||||||
Get(context.Background(), p.URL, new(middleware.CachedPage))
|
|
||||||
assert.Error(t, err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/go-playground/validator/v10"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FormSubmission represents the state of the submission of a form, not including the form itself
|
|
||||||
type FormSubmission struct {
|
|
||||||
// IsSubmitted indicates if the form has been submitted
|
|
||||||
IsSubmitted bool
|
|
||||||
|
|
||||||
// Errors stores a slice of error message strings keyed by form struct field name
|
|
||||||
Errors map[string][]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process processes a submission for a form
|
|
||||||
func (f *FormSubmission) Process(ctx echo.Context, form interface{}) error {
|
|
||||||
f.Errors = make(map[string][]string)
|
|
||||||
f.IsSubmitted = true
|
|
||||||
|
|
||||||
// Validate the form
|
|
||||||
if err := ctx.Validate(form); err != nil {
|
|
||||||
f.setErrorMessages(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasErrors indicates if the submission has any validation errors
|
|
||||||
func (f FormSubmission) HasErrors() bool {
|
|
||||||
if f.Errors == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return len(f.Errors) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// FieldHasErrors indicates if a given field on the form has any validation errors
|
|
||||||
func (f FormSubmission) FieldHasErrors(fieldName string) bool {
|
|
||||||
return len(f.GetFieldErrors(fieldName)) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetFieldError sets an error message for a given field name
|
|
||||||
func (f *FormSubmission) SetFieldError(fieldName string, message string) {
|
|
||||||
if f.Errors == nil {
|
|
||||||
f.Errors = make(map[string][]string)
|
|
||||||
}
|
|
||||||
f.Errors[fieldName] = append(f.Errors[fieldName], message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFieldErrors gets the errors for a given field name
|
|
||||||
func (f FormSubmission) GetFieldErrors(fieldName string) []string {
|
|
||||||
if f.Errors == nil {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
return f.Errors[fieldName]
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFieldStatusClass returns an HTML class based on the status of the field
|
|
||||||
func (f FormSubmission) GetFieldStatusClass(fieldName string) string {
|
|
||||||
if f.IsSubmitted {
|
|
||||||
if f.FieldHasErrors(fieldName) {
|
|
||||||
return "is-danger"
|
|
||||||
}
|
|
||||||
return "is-success"
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsDone indicates if the submission is considered done which is when it has been submitted
|
|
||||||
// and there are no errors.
|
|
||||||
func (f FormSubmission) IsDone() bool {
|
|
||||||
return f.IsSubmitted && !f.HasErrors()
|
|
||||||
}
|
|
||||||
|
|
||||||
// setErrorMessages sets errors messages on the submission for all fields that failed validation
|
|
||||||
func (f *FormSubmission) setErrorMessages(err error) {
|
|
||||||
// Only this is supported right now
|
|
||||||
ves, ok := err.(validator.ValidationErrors)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ve := range ves {
|
|
||||||
var message string
|
|
||||||
|
|
||||||
// Provide better error messages depending on the failed validation tag
|
|
||||||
// This should be expanded as you use additional tags in your validation
|
|
||||||
switch ve.Tag() {
|
|
||||||
case "required":
|
|
||||||
message = "This field is required."
|
|
||||||
case "email":
|
|
||||||
message = "Enter a valid email address."
|
|
||||||
case "eqfield":
|
|
||||||
message = "Does not match."
|
|
||||||
default:
|
|
||||||
message = "Invalid value."
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the error
|
|
||||||
f.SetFieldError(ve.Field(), message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"goweb/tests"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFormSubmission(t *testing.T) {
|
|
||||||
type formTest struct {
|
|
||||||
Name string `validate:"required"`
|
|
||||||
Email string `validate:"required,email"`
|
|
||||||
Submission FormSubmission
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, _ := tests.NewContext(c.Web, "/")
|
|
||||||
form := formTest{
|
|
||||||
Name: "",
|
|
||||||
Email: "a@a.com",
|
|
||||||
}
|
|
||||||
err := form.Submission.Process(ctx, form)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.True(t, form.Submission.HasErrors())
|
|
||||||
assert.True(t, form.Submission.FieldHasErrors("Name"))
|
|
||||||
assert.False(t, form.Submission.FieldHasErrors("Email"))
|
|
||||||
require.Len(t, form.Submission.GetFieldErrors("Name"), 1)
|
|
||||||
assert.Len(t, form.Submission.GetFieldErrors("Email"), 0)
|
|
||||||
assert.Equal(t, "This field is required.", form.Submission.GetFieldErrors("Name")[0])
|
|
||||||
assert.Equal(t, "is-danger", form.Submission.GetFieldStatusClass("Name"))
|
|
||||||
assert.Equal(t, "is-success", form.Submission.GetFieldStatusClass("Email"))
|
|
||||||
assert.False(t, form.Submission.IsDone())
|
|
||||||
}
|
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"html/template"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"goweb/context"
|
|
||||||
"goweb/ent"
|
|
||||||
"goweb/htmx"
|
|
||||||
"goweb/msg"
|
|
||||||
|
|
||||||
echomw "github.com/labstack/echo/v4/middleware"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Page consists of all data that will be used to render a page response for a given controller.
|
|
||||||
// While it's not required for a controller to render a Page on a route, this is the common data
|
|
||||||
// object that will be passed to the templates, making it easy for all controllers to share
|
|
||||||
// functionality both on the back and frontend. The Page can be expanded to include anything else
|
|
||||||
// your app wants to support.
|
|
||||||
// Methods on this page also then become available in the templates, which can be more useful than
|
|
||||||
// the funcmap if your methods require data stored in the page, such as the context.
|
|
||||||
type Page struct {
|
|
||||||
// AppName stores the name of the application.
|
|
||||||
// If omitted, the configuration value will be used.
|
|
||||||
AppName string
|
|
||||||
|
|
||||||
// Title stores the title of the page
|
|
||||||
Title string
|
|
||||||
|
|
||||||
// Context stores the request context
|
|
||||||
Context echo.Context
|
|
||||||
|
|
||||||
// ToURL is a function to convert a route name and optional route parameters to a URL
|
|
||||||
ToURL func(name string, params ...interface{}) string
|
|
||||||
|
|
||||||
// Path stores the path of the current request
|
|
||||||
Path string
|
|
||||||
|
|
||||||
// URL stores the URL of the current request
|
|
||||||
URL string
|
|
||||||
|
|
||||||
// Data stores whatever additional data that needs to be passed to the templates.
|
|
||||||
// This is what the controller uses to pass the content of the page.
|
|
||||||
Data interface{}
|
|
||||||
|
|
||||||
// Form stores a struct that represents a form on the page.
|
|
||||||
// This should be a struct with fields for each form field, using both "form" and "validate" tags
|
|
||||||
// It should also contain a Submission field of type FormSubmission if you wish to have validation
|
|
||||||
// messagesa and markup presented to the user
|
|
||||||
Form interface{}
|
|
||||||
|
|
||||||
// Layout stores the name of the layout base template file which will be used when the page is rendered.
|
|
||||||
// This should match a template file located within the layouts directory inside the templates directory.
|
|
||||||
// The template extension should not be included in this value.
|
|
||||||
Layout string
|
|
||||||
|
|
||||||
// Name stores the name of the page as well as the name of the template file which will be used to render
|
|
||||||
// the content portion of the layout template.
|
|
||||||
// This should match a template file located within the pages directory inside the templates directory.
|
|
||||||
// The template extension should not be included in this value.
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// IsHome stores whether the requested page is the home page or not
|
|
||||||
IsHome bool
|
|
||||||
|
|
||||||
// IsAuth stores whether or not the user is authenticated
|
|
||||||
IsAuth bool
|
|
||||||
|
|
||||||
// AuthUser stores the authenticated user
|
|
||||||
AuthUser *ent.User
|
|
||||||
|
|
||||||
// StatusCode stores the HTTP status code that will be returned
|
|
||||||
StatusCode int
|
|
||||||
|
|
||||||
// Metatags stores metatag values
|
|
||||||
Metatags struct {
|
|
||||||
// Description stores the description metatag value
|
|
||||||
Description string
|
|
||||||
|
|
||||||
// Keywords stores the keywords metatag values
|
|
||||||
Keywords []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pager stores a pager which can be used to page lists of results
|
|
||||||
Pager Pager
|
|
||||||
|
|
||||||
// CSRF stores the CSRF token for the given request.
|
|
||||||
// This will only be populated if the CSRF middleware is in effect for the given request.
|
|
||||||
// If this is populated, all forms must include this value otherwise the requests will be rejected.
|
|
||||||
CSRF string
|
|
||||||
|
|
||||||
// Headers stores a list of HTTP headers and values to be set on the response
|
|
||||||
Headers map[string]string
|
|
||||||
|
|
||||||
// RequestID stores the ID of the given request.
|
|
||||||
// This will only be populated if the request ID middleware is in effect for the given request.
|
|
||||||
RequestID string
|
|
||||||
|
|
||||||
HTMX struct {
|
|
||||||
Request htmx.Request
|
|
||||||
Response *htmx.Response
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache stores values for caching the response of this page
|
|
||||||
Cache struct {
|
|
||||||
// Enabled dictates if the response of this page should be cached.
|
|
||||||
// Cached responses are served via middleware.
|
|
||||||
Enabled bool
|
|
||||||
|
|
||||||
// Expiration stores the amount of time that the cache entry should live for before expiring.
|
|
||||||
// If omitted, the configuration value will be used.
|
|
||||||
Expiration time.Duration
|
|
||||||
|
|
||||||
// Tags stores a list of tags to apply to the cache entry.
|
|
||||||
// These are useful when invalidating cache for dynamic events such as entity operations.
|
|
||||||
Tags []string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPage creates and initiatizes a new Page for a given request context
|
|
||||||
func NewPage(ctx echo.Context) Page {
|
|
||||||
p := Page{
|
|
||||||
Context: ctx,
|
|
||||||
ToURL: ctx.Echo().Reverse,
|
|
||||||
Path: ctx.Request().URL.Path,
|
|
||||||
URL: ctx.Request().URL.String(),
|
|
||||||
StatusCode: http.StatusOK,
|
|
||||||
Pager: NewPager(ctx, DefaultItemsPerPage),
|
|
||||||
Headers: make(map[string]string),
|
|
||||||
RequestID: ctx.Response().Header().Get(echo.HeaderXRequestID),
|
|
||||||
}
|
|
||||||
|
|
||||||
p.IsHome = p.Path == "/"
|
|
||||||
|
|
||||||
if csrf := ctx.Get(echomw.DefaultCSRFConfig.ContextKey); csrf != nil {
|
|
||||||
p.CSRF = csrf.(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
if u := ctx.Get(context.AuthenticatedUserKey); u != nil {
|
|
||||||
p.IsAuth = true
|
|
||||||
p.AuthUser = u.(*ent.User)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.HTMX.Request = htmx.GetRequest(ctx)
|
|
||||||
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMessages gets all flash messages for a given type.
|
|
||||||
// This allows for easy access to flash messages from the templates.
|
|
||||||
func (p Page) GetMessages(typ msg.Type) []template.HTML {
|
|
||||||
strs := msg.Get(p.Context, typ)
|
|
||||||
ret := make([]template.HTML, len(strs))
|
|
||||||
for k, v := range strs {
|
|
||||||
ret[k] = template.HTML(v)
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"goweb/context"
|
|
||||||
"goweb/msg"
|
|
||||||
"goweb/tests"
|
|
||||||
|
|
||||||
echomw "github.com/labstack/echo/v4/middleware"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNewPage(t *testing.T) {
|
|
||||||
ctx, _ := tests.NewContext(c.Web, "/")
|
|
||||||
p := NewPage(ctx)
|
|
||||||
assert.Same(t, ctx, p.Context)
|
|
||||||
assert.NotNil(t, p.ToURL)
|
|
||||||
assert.Equal(t, "/", p.Path)
|
|
||||||
assert.Equal(t, "/", p.URL)
|
|
||||||
assert.Equal(t, http.StatusOK, p.StatusCode)
|
|
||||||
assert.Equal(t, NewPager(ctx, DefaultItemsPerPage), p.Pager)
|
|
||||||
assert.Empty(t, p.Headers)
|
|
||||||
assert.True(t, p.IsHome)
|
|
||||||
assert.False(t, p.IsAuth)
|
|
||||||
assert.Empty(t, p.CSRF)
|
|
||||||
assert.Empty(t, p.RequestID)
|
|
||||||
assert.False(t, p.Cache.Enabled)
|
|
||||||
|
|
||||||
ctx, _ = tests.NewContext(c.Web, "/abc?def=123")
|
|
||||||
usr, err := tests.CreateUser(c.ORM)
|
|
||||||
require.NoError(t, err)
|
|
||||||
ctx.Set(context.AuthenticatedUserKey, usr)
|
|
||||||
ctx.Set(echomw.DefaultCSRFConfig.ContextKey, "csrf")
|
|
||||||
p = NewPage(ctx)
|
|
||||||
assert.Equal(t, "/abc", p.Path)
|
|
||||||
assert.Equal(t, "/abc?def=123", p.URL)
|
|
||||||
assert.False(t, p.IsHome)
|
|
||||||
assert.True(t, p.IsAuth)
|
|
||||||
assert.Equal(t, usr, p.AuthUser)
|
|
||||||
assert.Equal(t, "csrf", p.CSRF)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPage_GetMessages(t *testing.T) {
|
|
||||||
ctx, _ := tests.NewContext(c.Web, "/")
|
|
||||||
tests.InitSession(ctx)
|
|
||||||
p := NewPage(ctx)
|
|
||||||
|
|
||||||
// Set messages
|
|
||||||
msgTests := make(map[msg.Type][]string)
|
|
||||||
msgTests[msg.TypeWarning] = []string{
|
|
||||||
"abc",
|
|
||||||
"def",
|
|
||||||
}
|
|
||||||
msgTests[msg.TypeInfo] = []string{
|
|
||||||
"123",
|
|
||||||
"456",
|
|
||||||
}
|
|
||||||
for typ, values := range msgTests {
|
|
||||||
for _, value := range values {
|
|
||||||
msg.Set(ctx, typ, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the messages
|
|
||||||
for typ, values := range msgTests {
|
|
||||||
msgs := p.GetMessages(typ)
|
|
||||||
|
|
||||||
for i, message := range msgs {
|
|
||||||
assert.Equal(t, values[i], string(message))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
version: "3"
|
|
||||||
|
|
||||||
services:
|
|
||||||
cache:
|
|
||||||
image: "redis:alpine"
|
|
||||||
ports:
|
|
||||||
- "6379:6379"
|
|
||||||
db:
|
|
||||||
image: postgres:alpine
|
|
||||||
ports:
|
|
||||||
- "5432:5432"
|
|
||||||
environment:
|
|
||||||
- POSTGRES_USER=admin
|
|
||||||
- POSTGRES_PASSWORD=admin
|
|
||||||
- POSTGRES_DB=app
|
|
||||||
97
ent/admin/extension.go
Normal file
97
ent/admin/extension.go
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
"entgo.io/ent/entc"
|
||||||
|
"entgo.io/ent/entc/gen"
|
||||||
|
"entgo.io/ent/schema/field"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed templates
|
||||||
|
templateDir embed.FS
|
||||||
|
)
|
||||||
|
|
||||||
|
// Extension is the Ent extension that generates code to support the entity admin panel.
|
||||||
|
type Extension struct {
|
||||||
|
entc.DefaultExtension
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Extension) Templates() []*gen.Template {
|
||||||
|
return []*gen.Template{
|
||||||
|
gen.MustParse(
|
||||||
|
gen.NewTemplate("admin").
|
||||||
|
Funcs(template.FuncMap{
|
||||||
|
"fieldName": fieldName,
|
||||||
|
"fieldLabel": FieldLabel,
|
||||||
|
"fieldIsPointer": fieldIsPointer,
|
||||||
|
}).
|
||||||
|
ParseFS(templateDir, "templates/*tmpl"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fieldName provides a struct field name from an entity field name (ie, user_id -> UserID).
|
||||||
|
func fieldName(name string) string {
|
||||||
|
if len(name) == 0 {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(name, "_")
|
||||||
|
for i := 0; i < len(parts); i++ {
|
||||||
|
if parts[i] == "id" {
|
||||||
|
parts[i] = "ID"
|
||||||
|
} else {
|
||||||
|
parts[i] = upperFirst(parts[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(parts, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// FieldLabel provides a label for an entity field name (ie, user_id -> User ID).
|
||||||
|
func FieldLabel(name string) string {
|
||||||
|
if len(name) == 0 {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(name, "_")
|
||||||
|
for i := 0; i < len(parts); i++ {
|
||||||
|
if parts[i] == "id" {
|
||||||
|
parts[i] = "ID"
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
parts[i] = upperFirst(parts[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(parts, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// fieldIsPointer determines if a given entity field should be a pointer on the struct.
|
||||||
|
func fieldIsPointer(f *gen.Field) bool {
|
||||||
|
switch {
|
||||||
|
case f.Type.Type == field.TypeBool:
|
||||||
|
return false
|
||||||
|
case f.Optional,
|
||||||
|
f.Default,
|
||||||
|
f.Sensitive(),
|
||||||
|
f.Nillable:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// upperFirst uppercases the first character of a given string.
|
||||||
|
func upperFirst(s string) string {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
out := []rune(s)
|
||||||
|
out[0] = unicode.ToUpper(out[0])
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
319
ent/admin/handler.go
Normal file
319
ent/admin/handler.go
Normal file
|
|
@ -0,0 +1,319 @@
|
||||||
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
|
||||||
|
"github.com/mikestefanello/pagoda/ent"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/passwordtoken"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
const dateTimeFormat = "2006-01-02T15:04:05"
|
||||||
|
const dateTimeFormatNoSeconds = "2006-01-02T15:04"
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
client *ent.Client
|
||||||
|
Config HandlerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(client *ent.Client, cfg HandlerConfig) *Handler {
|
||||||
|
return &Handler{
|
||||||
|
client: client,
|
||||||
|
Config: cfg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) Create(ctx echo.Context, entityType EntityType) error {
|
||||||
|
switch entityType.(type) {
|
||||||
|
case *PasswordToken:
|
||||||
|
return h.PasswordTokenCreate(ctx)
|
||||||
|
case *User:
|
||||||
|
return h.UserCreate(ctx)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported entity type: %s", entityType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) Get(ctx echo.Context, entityType EntityType, id int) (url.Values, error) {
|
||||||
|
switch entityType.(type) {
|
||||||
|
case *PasswordToken:
|
||||||
|
return h.PasswordTokenGet(ctx, id)
|
||||||
|
case *User:
|
||||||
|
return h.UserGet(ctx, id)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported entity type: %s", entityType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) Delete(ctx echo.Context, entityType EntityType, id int) error {
|
||||||
|
switch entityType.(type) {
|
||||||
|
case *PasswordToken:
|
||||||
|
return h.PasswordTokenDelete(ctx, id)
|
||||||
|
case *User:
|
||||||
|
return h.UserDelete(ctx, id)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported entity type: %s", entityType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) Update(ctx echo.Context, entityType EntityType, id int) error {
|
||||||
|
switch entityType.(type) {
|
||||||
|
case *PasswordToken:
|
||||||
|
return h.PasswordTokenUpdate(ctx, id)
|
||||||
|
case *User:
|
||||||
|
return h.UserUpdate(ctx, id)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported entity type: %s", entityType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) List(ctx echo.Context, entityType EntityType) (*EntityList, error) {
|
||||||
|
switch entityType.(type) {
|
||||||
|
case *PasswordToken:
|
||||||
|
return h.PasswordTokenList(ctx)
|
||||||
|
case *User:
|
||||||
|
return h.UserList(ctx)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported entity type: %s", entityType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) PasswordTokenCreate(ctx echo.Context) error {
|
||||||
|
var payload PasswordToken
|
||||||
|
if err := h.bind(ctx, &payload); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
op := h.client.PasswordToken.Create()
|
||||||
|
if payload.Token != nil {
|
||||||
|
op.SetToken(*payload.Token)
|
||||||
|
}
|
||||||
|
op.SetUserID(payload.UserID)
|
||||||
|
if payload.CreatedAt != nil {
|
||||||
|
op.SetCreatedAt(*payload.CreatedAt)
|
||||||
|
}
|
||||||
|
_, err := op.Save(ctx.Request().Context())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) PasswordTokenUpdate(ctx echo.Context, id int) error {
|
||||||
|
entity, err := h.client.PasswordToken.Get(ctx.Request().Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload PasswordToken
|
||||||
|
if err = h.bind(ctx, &payload); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
op := entity.Update()
|
||||||
|
if payload.Token != nil {
|
||||||
|
op.SetToken(*payload.Token)
|
||||||
|
}
|
||||||
|
op.SetUserID(payload.UserID)
|
||||||
|
if payload.CreatedAt == nil {
|
||||||
|
var empty time.Time
|
||||||
|
op.SetCreatedAt(empty)
|
||||||
|
} else {
|
||||||
|
op.SetCreatedAt(*payload.CreatedAt)
|
||||||
|
}
|
||||||
|
_, err = op.Save(ctx.Request().Context())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) PasswordTokenDelete(ctx echo.Context, id int) error {
|
||||||
|
return h.client.PasswordToken.DeleteOneID(id).
|
||||||
|
Exec(ctx.Request().Context())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) PasswordTokenList(ctx echo.Context) (*EntityList, error) {
|
||||||
|
page, offset := h.getPageAndOffset(ctx)
|
||||||
|
res, err := h.client.PasswordToken.
|
||||||
|
Query().
|
||||||
|
Limit(h.Config.ItemsPerPage + 1).
|
||||||
|
Offset(offset).
|
||||||
|
Order(passwordtoken.ByID(sql.OrderDesc())).
|
||||||
|
All(ctx.Request().Context())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
list := &EntityList{
|
||||||
|
Columns: []string{
|
||||||
|
"User ID",
|
||||||
|
"Created at",
|
||||||
|
},
|
||||||
|
Entities: make([]EntityValues, 0, len(res)),
|
||||||
|
Page: page,
|
||||||
|
HasNextPage: len(res) > h.Config.ItemsPerPage,
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i <= len(res)-1; i++ {
|
||||||
|
list.Entities = append(list.Entities, EntityValues{
|
||||||
|
ID: res[i].ID,
|
||||||
|
Values: []string{
|
||||||
|
fmt.Sprint(res[i].UserID),
|
||||||
|
res[i].CreatedAt.Format(h.Config.TimeFormat),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) PasswordTokenGet(ctx echo.Context, id int) (url.Values, error) {
|
||||||
|
entity, err := h.client.PasswordToken.Get(ctx.Request().Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v := url.Values{}
|
||||||
|
v.Set("user_id", fmt.Sprint(entity.UserID))
|
||||||
|
v.Set("created_at", entity.CreatedAt.Format(dateTimeFormat))
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) UserCreate(ctx echo.Context) error {
|
||||||
|
var payload User
|
||||||
|
if err := h.bind(ctx, &payload); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
op := h.client.User.Create()
|
||||||
|
op.SetName(payload.Name)
|
||||||
|
op.SetEmail(payload.Email)
|
||||||
|
if payload.Password != nil {
|
||||||
|
op.SetPassword(*payload.Password)
|
||||||
|
}
|
||||||
|
op.SetVerified(payload.Verified)
|
||||||
|
op.SetAdmin(payload.Admin)
|
||||||
|
if payload.CreatedAt != nil {
|
||||||
|
op.SetCreatedAt(*payload.CreatedAt)
|
||||||
|
}
|
||||||
|
_, err := op.Save(ctx.Request().Context())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) UserUpdate(ctx echo.Context, id int) error {
|
||||||
|
entity, err := h.client.User.Get(ctx.Request().Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload User
|
||||||
|
if err = h.bind(ctx, &payload); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
op := entity.Update()
|
||||||
|
op.SetName(payload.Name)
|
||||||
|
op.SetEmail(payload.Email)
|
||||||
|
if payload.Password != nil {
|
||||||
|
op.SetPassword(*payload.Password)
|
||||||
|
}
|
||||||
|
op.SetVerified(payload.Verified)
|
||||||
|
op.SetAdmin(payload.Admin)
|
||||||
|
_, err = op.Save(ctx.Request().Context())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) UserDelete(ctx echo.Context, id int) error {
|
||||||
|
return h.client.User.DeleteOneID(id).
|
||||||
|
Exec(ctx.Request().Context())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) UserList(ctx echo.Context) (*EntityList, error) {
|
||||||
|
page, offset := h.getPageAndOffset(ctx)
|
||||||
|
res, err := h.client.User.
|
||||||
|
Query().
|
||||||
|
Limit(h.Config.ItemsPerPage + 1).
|
||||||
|
Offset(offset).
|
||||||
|
Order(user.ByID(sql.OrderDesc())).
|
||||||
|
All(ctx.Request().Context())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
list := &EntityList{
|
||||||
|
Columns: []string{
|
||||||
|
"Name",
|
||||||
|
"Email",
|
||||||
|
"Verified",
|
||||||
|
"Admin",
|
||||||
|
"Created at",
|
||||||
|
},
|
||||||
|
Entities: make([]EntityValues, 0, len(res)),
|
||||||
|
Page: page,
|
||||||
|
HasNextPage: len(res) > h.Config.ItemsPerPage,
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i <= len(res)-1; i++ {
|
||||||
|
list.Entities = append(list.Entities, EntityValues{
|
||||||
|
ID: res[i].ID,
|
||||||
|
Values: []string{
|
||||||
|
res[i].Name,
|
||||||
|
res[i].Email,
|
||||||
|
fmt.Sprint(res[i].Verified),
|
||||||
|
fmt.Sprint(res[i].Admin),
|
||||||
|
res[i].CreatedAt.Format(h.Config.TimeFormat),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) UserGet(ctx echo.Context, id int) (url.Values, error) {
|
||||||
|
entity, err := h.client.User.Get(ctx.Request().Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v := url.Values{}
|
||||||
|
v.Set("name", entity.Name)
|
||||||
|
v.Set("email", entity.Email)
|
||||||
|
v.Set("verified", fmt.Sprint(entity.Verified))
|
||||||
|
v.Set("admin", fmt.Sprint(entity.Admin))
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) getPageAndOffset(ctx echo.Context) (int, int) {
|
||||||
|
if page, err := strconv.Atoi(ctx.QueryParam(h.Config.PageQueryKey)); err == nil {
|
||||||
|
if page > 1 {
|
||||||
|
return page, (page - 1) * h.Config.ItemsPerPage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) bind(ctx echo.Context, entity any) error {
|
||||||
|
// Echo requires some pre-processing of form values to avoid problems.
|
||||||
|
for k, v := range ctx.Request().Form {
|
||||||
|
// Remove empty field values so Echo's bind does not fail when trying to parse things like
|
||||||
|
// times, etc.
|
||||||
|
if len(v) == 1 && len(v[0]) == 0 {
|
||||||
|
delete(ctx.Request().Form, k)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Echo expects datetime values to be in a certain format but that does not align with the datetime-local
|
||||||
|
// HTML form element format, so we will attempt to convert it here.
|
||||||
|
for _, format := range []string{dateTimeFormatNoSeconds, dateTimeFormat} {
|
||||||
|
if t, err := time.Parse(format, v[0]); err == nil {
|
||||||
|
ctx.Request().Form[k][0] = t.Format(time.RFC3339)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctx.Bind(entity)
|
||||||
|
}
|
||||||
101
ent/admin/schema.go
Normal file
101
ent/admin/schema.go
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"entgo.io/ent/schema/field"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Enum struct {
|
||||||
|
Label, Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type FieldSchema struct {
|
||||||
|
Name string
|
||||||
|
Type field.Type
|
||||||
|
Optional bool
|
||||||
|
Immutable bool
|
||||||
|
Sensitive bool
|
||||||
|
Enums []string
|
||||||
|
}
|
||||||
|
|
||||||
|
const NamePasswordToken = "PasswordToken"
|
||||||
|
|
||||||
|
var fieldsPasswordToken = []*FieldSchema{
|
||||||
|
{
|
||||||
|
Name: "token",
|
||||||
|
Type: field.TypeString,
|
||||||
|
Optional: false,
|
||||||
|
Immutable: false,
|
||||||
|
Sensitive: true,
|
||||||
|
Enums: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "user_id",
|
||||||
|
Type: field.TypeInt,
|
||||||
|
Optional: false,
|
||||||
|
Immutable: false,
|
||||||
|
Sensitive: false,
|
||||||
|
Enums: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "created_at",
|
||||||
|
Type: field.TypeTime,
|
||||||
|
Optional: false,
|
||||||
|
Immutable: false,
|
||||||
|
Sensitive: false,
|
||||||
|
Enums: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const NameUser = "User"
|
||||||
|
|
||||||
|
var fieldsUser = []*FieldSchema{
|
||||||
|
{
|
||||||
|
Name: "name",
|
||||||
|
Type: field.TypeString,
|
||||||
|
Optional: false,
|
||||||
|
Immutable: false,
|
||||||
|
Sensitive: false,
|
||||||
|
Enums: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "email",
|
||||||
|
Type: field.TypeString,
|
||||||
|
Optional: false,
|
||||||
|
Immutable: false,
|
||||||
|
Sensitive: false,
|
||||||
|
Enums: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "password",
|
||||||
|
Type: field.TypeString,
|
||||||
|
Optional: false,
|
||||||
|
Immutable: false,
|
||||||
|
Sensitive: true,
|
||||||
|
Enums: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "verified",
|
||||||
|
Type: field.TypeBool,
|
||||||
|
Optional: false,
|
||||||
|
Immutable: false,
|
||||||
|
Sensitive: false,
|
||||||
|
Enums: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "admin",
|
||||||
|
Type: field.TypeBool,
|
||||||
|
Optional: false,
|
||||||
|
Immutable: false,
|
||||||
|
Sensitive: false,
|
||||||
|
Enums: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "created_at",
|
||||||
|
Type: field.TypeTime,
|
||||||
|
Optional: false,
|
||||||
|
Immutable: true,
|
||||||
|
Sensitive: false,
|
||||||
|
Enums: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
262
ent/admin/templates/handler.tmpl
Normal file
262
ent/admin/templates/handler.tmpl
Normal file
|
|
@ -0,0 +1,262 @@
|
||||||
|
{{/* Tell Intellij/GoLand to enable the autocompletion based on the *gen.Graph type. */}}
|
||||||
|
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
|
||||||
|
|
||||||
|
{{ define "admin/handler" }}
|
||||||
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
{{- $pkg := base $.Config.Package }}
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
|
||||||
|
"{{ $.Config.Package }}"
|
||||||
|
{{- range $n := $.Nodes }}
|
||||||
|
"{{ $.Config.Package }}/{{ $n.Package }}"
|
||||||
|
{{- end }}
|
||||||
|
)
|
||||||
|
|
||||||
|
const dateTimeFormat = "2006-01-02T15:04:05"
|
||||||
|
const dateTimeFormatNoSeconds = "2006-01-02T15:04"
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
client *{{ $pkg }}.Client
|
||||||
|
Config HandlerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(client *{{ $pkg }}.Client, cfg HandlerConfig) *Handler {
|
||||||
|
return &Handler{
|
||||||
|
client: client,
|
||||||
|
Config: cfg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) Create(ctx echo.Context, entityType EntityType) error {
|
||||||
|
switch entityType.(type) {
|
||||||
|
{{- range $n := $.Nodes }}
|
||||||
|
case *{{ $n.Name }}:
|
||||||
|
return h.{{ $n.Name }}Create(ctx)
|
||||||
|
{{- end }}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported entity type: %s", entityType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) Get(ctx echo.Context, entityType EntityType, id int) (url.Values, error) {
|
||||||
|
switch entityType.(type) {
|
||||||
|
{{- range $n := $.Nodes }}
|
||||||
|
case *{{ $n.Name }}:
|
||||||
|
return h.{{ $n.Name }}Get(ctx, id)
|
||||||
|
{{- end }}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported entity type: %s", entityType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) Delete(ctx echo.Context, entityType EntityType, id int) error {
|
||||||
|
switch entityType.(type) {
|
||||||
|
{{- range $n := $.Nodes }}
|
||||||
|
case *{{ $n.Name }}:
|
||||||
|
return h.{{ $n.Name }}Delete(ctx, id)
|
||||||
|
{{- end }}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported entity type: %s", entityType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) Update(ctx echo.Context, entityType EntityType, id int) error {
|
||||||
|
switch entityType.(type) {
|
||||||
|
{{- range $n := $.Nodes }}
|
||||||
|
case *{{ $n.Name }}:
|
||||||
|
return h.{{ $n.Name }}Update(ctx, id)
|
||||||
|
{{- end }}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported entity type: %s", entityType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) List(ctx echo.Context, entityType EntityType) (*EntityList, error) {
|
||||||
|
switch entityType.(type) {
|
||||||
|
{{- range $n := $.Nodes }}
|
||||||
|
case *{{ $n.Name }}:
|
||||||
|
return h.{{ $n.Name }}List(ctx)
|
||||||
|
{{- end }}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported entity type: %s", entityType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{ range $n := $.Nodes }}
|
||||||
|
func (h *Handler) {{ $n.Name }}Create(ctx echo.Context) error {
|
||||||
|
var payload {{ $n.Name }}
|
||||||
|
if err := h.bind(ctx, &payload); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
op := h.client.{{ $n.Name }}.Create()
|
||||||
|
{{- range $f := $n.Fields }}
|
||||||
|
{{- if (fieldIsPointer $f) }}
|
||||||
|
if payload.{{ fieldName $f.Name }} != nil {
|
||||||
|
op.Set{{ fieldName $f.Name }}(*payload.{{ fieldName $f.Name }})
|
||||||
|
}
|
||||||
|
{{- else }}
|
||||||
|
op.Set{{ fieldName $f.Name }}(payload.{{ fieldName $f.Name }})
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
_, err := op.Save(ctx.Request().Context())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) {{ $n.Name }}Update(ctx echo.Context, id int) error {
|
||||||
|
entity, err := h.client.{{ $n.Name }}.Get(ctx.Request().Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload {{ $n.Name }}
|
||||||
|
if err = h.bind(ctx, &payload); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
op := entity.Update()
|
||||||
|
{{- range $f := $n.Fields }}
|
||||||
|
{{- if not $f.Immutable }}
|
||||||
|
{{- if $f.Sensitive }}
|
||||||
|
if payload.{{ fieldName $f.Name }} != nil {
|
||||||
|
op.Set{{ fieldName $f.Name }}(*payload.{{ fieldName $f.Name }})
|
||||||
|
}
|
||||||
|
{{- else if $f.Nillable }}
|
||||||
|
op.SetNillable{{ fieldName $f.Name }}(payload.{{ fieldName $f.Name }})
|
||||||
|
{{- else if $f.Optional }}
|
||||||
|
if payload.{{ fieldName $f.Name }} == nil {
|
||||||
|
op.Clear{{ fieldName $f.Name }}()
|
||||||
|
} else {
|
||||||
|
op.Set{{ fieldName $f.Name }}(*payload.{{ fieldName $f.Name }})
|
||||||
|
}
|
||||||
|
{{- else if (fieldIsPointer $f) }}
|
||||||
|
if payload.{{ fieldName $f.Name }} == nil {
|
||||||
|
var empty {{ $f.Type }}
|
||||||
|
op.Set{{ fieldName $f.Name }}(empty)
|
||||||
|
} else {
|
||||||
|
op.Set{{ fieldName $f.Name }}(*payload.{{ fieldName $f.Name }})
|
||||||
|
}
|
||||||
|
{{- else }}
|
||||||
|
op.Set{{ fieldName $f.Name }}(payload.{{ fieldName $f.Name }})
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
_, err = op.Save(ctx.Request().Context())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) {{ $n.Name }}Delete(ctx echo.Context, id int) error {
|
||||||
|
return h.client.{{ $n.Name }}.DeleteOneID(id).
|
||||||
|
Exec(ctx.Request().Context())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) {{ $n.Name }}List(ctx echo.Context) (*EntityList, error) {
|
||||||
|
page, offset := h.getPageAndOffset(ctx)
|
||||||
|
res, err := h.client.{{ $n.Name }}.
|
||||||
|
Query().
|
||||||
|
Limit(h.Config.ItemsPerPage+1).
|
||||||
|
Offset(offset).
|
||||||
|
Order({{ $n.Package }}.ByID(sql.OrderDesc())).
|
||||||
|
All(ctx.Request().Context())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
list := &EntityList{
|
||||||
|
Columns: []string{
|
||||||
|
{{- range $f := $n.Fields }}
|
||||||
|
{{- if not $f.Sensitive }}
|
||||||
|
"{{ fieldLabel $f.Name }}",
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
},
|
||||||
|
Entities: make([]EntityValues, 0, len(res)),
|
||||||
|
Page: page,
|
||||||
|
HasNextPage: len(res) > h.Config.ItemsPerPage,
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i <= len(res)-1; i++ {
|
||||||
|
list.Entities = append(list.Entities, EntityValues{
|
||||||
|
ID: res[i].ID,
|
||||||
|
Values: []string{
|
||||||
|
{{- range $f := $n.Fields }}
|
||||||
|
{{- if not $f.Sensitive }}
|
||||||
|
{{- if eq $f.Type.String "string" }}
|
||||||
|
res[i].{{ fieldName $f.Name }},
|
||||||
|
{{- else if eq $f.Type.String "time.Time" }}
|
||||||
|
res[i].{{ fieldName $f.Name }}.Format(h.Config.TimeFormat),
|
||||||
|
{{- else }}
|
||||||
|
fmt.Sprint(res[i].{{ fieldName $f.Name }}),
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) {{ $n.Name }}Get(ctx echo.Context, id int) (url.Values, error) {
|
||||||
|
entity, err := h.client.{{ $n.Name }}.Get(ctx.Request().Context(), id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v := url.Values{}
|
||||||
|
{{- range $f := $n.Fields }}
|
||||||
|
{{- if and (not $f.Sensitive) (not $f.Immutable) }}
|
||||||
|
{{- if eq $f.Type.String "string" }}
|
||||||
|
v.Set("{{ $f.Name }}", entity.{{ fieldName $f.Name }})
|
||||||
|
{{- else if eq $f.Type.String "time.Time" }}
|
||||||
|
v.Set("{{ $f.Name }}", entity.{{ fieldName $f.Name }}.Format(dateTimeFormat))
|
||||||
|
{{- else }}
|
||||||
|
v.Set("{{ $f.Name }}", fmt.Sprint(entity.{{ fieldName $f.Name }}))
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
func (h *Handler) getPageAndOffset(ctx echo.Context) (int, int) {
|
||||||
|
if page, err := strconv.Atoi(ctx.QueryParam(h.Config.PageQueryKey)); err == nil {
|
||||||
|
if page > 1 {
|
||||||
|
return page, (page-1) * h.Config.ItemsPerPage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) bind(ctx echo.Context, entity any) error {
|
||||||
|
// Echo requires some pre-processing of form values to avoid problems.
|
||||||
|
for k, v := range ctx.Request().Form {
|
||||||
|
// Remove empty field values so Echo's bind does not fail when trying to parse things like
|
||||||
|
// times, etc.
|
||||||
|
if len(v) == 1 && len(v[0]) == 0 {
|
||||||
|
delete(ctx.Request().Form, k)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Echo expects datetime values to be in a certain format but that does not align with the datetime-local
|
||||||
|
// HTML form element format, so we will attempt to convert it here.
|
||||||
|
for _, format := range []string{dateTimeFormatNoSeconds, dateTimeFormat} {
|
||||||
|
if t, err := time.Parse(format, v[0]); err == nil {
|
||||||
|
ctx.Request().Form[k][0] = t.Format(time.RFC3339)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctx.Bind(entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
{{ end }}
|
||||||
51
ent/admin/templates/schema.tmpl
Normal file
51
ent/admin/templates/schema.tmpl
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
{{/* Tell Intellij/GoLand to enable the autocompletion based on the *gen.Graph type. */}}
|
||||||
|
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
|
||||||
|
|
||||||
|
{{ define "admin/schema" }}
|
||||||
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"entgo.io/ent/schema/field"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Enum struct {
|
||||||
|
Label, Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type FieldSchema struct {
|
||||||
|
Name string
|
||||||
|
Type field.Type
|
||||||
|
Optional bool
|
||||||
|
Immutable bool
|
||||||
|
Sensitive bool
|
||||||
|
Enums []string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{{- range $n := $.Nodes }}
|
||||||
|
const Name{{ $n.Name }} = "{{ $n.Name }}"
|
||||||
|
|
||||||
|
var fields{{ $n.Name }} = []*FieldSchema{
|
||||||
|
{{- range $f := $n.Fields }}
|
||||||
|
{
|
||||||
|
Name: "{{ $f.Name }}",
|
||||||
|
Type: field.{{ $f.Type.Type.ConstName }},
|
||||||
|
Optional: {{ $f.Optional }},
|
||||||
|
Immutable: {{ $f.Immutable }},
|
||||||
|
Sensitive: {{ $f.Sensitive }},
|
||||||
|
{{- if len $f.Enums }}
|
||||||
|
Enums: []string{
|
||||||
|
{{- range $e := $f.Enums }}
|
||||||
|
"{{ $e.Value }}",
|
||||||
|
{{- end }}
|
||||||
|
},
|
||||||
|
{{- else }}
|
||||||
|
Enums: nil,
|
||||||
|
{{- end }}
|
||||||
|
},
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ end }}
|
||||||
56
ent/admin/templates/types.tmpl
Normal file
56
ent/admin/templates/types.tmpl
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
{{/* Tell Intellij/GoLand to enable the autocompletion based on the *gen.Graph type. */}}
|
||||||
|
{{/* gotype: entgo.io/ent/entc/gen.Graph */}}
|
||||||
|
|
||||||
|
{{ define "admin/types" }}
|
||||||
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
package admin
|
||||||
|
|
||||||
|
{{- range $n := $.Nodes }}
|
||||||
|
type {{ $n.Name }} struct {
|
||||||
|
{{- range $f := $n.Fields }}
|
||||||
|
{{ fieldName $f.Name }} {{ if (fieldIsPointer $f) }}*{{ end }}{{ $f.Type }} `form:"{{ $f.Name }}"`
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *{{ $n.Name }}) GetName() string {
|
||||||
|
return Name{{ $n.Name }}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *{{ $n.Name }}) GetSchema() []*FieldSchema {
|
||||||
|
return fields{{ $n.Name }}
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
type EntityType interface {
|
||||||
|
GetName() string
|
||||||
|
GetSchema() []*FieldSchema
|
||||||
|
}
|
||||||
|
|
||||||
|
var entityTypes = []EntityType{
|
||||||
|
{{- range $n := $.Nodes }}
|
||||||
|
&{{ $n.Name }}{},
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntityList struct {
|
||||||
|
Columns []string
|
||||||
|
Entities []EntityValues
|
||||||
|
Page int
|
||||||
|
HasNextPage bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntityValues struct {
|
||||||
|
ID int
|
||||||
|
Values []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type HandlerConfig struct {
|
||||||
|
ItemsPerPage int
|
||||||
|
PageQueryKey string
|
||||||
|
TimeFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetEntityTypes() []EntityType {
|
||||||
|
return entityTypes
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
67
ent/admin/types.go
Normal file
67
ent/admin/types.go
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type PasswordToken struct {
|
||||||
|
Token *string `form:"token"`
|
||||||
|
UserID int `form:"user_id"`
|
||||||
|
CreatedAt *time.Time `form:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *PasswordToken) GetName() string {
|
||||||
|
return NamePasswordToken
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *PasswordToken) GetSchema() []*FieldSchema {
|
||||||
|
return fieldsPasswordToken
|
||||||
|
}
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Name string `form:"name"`
|
||||||
|
Email string `form:"email"`
|
||||||
|
Password *string `form:"password"`
|
||||||
|
Verified bool `form:"verified"`
|
||||||
|
Admin bool `form:"admin"`
|
||||||
|
CreatedAt *time.Time `form:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *User) GetName() string {
|
||||||
|
return NameUser
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *User) GetSchema() []*FieldSchema {
|
||||||
|
return fieldsUser
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntityType interface {
|
||||||
|
GetName() string
|
||||||
|
GetSchema() []*FieldSchema
|
||||||
|
}
|
||||||
|
|
||||||
|
var entityTypes = []EntityType{
|
||||||
|
&PasswordToken{},
|
||||||
|
&User{},
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntityList struct {
|
||||||
|
Columns []string
|
||||||
|
Entities []EntityValues
|
||||||
|
Page int
|
||||||
|
HasNextPage bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type EntityValues struct {
|
||||||
|
ID int
|
||||||
|
Values []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type HandlerConfig struct {
|
||||||
|
ItemsPerPage int
|
||||||
|
PageQueryKey string
|
||||||
|
TimeFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetEntityTypes() []EntityType {
|
||||||
|
return entityTypes
|
||||||
|
}
|
||||||
247
ent/client.go
247
ent/client.go
|
|
@ -1,20 +1,22 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"goweb/ent/migrate"
|
"github.com/mikestefanello/pagoda/ent/migrate"
|
||||||
|
|
||||||
"goweb/ent/passwordtoken"
|
|
||||||
"goweb/ent/user"
|
|
||||||
|
|
||||||
|
"entgo.io/ent"
|
||||||
"entgo.io/ent/dialect"
|
"entgo.io/ent/dialect"
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/passwordtoken"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client is the client that holds all ent builders.
|
// Client is the client that holds all ent builders.
|
||||||
|
|
@ -30,9 +32,7 @@ type Client struct {
|
||||||
|
|
||||||
// NewClient creates a new client configured with the given options.
|
// NewClient creates a new client configured with the given options.
|
||||||
func NewClient(opts ...Option) *Client {
|
func NewClient(opts ...Option) *Client {
|
||||||
cfg := config{log: log.Println, hooks: &hooks{}}
|
client := &Client{config: newConfig(opts...)}
|
||||||
cfg.options(opts...)
|
|
||||||
client := &Client{config: cfg}
|
|
||||||
client.init()
|
client.init()
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
|
|
@ -43,6 +43,62 @@ func (c *Client) init() {
|
||||||
c.User = NewUserClient(c.config)
|
c.User = NewUserClient(c.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
// config is the configuration for the client and its builder.
|
||||||
|
config struct {
|
||||||
|
// driver used for executing database requests.
|
||||||
|
driver dialect.Driver
|
||||||
|
// debug enable a debug logging.
|
||||||
|
debug bool
|
||||||
|
// log used for logging on debug mode.
|
||||||
|
log func(...any)
|
||||||
|
// hooks to execute on mutations.
|
||||||
|
hooks *hooks
|
||||||
|
// interceptors to execute on queries.
|
||||||
|
inters *inters
|
||||||
|
}
|
||||||
|
// Option function to configure the client.
|
||||||
|
Option func(*config)
|
||||||
|
)
|
||||||
|
|
||||||
|
// newConfig creates a new config for the client.
|
||||||
|
func newConfig(opts ...Option) config {
|
||||||
|
cfg := config{log: log.Println, hooks: &hooks{}, inters: &inters{}}
|
||||||
|
cfg.options(opts...)
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
// options applies the options on the config object.
|
||||||
|
func (c *config) options(opts ...Option) {
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(c)
|
||||||
|
}
|
||||||
|
if c.debug {
|
||||||
|
c.driver = dialect.Debug(c.driver, c.log)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug enables debug logging on the ent.Driver.
|
||||||
|
func Debug() Option {
|
||||||
|
return func(c *config) {
|
||||||
|
c.debug = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log sets the logging function for debug mode.
|
||||||
|
func Log(fn func(...any)) Option {
|
||||||
|
return func(c *config) {
|
||||||
|
c.log = fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Driver configures the client driver.
|
||||||
|
func Driver(driver dialect.Driver) Option {
|
||||||
|
return func(c *config) {
|
||||||
|
c.driver = driver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Open opens a database/sql.DB specified by the driver name and
|
// Open opens a database/sql.DB specified by the driver name and
|
||||||
// the data source name, and returns a new client attached to it.
|
// the data source name, and returns a new client attached to it.
|
||||||
// Optional parameters can be added for configuring the client.
|
// Optional parameters can be added for configuring the client.
|
||||||
|
|
@ -59,11 +115,14 @@ func Open(driverName, dataSourceName string, options ...Option) (*Client, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrTxStarted is returned when trying to start a new transaction from a transactional client.
|
||||||
|
var ErrTxStarted = errors.New("ent: cannot start a transaction within a transaction")
|
||||||
|
|
||||||
// Tx returns a new transactional client. The provided context
|
// Tx returns a new transactional client. The provided context
|
||||||
// is used until the transaction is committed or rolled back.
|
// is used until the transaction is committed or rolled back.
|
||||||
func (c *Client) Tx(ctx context.Context) (*Tx, error) {
|
func (c *Client) Tx(ctx context.Context) (*Tx, error) {
|
||||||
if _, ok := c.driver.(*txDriver); ok {
|
if _, ok := c.driver.(*txDriver); ok {
|
||||||
return nil, fmt.Errorf("ent: cannot start a transaction within a transaction")
|
return nil, ErrTxStarted
|
||||||
}
|
}
|
||||||
tx, err := newTx(ctx, c.driver)
|
tx, err := newTx(ctx, c.driver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -82,7 +141,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) {
|
||||||
// BeginTx returns a transactional client with specified options.
|
// BeginTx returns a transactional client with specified options.
|
||||||
func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
|
func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
|
||||||
if _, ok := c.driver.(*txDriver); ok {
|
if _, ok := c.driver.(*txDriver); ok {
|
||||||
return nil, fmt.Errorf("ent: cannot start a transaction within a transaction")
|
return nil, errors.New("ent: cannot start a transaction within a transaction")
|
||||||
}
|
}
|
||||||
tx, err := c.driver.(interface {
|
tx, err := c.driver.(interface {
|
||||||
BeginTx(context.Context, *sql.TxOptions) (dialect.Tx, error)
|
BeginTx(context.Context, *sql.TxOptions) (dialect.Tx, error)
|
||||||
|
|
@ -93,6 +152,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
|
||||||
cfg := c.config
|
cfg := c.config
|
||||||
cfg.driver = &txDriver{tx: tx, drv: c.driver}
|
cfg.driver = &txDriver{tx: tx, drv: c.driver}
|
||||||
return &Tx{
|
return &Tx{
|
||||||
|
ctx: ctx,
|
||||||
config: cfg,
|
config: cfg,
|
||||||
PasswordToken: NewPasswordTokenClient(cfg),
|
PasswordToken: NewPasswordTokenClient(cfg),
|
||||||
User: NewUserClient(cfg),
|
User: NewUserClient(cfg),
|
||||||
|
|
@ -105,7 +165,6 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
|
||||||
// PasswordToken.
|
// PasswordToken.
|
||||||
// Query().
|
// Query().
|
||||||
// Count(ctx)
|
// Count(ctx)
|
||||||
//
|
|
||||||
func (c *Client) Debug() *Client {
|
func (c *Client) Debug() *Client {
|
||||||
if c.debug {
|
if c.debug {
|
||||||
return c
|
return c
|
||||||
|
|
@ -129,6 +188,25 @@ func (c *Client) Use(hooks ...Hook) {
|
||||||
c.User.Use(hooks...)
|
c.User.Use(hooks...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Intercept adds the query interceptors to all the entity clients.
|
||||||
|
// In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`.
|
||||||
|
func (c *Client) Intercept(interceptors ...Interceptor) {
|
||||||
|
c.PasswordToken.Intercept(interceptors...)
|
||||||
|
c.User.Intercept(interceptors...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mutate implements the ent.Mutator interface.
|
||||||
|
func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
|
||||||
|
switch m := m.(type) {
|
||||||
|
case *PasswordTokenMutation:
|
||||||
|
return c.PasswordToken.mutate(ctx, m)
|
||||||
|
case *UserMutation:
|
||||||
|
return c.User.mutate(ctx, m)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("ent: unknown mutation type %T", m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// PasswordTokenClient is a client for the PasswordToken schema.
|
// PasswordTokenClient is a client for the PasswordToken schema.
|
||||||
type PasswordTokenClient struct {
|
type PasswordTokenClient struct {
|
||||||
config
|
config
|
||||||
|
|
@ -145,7 +223,13 @@ func (c *PasswordTokenClient) Use(hooks ...Hook) {
|
||||||
c.hooks.PasswordToken = append(c.hooks.PasswordToken, hooks...)
|
c.hooks.PasswordToken = append(c.hooks.PasswordToken, hooks...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create returns a create builder for PasswordToken.
|
// Intercept adds a list of query interceptors to the interceptors stack.
|
||||||
|
// A call to `Intercept(f, g, h)` equals to `passwordtoken.Intercept(f(g(h())))`.
|
||||||
|
func (c *PasswordTokenClient) Intercept(interceptors ...Interceptor) {
|
||||||
|
c.inters.PasswordToken = append(c.inters.PasswordToken, interceptors...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create returns a builder for creating a PasswordToken entity.
|
||||||
func (c *PasswordTokenClient) Create() *PasswordTokenCreate {
|
func (c *PasswordTokenClient) Create() *PasswordTokenCreate {
|
||||||
mutation := newPasswordTokenMutation(c.config, OpCreate)
|
mutation := newPasswordTokenMutation(c.config, OpCreate)
|
||||||
return &PasswordTokenCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
return &PasswordTokenCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||||
|
|
@ -156,6 +240,21 @@ func (c *PasswordTokenClient) CreateBulk(builders ...*PasswordTokenCreate) *Pass
|
||||||
return &PasswordTokenCreateBulk{config: c.config, builders: builders}
|
return &PasswordTokenCreateBulk{config: c.config, builders: builders}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
|
||||||
|
// a builder and applies setFunc on it.
|
||||||
|
func (c *PasswordTokenClient) MapCreateBulk(slice any, setFunc func(*PasswordTokenCreate, int)) *PasswordTokenCreateBulk {
|
||||||
|
rv := reflect.ValueOf(slice)
|
||||||
|
if rv.Kind() != reflect.Slice {
|
||||||
|
return &PasswordTokenCreateBulk{err: fmt.Errorf("calling to PasswordTokenClient.MapCreateBulk with wrong type %T, need slice", slice)}
|
||||||
|
}
|
||||||
|
builders := make([]*PasswordTokenCreate, rv.Len())
|
||||||
|
for i := 0; i < rv.Len(); i++ {
|
||||||
|
builders[i] = c.Create()
|
||||||
|
setFunc(builders[i], i)
|
||||||
|
}
|
||||||
|
return &PasswordTokenCreateBulk{config: c.config, builders: builders}
|
||||||
|
}
|
||||||
|
|
||||||
// Update returns an update builder for PasswordToken.
|
// Update returns an update builder for PasswordToken.
|
||||||
func (c *PasswordTokenClient) Update() *PasswordTokenUpdate {
|
func (c *PasswordTokenClient) Update() *PasswordTokenUpdate {
|
||||||
mutation := newPasswordTokenMutation(c.config, OpUpdate)
|
mutation := newPasswordTokenMutation(c.config, OpUpdate)
|
||||||
|
|
@ -163,8 +262,8 @@ func (c *PasswordTokenClient) Update() *PasswordTokenUpdate {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateOne returns an update builder for the given entity.
|
// UpdateOne returns an update builder for the given entity.
|
||||||
func (c *PasswordTokenClient) UpdateOne(pt *PasswordToken) *PasswordTokenUpdateOne {
|
func (c *PasswordTokenClient) UpdateOne(_m *PasswordToken) *PasswordTokenUpdateOne {
|
||||||
mutation := newPasswordTokenMutation(c.config, OpUpdateOne, withPasswordToken(pt))
|
mutation := newPasswordTokenMutation(c.config, OpUpdateOne, withPasswordToken(_m))
|
||||||
return &PasswordTokenUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
return &PasswordTokenUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -180,12 +279,12 @@ func (c *PasswordTokenClient) Delete() *PasswordTokenDelete {
|
||||||
return &PasswordTokenDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
return &PasswordTokenDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteOne returns a delete builder for the given entity.
|
// DeleteOne returns a builder for deleting the given entity.
|
||||||
func (c *PasswordTokenClient) DeleteOne(pt *PasswordToken) *PasswordTokenDeleteOne {
|
func (c *PasswordTokenClient) DeleteOne(_m *PasswordToken) *PasswordTokenDeleteOne {
|
||||||
return c.DeleteOneID(pt.ID)
|
return c.DeleteOneID(_m.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteOneID returns a delete builder for the given id.
|
// DeleteOneID returns a builder for deleting the given entity by its id.
|
||||||
func (c *PasswordTokenClient) DeleteOneID(id int) *PasswordTokenDeleteOne {
|
func (c *PasswordTokenClient) DeleteOneID(id int) *PasswordTokenDeleteOne {
|
||||||
builder := c.Delete().Where(passwordtoken.ID(id))
|
builder := c.Delete().Where(passwordtoken.ID(id))
|
||||||
builder.mutation.id = &id
|
builder.mutation.id = &id
|
||||||
|
|
@ -197,6 +296,8 @@ func (c *PasswordTokenClient) DeleteOneID(id int) *PasswordTokenDeleteOne {
|
||||||
func (c *PasswordTokenClient) Query() *PasswordTokenQuery {
|
func (c *PasswordTokenClient) Query() *PasswordTokenQuery {
|
||||||
return &PasswordTokenQuery{
|
return &PasswordTokenQuery{
|
||||||
config: c.config,
|
config: c.config,
|
||||||
|
ctx: &QueryContext{Type: TypePasswordToken},
|
||||||
|
inters: c.Interceptors(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,16 +316,16 @@ func (c *PasswordTokenClient) GetX(ctx context.Context, id int) *PasswordToken {
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryUser queries the user edge of a PasswordToken.
|
// QueryUser queries the user edge of a PasswordToken.
|
||||||
func (c *PasswordTokenClient) QueryUser(pt *PasswordToken) *UserQuery {
|
func (c *PasswordTokenClient) QueryUser(_m *PasswordToken) *UserQuery {
|
||||||
query := &UserQuery{config: c.config}
|
query := (&UserClient{config: c.config}).Query()
|
||||||
query.path = func(ctx context.Context) (fromV *sql.Selector, _ error) {
|
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||||
id := pt.ID
|
id := _m.ID
|
||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(passwordtoken.Table, passwordtoken.FieldID, id),
|
sqlgraph.From(passwordtoken.Table, passwordtoken.FieldID, id),
|
||||||
sqlgraph.To(user.Table, user.FieldID),
|
sqlgraph.To(user.Table, user.FieldID),
|
||||||
sqlgraph.Edge(sqlgraph.M2O, false, passwordtoken.UserTable, passwordtoken.UserColumn),
|
sqlgraph.Edge(sqlgraph.M2O, false, passwordtoken.UserTable, passwordtoken.UserColumn),
|
||||||
)
|
)
|
||||||
fromV = sqlgraph.Neighbors(pt.driver.Dialect(), step)
|
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||||
return fromV, nil
|
return fromV, nil
|
||||||
}
|
}
|
||||||
return query
|
return query
|
||||||
|
|
@ -232,7 +333,28 @@ func (c *PasswordTokenClient) QueryUser(pt *PasswordToken) *UserQuery {
|
||||||
|
|
||||||
// Hooks returns the client hooks.
|
// Hooks returns the client hooks.
|
||||||
func (c *PasswordTokenClient) Hooks() []Hook {
|
func (c *PasswordTokenClient) Hooks() []Hook {
|
||||||
return c.hooks.PasswordToken
|
hooks := c.hooks.PasswordToken
|
||||||
|
return append(hooks[:len(hooks):len(hooks)], passwordtoken.Hooks[:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interceptors returns the client interceptors.
|
||||||
|
func (c *PasswordTokenClient) Interceptors() []Interceptor {
|
||||||
|
return c.inters.PasswordToken
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PasswordTokenClient) mutate(ctx context.Context, m *PasswordTokenMutation) (Value, error) {
|
||||||
|
switch m.Op() {
|
||||||
|
case OpCreate:
|
||||||
|
return (&PasswordTokenCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||||
|
case OpUpdate:
|
||||||
|
return (&PasswordTokenUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||||
|
case OpUpdateOne:
|
||||||
|
return (&PasswordTokenUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||||
|
case OpDelete, OpDeleteOne:
|
||||||
|
return (&PasswordTokenDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("ent: unknown PasswordToken mutation op: %q", m.Op())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserClient is a client for the User schema.
|
// UserClient is a client for the User schema.
|
||||||
|
|
@ -251,7 +373,13 @@ func (c *UserClient) Use(hooks ...Hook) {
|
||||||
c.hooks.User = append(c.hooks.User, hooks...)
|
c.hooks.User = append(c.hooks.User, hooks...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create returns a create builder for User.
|
// Intercept adds a list of query interceptors to the interceptors stack.
|
||||||
|
// A call to `Intercept(f, g, h)` equals to `user.Intercept(f(g(h())))`.
|
||||||
|
func (c *UserClient) Intercept(interceptors ...Interceptor) {
|
||||||
|
c.inters.User = append(c.inters.User, interceptors...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create returns a builder for creating a User entity.
|
||||||
func (c *UserClient) Create() *UserCreate {
|
func (c *UserClient) Create() *UserCreate {
|
||||||
mutation := newUserMutation(c.config, OpCreate)
|
mutation := newUserMutation(c.config, OpCreate)
|
||||||
return &UserCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
return &UserCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||||
|
|
@ -262,6 +390,21 @@ func (c *UserClient) CreateBulk(builders ...*UserCreate) *UserCreateBulk {
|
||||||
return &UserCreateBulk{config: c.config, builders: builders}
|
return &UserCreateBulk{config: c.config, builders: builders}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
|
||||||
|
// a builder and applies setFunc on it.
|
||||||
|
func (c *UserClient) MapCreateBulk(slice any, setFunc func(*UserCreate, int)) *UserCreateBulk {
|
||||||
|
rv := reflect.ValueOf(slice)
|
||||||
|
if rv.Kind() != reflect.Slice {
|
||||||
|
return &UserCreateBulk{err: fmt.Errorf("calling to UserClient.MapCreateBulk with wrong type %T, need slice", slice)}
|
||||||
|
}
|
||||||
|
builders := make([]*UserCreate, rv.Len())
|
||||||
|
for i := 0; i < rv.Len(); i++ {
|
||||||
|
builders[i] = c.Create()
|
||||||
|
setFunc(builders[i], i)
|
||||||
|
}
|
||||||
|
return &UserCreateBulk{config: c.config, builders: builders}
|
||||||
|
}
|
||||||
|
|
||||||
// Update returns an update builder for User.
|
// Update returns an update builder for User.
|
||||||
func (c *UserClient) Update() *UserUpdate {
|
func (c *UserClient) Update() *UserUpdate {
|
||||||
mutation := newUserMutation(c.config, OpUpdate)
|
mutation := newUserMutation(c.config, OpUpdate)
|
||||||
|
|
@ -269,8 +412,8 @@ func (c *UserClient) Update() *UserUpdate {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateOne returns an update builder for the given entity.
|
// UpdateOne returns an update builder for the given entity.
|
||||||
func (c *UserClient) UpdateOne(u *User) *UserUpdateOne {
|
func (c *UserClient) UpdateOne(_m *User) *UserUpdateOne {
|
||||||
mutation := newUserMutation(c.config, OpUpdateOne, withUser(u))
|
mutation := newUserMutation(c.config, OpUpdateOne, withUser(_m))
|
||||||
return &UserUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
return &UserUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -286,12 +429,12 @@ func (c *UserClient) Delete() *UserDelete {
|
||||||
return &UserDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
return &UserDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteOne returns a delete builder for the given entity.
|
// DeleteOne returns a builder for deleting the given entity.
|
||||||
func (c *UserClient) DeleteOne(u *User) *UserDeleteOne {
|
func (c *UserClient) DeleteOne(_m *User) *UserDeleteOne {
|
||||||
return c.DeleteOneID(u.ID)
|
return c.DeleteOneID(_m.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteOneID returns a delete builder for the given id.
|
// DeleteOneID returns a builder for deleting the given entity by its id.
|
||||||
func (c *UserClient) DeleteOneID(id int) *UserDeleteOne {
|
func (c *UserClient) DeleteOneID(id int) *UserDeleteOne {
|
||||||
builder := c.Delete().Where(user.ID(id))
|
builder := c.Delete().Where(user.ID(id))
|
||||||
builder.mutation.id = &id
|
builder.mutation.id = &id
|
||||||
|
|
@ -303,6 +446,8 @@ func (c *UserClient) DeleteOneID(id int) *UserDeleteOne {
|
||||||
func (c *UserClient) Query() *UserQuery {
|
func (c *UserClient) Query() *UserQuery {
|
||||||
return &UserQuery{
|
return &UserQuery{
|
||||||
config: c.config,
|
config: c.config,
|
||||||
|
ctx: &QueryContext{Type: TypeUser},
|
||||||
|
inters: c.Interceptors(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -321,16 +466,16 @@ func (c *UserClient) GetX(ctx context.Context, id int) *User {
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryOwner queries the owner edge of a User.
|
// QueryOwner queries the owner edge of a User.
|
||||||
func (c *UserClient) QueryOwner(u *User) *PasswordTokenQuery {
|
func (c *UserClient) QueryOwner(_m *User) *PasswordTokenQuery {
|
||||||
query := &PasswordTokenQuery{config: c.config}
|
query := (&PasswordTokenClient{config: c.config}).Query()
|
||||||
query.path = func(ctx context.Context) (fromV *sql.Selector, _ error) {
|
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||||
id := u.ID
|
id := _m.ID
|
||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(user.Table, user.FieldID, id),
|
sqlgraph.From(user.Table, user.FieldID, id),
|
||||||
sqlgraph.To(passwordtoken.Table, passwordtoken.FieldID),
|
sqlgraph.To(passwordtoken.Table, passwordtoken.FieldID),
|
||||||
sqlgraph.Edge(sqlgraph.O2M, true, user.OwnerTable, user.OwnerColumn),
|
sqlgraph.Edge(sqlgraph.O2M, true, user.OwnerTable, user.OwnerColumn),
|
||||||
)
|
)
|
||||||
fromV = sqlgraph.Neighbors(u.driver.Dialect(), step)
|
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||||
return fromV, nil
|
return fromV, nil
|
||||||
}
|
}
|
||||||
return query
|
return query
|
||||||
|
|
@ -341,3 +486,33 @@ func (c *UserClient) Hooks() []Hook {
|
||||||
hooks := c.hooks.User
|
hooks := c.hooks.User
|
||||||
return append(hooks[:len(hooks):len(hooks)], user.Hooks[:]...)
|
return append(hooks[:len(hooks):len(hooks)], user.Hooks[:]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Interceptors returns the client interceptors.
|
||||||
|
func (c *UserClient) Interceptors() []Interceptor {
|
||||||
|
return c.inters.User
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UserClient) mutate(ctx context.Context, m *UserMutation) (Value, error) {
|
||||||
|
switch m.Op() {
|
||||||
|
case OpCreate:
|
||||||
|
return (&UserCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||||
|
case OpUpdate:
|
||||||
|
return (&UserUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||||
|
case OpUpdateOne:
|
||||||
|
return (&UserUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||||
|
case OpDelete, OpDeleteOne:
|
||||||
|
return (&UserDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("ent: unknown User mutation op: %q", m.Op())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hooks and interceptors per client, for fast access.
|
||||||
|
type (
|
||||||
|
hooks struct {
|
||||||
|
PasswordToken, User []ent.Hook
|
||||||
|
}
|
||||||
|
inters struct {
|
||||||
|
PasswordToken, User []ent.Interceptor
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
|
||||||
|
|
||||||
package ent
|
|
||||||
|
|
||||||
import (
|
|
||||||
"entgo.io/ent"
|
|
||||||
"entgo.io/ent/dialect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Option function to configure the client.
|
|
||||||
type Option func(*config)
|
|
||||||
|
|
||||||
// Config is the configuration for the client and its builder.
|
|
||||||
type config struct {
|
|
||||||
// driver used for executing database requests.
|
|
||||||
driver dialect.Driver
|
|
||||||
// debug enable a debug logging.
|
|
||||||
debug bool
|
|
||||||
// log used for logging on debug mode.
|
|
||||||
log func(...interface{})
|
|
||||||
// hooks to execute on mutations.
|
|
||||||
hooks *hooks
|
|
||||||
}
|
|
||||||
|
|
||||||
// hooks per client, for fast access.
|
|
||||||
type hooks struct {
|
|
||||||
PasswordToken []ent.Hook
|
|
||||||
User []ent.Hook
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options applies the options on the config object.
|
|
||||||
func (c *config) options(opts ...Option) {
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(c)
|
|
||||||
}
|
|
||||||
if c.debug {
|
|
||||||
c.driver = dialect.Debug(c.driver, c.log)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug enables debug logging on the ent.Driver.
|
|
||||||
func Debug() Option {
|
|
||||||
return func(c *config) {
|
|
||||||
c.debug = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log sets the logging function for debug mode.
|
|
||||||
func Log(fn func(...interface{})) Option {
|
|
||||||
return func(c *config) {
|
|
||||||
c.log = fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Driver configures the client driver.
|
|
||||||
func Driver(driver dialect.Driver) Option {
|
|
||||||
return func(c *config) {
|
|
||||||
c.driver = driver
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
|
||||||
|
|
||||||
package ent
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type clientCtxKey struct{}
|
|
||||||
|
|
||||||
// FromContext returns a Client stored inside a context, or nil if there isn't one.
|
|
||||||
func FromContext(ctx context.Context) *Client {
|
|
||||||
c, _ := ctx.Value(clientCtxKey{}).(*Client)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContext returns a new context with the given Client attached.
|
|
||||||
func NewContext(parent context.Context, c *Client) context.Context {
|
|
||||||
return context.WithValue(parent, clientCtxKey{}, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
type txCtxKey struct{}
|
|
||||||
|
|
||||||
// TxFromContext returns a Tx stored inside a context, or nil if there isn't one.
|
|
||||||
func TxFromContext(ctx context.Context) *Tx {
|
|
||||||
tx, _ := ctx.Value(txCtxKey{}).(*Tx)
|
|
||||||
return tx
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTxContext returns a new context with the given Tx attached.
|
|
||||||
func NewTxContext(parent context.Context, tx *Tx) context.Context {
|
|
||||||
return context.WithValue(parent, txCtxKey{}, tx)
|
|
||||||
}
|
|
||||||
439
ent/ent.go
439
ent/ent.go
|
|
@ -1,58 +1,91 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"goweb/ent/passwordtoken"
|
"reflect"
|
||||||
"goweb/ent/user"
|
"sync"
|
||||||
|
|
||||||
"entgo.io/ent"
|
"entgo.io/ent"
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/passwordtoken"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ent aliases to avoid import conflicts in user's code.
|
// ent aliases to avoid import conflicts in user's code.
|
||||||
type (
|
type (
|
||||||
Op = ent.Op
|
Op = ent.Op
|
||||||
Hook = ent.Hook
|
Hook = ent.Hook
|
||||||
Value = ent.Value
|
Value = ent.Value
|
||||||
Query = ent.Query
|
Query = ent.Query
|
||||||
Policy = ent.Policy
|
QueryContext = ent.QueryContext
|
||||||
Mutator = ent.Mutator
|
Querier = ent.Querier
|
||||||
Mutation = ent.Mutation
|
QuerierFunc = ent.QuerierFunc
|
||||||
MutateFunc = ent.MutateFunc
|
Interceptor = ent.Interceptor
|
||||||
|
InterceptFunc = ent.InterceptFunc
|
||||||
|
Traverser = ent.Traverser
|
||||||
|
TraverseFunc = ent.TraverseFunc
|
||||||
|
Policy = ent.Policy
|
||||||
|
Mutator = ent.Mutator
|
||||||
|
Mutation = ent.Mutation
|
||||||
|
MutateFunc = ent.MutateFunc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type clientCtxKey struct{}
|
||||||
|
|
||||||
|
// FromContext returns a Client stored inside a context, or nil if there isn't one.
|
||||||
|
func FromContext(ctx context.Context) *Client {
|
||||||
|
c, _ := ctx.Value(clientCtxKey{}).(*Client)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContext returns a new context with the given Client attached.
|
||||||
|
func NewContext(parent context.Context, c *Client) context.Context {
|
||||||
|
return context.WithValue(parent, clientCtxKey{}, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
type txCtxKey struct{}
|
||||||
|
|
||||||
|
// TxFromContext returns a Tx stored inside a context, or nil if there isn't one.
|
||||||
|
func TxFromContext(ctx context.Context) *Tx {
|
||||||
|
tx, _ := ctx.Value(txCtxKey{}).(*Tx)
|
||||||
|
return tx
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTxContext returns a new context with the given Tx attached.
|
||||||
|
func NewTxContext(parent context.Context, tx *Tx) context.Context {
|
||||||
|
return context.WithValue(parent, txCtxKey{}, tx)
|
||||||
|
}
|
||||||
|
|
||||||
// OrderFunc applies an ordering on the sql selector.
|
// OrderFunc applies an ordering on the sql selector.
|
||||||
|
// Deprecated: Use Asc/Desc functions or the package builders instead.
|
||||||
type OrderFunc func(*sql.Selector)
|
type OrderFunc func(*sql.Selector)
|
||||||
|
|
||||||
// columnChecker returns a function indicates if the column exists in the given column.
|
var (
|
||||||
func columnChecker(table string) func(string) error {
|
initCheck sync.Once
|
||||||
checks := map[string]func(string) bool{
|
columnCheck sql.ColumnCheck
|
||||||
passwordtoken.Table: passwordtoken.ValidColumn,
|
)
|
||||||
user.Table: user.ValidColumn,
|
|
||||||
}
|
// checkColumn checks if the column exists in the given table.
|
||||||
check, ok := checks[table]
|
func checkColumn(t, c string) error {
|
||||||
if !ok {
|
initCheck.Do(func() {
|
||||||
return func(string) error {
|
columnCheck = sql.NewColumnCheck(map[string]func(string) bool{
|
||||||
return fmt.Errorf("unknown table %q", table)
|
passwordtoken.Table: passwordtoken.ValidColumn,
|
||||||
}
|
user.Table: user.ValidColumn,
|
||||||
}
|
})
|
||||||
return func(column string) error {
|
})
|
||||||
if !check(column) {
|
return columnCheck(t, c)
|
||||||
return fmt.Errorf("unknown column %q for table %q", column, table)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Asc applies the given fields in ASC order.
|
// Asc applies the given fields in ASC order.
|
||||||
func Asc(fields ...string) OrderFunc {
|
func Asc(fields ...string) func(*sql.Selector) {
|
||||||
return func(s *sql.Selector) {
|
return func(s *sql.Selector) {
|
||||||
check := columnChecker(s.TableName())
|
|
||||||
for _, f := range fields {
|
for _, f := range fields {
|
||||||
if err := check(f); err != nil {
|
if err := checkColumn(s.TableName(), f); err != nil {
|
||||||
s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)})
|
s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)})
|
||||||
}
|
}
|
||||||
s.OrderBy(sql.Asc(s.C(f)))
|
s.OrderBy(sql.Asc(s.C(f)))
|
||||||
|
|
@ -61,11 +94,10 @@ func Asc(fields ...string) OrderFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Desc applies the given fields in DESC order.
|
// Desc applies the given fields in DESC order.
|
||||||
func Desc(fields ...string) OrderFunc {
|
func Desc(fields ...string) func(*sql.Selector) {
|
||||||
return func(s *sql.Selector) {
|
return func(s *sql.Selector) {
|
||||||
check := columnChecker(s.TableName())
|
|
||||||
for _, f := range fields {
|
for _, f := range fields {
|
||||||
if err := check(f); err != nil {
|
if err := checkColumn(s.TableName(), f); err != nil {
|
||||||
s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)})
|
s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)})
|
||||||
}
|
}
|
||||||
s.OrderBy(sql.Desc(s.C(f)))
|
s.OrderBy(sql.Desc(s.C(f)))
|
||||||
|
|
@ -81,7 +113,6 @@ type AggregateFunc func(*sql.Selector) string
|
||||||
// GroupBy(field1, field2).
|
// GroupBy(field1, field2).
|
||||||
// Aggregate(ent.As(ent.Sum(field1), "sum_field1"), (ent.As(ent.Sum(field2), "sum_field2")).
|
// Aggregate(ent.As(ent.Sum(field1), "sum_field1"), (ent.As(ent.Sum(field2), "sum_field2")).
|
||||||
// Scan(ctx, &v)
|
// Scan(ctx, &v)
|
||||||
//
|
|
||||||
func As(fn AggregateFunc, end string) AggregateFunc {
|
func As(fn AggregateFunc, end string) AggregateFunc {
|
||||||
return func(s *sql.Selector) string {
|
return func(s *sql.Selector) string {
|
||||||
return sql.As(fn(s), end)
|
return sql.As(fn(s), end)
|
||||||
|
|
@ -98,8 +129,7 @@ func Count() AggregateFunc {
|
||||||
// Max applies the "max" aggregation function on the given field of each group.
|
// Max applies the "max" aggregation function on the given field of each group.
|
||||||
func Max(field string) AggregateFunc {
|
func Max(field string) AggregateFunc {
|
||||||
return func(s *sql.Selector) string {
|
return func(s *sql.Selector) string {
|
||||||
check := columnChecker(s.TableName())
|
if err := checkColumn(s.TableName(), field); err != nil {
|
||||||
if err := check(field); err != nil {
|
|
||||||
s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
|
s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
@ -110,8 +140,7 @@ func Max(field string) AggregateFunc {
|
||||||
// Mean applies the "mean" aggregation function on the given field of each group.
|
// Mean applies the "mean" aggregation function on the given field of each group.
|
||||||
func Mean(field string) AggregateFunc {
|
func Mean(field string) AggregateFunc {
|
||||||
return func(s *sql.Selector) string {
|
return func(s *sql.Selector) string {
|
||||||
check := columnChecker(s.TableName())
|
if err := checkColumn(s.TableName(), field); err != nil {
|
||||||
if err := check(field); err != nil {
|
|
||||||
s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
|
s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
@ -122,8 +151,7 @@ func Mean(field string) AggregateFunc {
|
||||||
// Min applies the "min" aggregation function on the given field of each group.
|
// Min applies the "min" aggregation function on the given field of each group.
|
||||||
func Min(field string) AggregateFunc {
|
func Min(field string) AggregateFunc {
|
||||||
return func(s *sql.Selector) string {
|
return func(s *sql.Selector) string {
|
||||||
check := columnChecker(s.TableName())
|
if err := checkColumn(s.TableName(), field); err != nil {
|
||||||
if err := check(field); err != nil {
|
|
||||||
s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
|
s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
@ -134,8 +162,7 @@ func Min(field string) AggregateFunc {
|
||||||
// Sum applies the "sum" aggregation function on the given field of each group.
|
// Sum applies the "sum" aggregation function on the given field of each group.
|
||||||
func Sum(field string) AggregateFunc {
|
func Sum(field string) AggregateFunc {
|
||||||
return func(s *sql.Selector) string {
|
return func(s *sql.Selector) string {
|
||||||
check := columnChecker(s.TableName())
|
if err := checkColumn(s.TableName(), field); err != nil {
|
||||||
if err := check(field); err != nil {
|
|
||||||
s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
|
s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)})
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
@ -143,7 +170,7 @@ func Sum(field string) AggregateFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidationError returns when validating a field fails.
|
// ValidationError returns when validating a field or edge fails.
|
||||||
type ValidationError struct {
|
type ValidationError struct {
|
||||||
Name string // Field or edge name.
|
Name string // Field or edge name.
|
||||||
err error
|
err error
|
||||||
|
|
@ -259,3 +286,325 @@ func IsConstraintError(err error) bool {
|
||||||
var e *ConstraintError
|
var e *ConstraintError
|
||||||
return errors.As(err, &e)
|
return errors.As(err, &e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// selector embedded by the different Select/GroupBy builders.
|
||||||
|
type selector struct {
|
||||||
|
label string
|
||||||
|
flds *[]string
|
||||||
|
fns []AggregateFunc
|
||||||
|
scan func(context.Context, any) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScanX is like Scan, but panics if an error occurs.
|
||||||
|
func (s *selector) ScanX(ctx context.Context, v any) {
|
||||||
|
if err := s.scan(ctx, v); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strings returns list of strings from a selector. It is only allowed when selecting one field.
|
||||||
|
func (s *selector) Strings(ctx context.Context) ([]string, error) {
|
||||||
|
if len(*s.flds) > 1 {
|
||||||
|
return nil, errors.New("ent: Strings is not achievable when selecting more than 1 field")
|
||||||
|
}
|
||||||
|
var v []string
|
||||||
|
if err := s.scan(ctx, &v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringsX is like Strings, but panics if an error occurs.
|
||||||
|
func (s *selector) StringsX(ctx context.Context) []string {
|
||||||
|
v, err := s.Strings(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a single string from a selector. It is only allowed when selecting one field.
|
||||||
|
func (s *selector) String(ctx context.Context) (_ string, err error) {
|
||||||
|
var v []string
|
||||||
|
if v, err = s.Strings(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch len(v) {
|
||||||
|
case 1:
|
||||||
|
return v[0], nil
|
||||||
|
case 0:
|
||||||
|
err = &NotFoundError{s.label}
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("ent: Strings returned %d results when one was expected", len(v))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringX is like String, but panics if an error occurs.
|
||||||
|
func (s *selector) StringX(ctx context.Context) string {
|
||||||
|
v, err := s.String(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ints returns list of ints from a selector. It is only allowed when selecting one field.
|
||||||
|
func (s *selector) Ints(ctx context.Context) ([]int, error) {
|
||||||
|
if len(*s.flds) > 1 {
|
||||||
|
return nil, errors.New("ent: Ints is not achievable when selecting more than 1 field")
|
||||||
|
}
|
||||||
|
var v []int
|
||||||
|
if err := s.scan(ctx, &v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntsX is like Ints, but panics if an error occurs.
|
||||||
|
func (s *selector) IntsX(ctx context.Context) []int {
|
||||||
|
v, err := s.Ints(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int returns a single int from a selector. It is only allowed when selecting one field.
|
||||||
|
func (s *selector) Int(ctx context.Context) (_ int, err error) {
|
||||||
|
var v []int
|
||||||
|
if v, err = s.Ints(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch len(v) {
|
||||||
|
case 1:
|
||||||
|
return v[0], nil
|
||||||
|
case 0:
|
||||||
|
err = &NotFoundError{s.label}
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("ent: Ints returned %d results when one was expected", len(v))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntX is like Int, but panics if an error occurs.
|
||||||
|
func (s *selector) IntX(ctx context.Context) int {
|
||||||
|
v, err := s.Int(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.
|
||||||
|
func (s *selector) Float64s(ctx context.Context) ([]float64, error) {
|
||||||
|
if len(*s.flds) > 1 {
|
||||||
|
return nil, errors.New("ent: Float64s is not achievable when selecting more than 1 field")
|
||||||
|
}
|
||||||
|
var v []float64
|
||||||
|
if err := s.scan(ctx, &v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64sX is like Float64s, but panics if an error occurs.
|
||||||
|
func (s *selector) Float64sX(ctx context.Context) []float64 {
|
||||||
|
v, err := s.Float64s(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.
|
||||||
|
func (s *selector) Float64(ctx context.Context) (_ float64, err error) {
|
||||||
|
var v []float64
|
||||||
|
if v, err = s.Float64s(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch len(v) {
|
||||||
|
case 1:
|
||||||
|
return v[0], nil
|
||||||
|
case 0:
|
||||||
|
err = &NotFoundError{s.label}
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("ent: Float64s returned %d results when one was expected", len(v))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64X is like Float64, but panics if an error occurs.
|
||||||
|
func (s *selector) Float64X(ctx context.Context) float64 {
|
||||||
|
v, err := s.Float64(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bools returns list of bools from a selector. It is only allowed when selecting one field.
|
||||||
|
func (s *selector) Bools(ctx context.Context) ([]bool, error) {
|
||||||
|
if len(*s.flds) > 1 {
|
||||||
|
return nil, errors.New("ent: Bools is not achievable when selecting more than 1 field")
|
||||||
|
}
|
||||||
|
var v []bool
|
||||||
|
if err := s.scan(ctx, &v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolsX is like Bools, but panics if an error occurs.
|
||||||
|
func (s *selector) BoolsX(ctx context.Context) []bool {
|
||||||
|
v, err := s.Bools(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool returns a single bool from a selector. It is only allowed when selecting one field.
|
||||||
|
func (s *selector) Bool(ctx context.Context) (_ bool, err error) {
|
||||||
|
var v []bool
|
||||||
|
if v, err = s.Bools(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch len(v) {
|
||||||
|
case 1:
|
||||||
|
return v[0], nil
|
||||||
|
case 0:
|
||||||
|
err = &NotFoundError{s.label}
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("ent: Bools returned %d results when one was expected", len(v))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolX is like Bool, but panics if an error occurs.
|
||||||
|
func (s *selector) BoolX(ctx context.Context) bool {
|
||||||
|
v, err := s.Bool(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// withHooks invokes the builder operation with the given hooks, if any.
|
||||||
|
func withHooks[V Value, M any, PM interface {
|
||||||
|
*M
|
||||||
|
Mutation
|
||||||
|
}](ctx context.Context, exec func(context.Context) (V, error), mutation PM, hooks []Hook) (value V, err error) {
|
||||||
|
if len(hooks) == 0 {
|
||||||
|
return exec(ctx)
|
||||||
|
}
|
||||||
|
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||||
|
mutationT, ok := any(m).(PM)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
||||||
|
}
|
||||||
|
// Set the mutation to the builder.
|
||||||
|
*mutation = *mutationT
|
||||||
|
return exec(ctx)
|
||||||
|
})
|
||||||
|
for i := len(hooks) - 1; i >= 0; i-- {
|
||||||
|
if hooks[i] == nil {
|
||||||
|
return value, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
||||||
|
}
|
||||||
|
mut = hooks[i](mut)
|
||||||
|
}
|
||||||
|
v, err := mut.Mutate(ctx, mutation)
|
||||||
|
if err != nil {
|
||||||
|
return value, err
|
||||||
|
}
|
||||||
|
nv, ok := v.(V)
|
||||||
|
if !ok {
|
||||||
|
return value, fmt.Errorf("unexpected node type %T returned from %T", v, mutation)
|
||||||
|
}
|
||||||
|
return nv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setContextOp returns a new context with the given QueryContext attached (including its op) in case it does not exist.
|
||||||
|
func setContextOp(ctx context.Context, qc *QueryContext, op string) context.Context {
|
||||||
|
if ent.QueryFromContext(ctx) == nil {
|
||||||
|
qc.Op = op
|
||||||
|
ctx = ent.NewQueryContext(ctx, qc)
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func querierAll[V Value, Q interface {
|
||||||
|
sqlAll(context.Context, ...queryHook) (V, error)
|
||||||
|
}]() Querier {
|
||||||
|
return QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
|
||||||
|
query, ok := q.(Q)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unexpected query type %T", q)
|
||||||
|
}
|
||||||
|
return query.sqlAll(ctx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func querierCount[Q interface {
|
||||||
|
sqlCount(context.Context) (int, error)
|
||||||
|
}]() Querier {
|
||||||
|
return QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
|
||||||
|
query, ok := q.(Q)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unexpected query type %T", q)
|
||||||
|
}
|
||||||
|
return query.sqlCount(ctx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func withInterceptors[V Value](ctx context.Context, q Query, qr Querier, inters []Interceptor) (v V, err error) {
|
||||||
|
for i := len(inters) - 1; i >= 0; i-- {
|
||||||
|
qr = inters[i].Intercept(qr)
|
||||||
|
}
|
||||||
|
rv, err := qr.Query(ctx, q)
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
vt, ok := rv.(V)
|
||||||
|
if !ok {
|
||||||
|
return v, fmt.Errorf("unexpected type %T returned from %T. expected type: %T", vt, q, v)
|
||||||
|
}
|
||||||
|
return vt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanWithInterceptors[Q1 ent.Query, Q2 interface {
|
||||||
|
sqlScan(context.Context, Q1, any) error
|
||||||
|
}](ctx context.Context, rootQuery Q1, selectOrGroup Q2, inters []Interceptor, v any) error {
|
||||||
|
rv := reflect.ValueOf(v)
|
||||||
|
var qr Querier = QuerierFunc(func(ctx context.Context, q Query) (Value, error) {
|
||||||
|
query, ok := q.(Q1)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unexpected query type %T", q)
|
||||||
|
}
|
||||||
|
if err := selectOrGroup.sqlScan(ctx, query, v); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if k := rv.Kind(); k == reflect.Pointer && rv.Elem().CanInterface() {
|
||||||
|
return rv.Elem().Interface(), nil
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
})
|
||||||
|
for i := len(inters) - 1; i >= 0; i-- {
|
||||||
|
qr = inters[i].Intercept(qr)
|
||||||
|
}
|
||||||
|
vv, err := qr.Query(ctx, rootQuery)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch rv2 := reflect.ValueOf(vv); {
|
||||||
|
case rv.IsNil(), rv2.IsNil(), rv.Kind() != reflect.Pointer:
|
||||||
|
case rv.Type() == rv2.Type():
|
||||||
|
rv.Elem().Set(rv2.Elem())
|
||||||
|
case rv.Elem().Type() == rv2.Type():
|
||||||
|
rv.Elem().Set(rv2)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// queryHook describes an internal hook for the different sqlAll methods.
|
||||||
|
type queryHook func(context.Context, *sqlgraph.QuerySpec)
|
||||||
|
|
|
||||||
22
ent/entc.go
Normal file
22
ent/entc.go
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
//go:build ignore
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"entgo.io/ent/entc"
|
||||||
|
"entgo.io/ent/entc/gen"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/admin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := entc.Generate("./schema",
|
||||||
|
&gen.Config{},
|
||||||
|
entc.Extensions(&admin.Extension{}),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("running ent codegen:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package enttest
|
package enttest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"goweb/ent"
|
|
||||||
|
"github.com/mikestefanello/pagoda/ent"
|
||||||
// required by schema hooks.
|
// required by schema hooks.
|
||||||
_ "goweb/ent/runtime"
|
_ "github.com/mikestefanello/pagoda/ent/runtime"
|
||||||
|
|
||||||
"entgo.io/ent/dialect/sql/schema"
|
"entgo.io/ent/dialect/sql/schema"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/migrate"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|
@ -16,7 +18,7 @@ type (
|
||||||
// testing.T and testing.B and used by enttest.
|
// testing.T and testing.B and used by enttest.
|
||||||
TestingT interface {
|
TestingT interface {
|
||||||
FailNow()
|
FailNow()
|
||||||
Error(...interface{})
|
Error(...any)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option configures client creation.
|
// Option configures client creation.
|
||||||
|
|
@ -58,10 +60,7 @@ func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Cl
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
if err := c.Schema.Create(context.Background(), o.migrateOpts...); err != nil {
|
migrateSchema(t, c, o)
|
||||||
t.Error(err)
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,9 +68,17 @@ func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Cl
|
||||||
func NewClient(t TestingT, opts ...Option) *ent.Client {
|
func NewClient(t TestingT, opts ...Option) *ent.Client {
|
||||||
o := newOptions(opts)
|
o := newOptions(opts)
|
||||||
c := ent.NewClient(o.opts...)
|
c := ent.NewClient(o.opts...)
|
||||||
if err := c.Schema.Create(context.Background(), o.migrateOpts...); err != nil {
|
migrateSchema(t, c, o)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
func migrateSchema(t TestingT, c *ent.Client, o *options) {
|
||||||
|
tables, err := schema.CopyTables(migrate.Tables)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema
|
//go:generate go run -mod=mod entc.go
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package hook
|
package hook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"goweb/ent"
|
|
||||||
|
"github.com/mikestefanello/pagoda/ent"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The PasswordTokenFunc type is an adapter to allow the use of ordinary
|
// The PasswordTokenFunc type is an adapter to allow the use of ordinary
|
||||||
|
|
@ -14,11 +15,10 @@ type PasswordTokenFunc func(context.Context, *ent.PasswordTokenMutation) (ent.Va
|
||||||
|
|
||||||
// Mutate calls f(ctx, m).
|
// Mutate calls f(ctx, m).
|
||||||
func (f PasswordTokenFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
func (f PasswordTokenFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||||
mv, ok := m.(*ent.PasswordTokenMutation)
|
if mv, ok := m.(*ent.PasswordTokenMutation); ok {
|
||||||
if !ok {
|
return f(ctx, mv)
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.PasswordTokenMutation", m)
|
|
||||||
}
|
}
|
||||||
return f(ctx, mv)
|
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.PasswordTokenMutation", m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The UserFunc type is an adapter to allow the use of ordinary
|
// The UserFunc type is an adapter to allow the use of ordinary
|
||||||
|
|
@ -27,11 +27,10 @@ type UserFunc func(context.Context, *ent.UserMutation) (ent.Value, error)
|
||||||
|
|
||||||
// Mutate calls f(ctx, m).
|
// Mutate calls f(ctx, m).
|
||||||
func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||||
mv, ok := m.(*ent.UserMutation)
|
if mv, ok := m.(*ent.UserMutation); ok {
|
||||||
if !ok {
|
return f(ctx, mv)
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.UserMutation", m)
|
|
||||||
}
|
}
|
||||||
return f(ctx, mv)
|
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.UserMutation", m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Condition is a hook condition function.
|
// Condition is a hook condition function.
|
||||||
|
|
@ -129,7 +128,6 @@ func HasFields(field string, fields ...string) Condition {
|
||||||
// If executes the given hook under condition.
|
// If executes the given hook under condition.
|
||||||
//
|
//
|
||||||
// hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...)))
|
// hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...)))
|
||||||
//
|
|
||||||
func If(hk ent.Hook, cond Condition) ent.Hook {
|
func If(hk ent.Hook, cond Condition) ent.Hook {
|
||||||
return func(next ent.Mutator) ent.Mutator {
|
return func(next ent.Mutator) ent.Mutator {
|
||||||
return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) {
|
||||||
|
|
@ -144,7 +142,6 @@ func If(hk ent.Hook, cond Condition) ent.Hook {
|
||||||
// On executes the given hook only for the given operation.
|
// On executes the given hook only for the given operation.
|
||||||
//
|
//
|
||||||
// hook.On(Log, ent.Delete|ent.Create)
|
// hook.On(Log, ent.Delete|ent.Create)
|
||||||
//
|
|
||||||
func On(hk ent.Hook, op ent.Op) ent.Hook {
|
func On(hk ent.Hook, op ent.Op) ent.Hook {
|
||||||
return If(hk, HasOp(op))
|
return If(hk, HasOp(op))
|
||||||
}
|
}
|
||||||
|
|
@ -152,7 +149,6 @@ func On(hk ent.Hook, op ent.Op) ent.Hook {
|
||||||
// Unless skips the given hook only for the given operation.
|
// Unless skips the given hook only for the given operation.
|
||||||
//
|
//
|
||||||
// hook.Unless(Log, ent.Update|ent.UpdateOne)
|
// hook.Unless(Log, ent.Update|ent.UpdateOne)
|
||||||
//
|
|
||||||
func Unless(hk ent.Hook, op ent.Op) ent.Hook {
|
func Unless(hk ent.Hook, op ent.Op) ent.Hook {
|
||||||
return If(hk, Not(HasOp(op)))
|
return If(hk, Not(HasOp(op)))
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +169,6 @@ func FixedError(err error) ent.Hook {
|
||||||
// Reject(ent.Delete|ent.Update),
|
// Reject(ent.Delete|ent.Update),
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
func Reject(op ent.Op) ent.Hook {
|
func Reject(op ent.Op) ent.Hook {
|
||||||
hk := FixedError(fmt.Errorf("%s operation is not allowed", op))
|
hk := FixedError(fmt.Errorf("%s operation is not allowed", op))
|
||||||
return On(hk, op)
|
return On(hk, op)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package migrate
|
package migrate
|
||||||
|
|
||||||
|
|
@ -28,17 +28,13 @@ var (
|
||||||
// and therefore, it's recommended to enable this option to get more
|
// and therefore, it's recommended to enable this option to get more
|
||||||
// flexibility in the schema changes.
|
// flexibility in the schema changes.
|
||||||
WithDropIndex = schema.WithDropIndex
|
WithDropIndex = schema.WithDropIndex
|
||||||
// WithFixture sets the foreign-key renaming option to the migration when upgrading
|
|
||||||
// ent from v0.1.0 (issue-#285). Defaults to false.
|
|
||||||
WithFixture = schema.WithFixture
|
|
||||||
// WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true.
|
// WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true.
|
||||||
WithForeignKeys = schema.WithForeignKeys
|
WithForeignKeys = schema.WithForeignKeys
|
||||||
)
|
)
|
||||||
|
|
||||||
// Schema is the API for creating, migrating and dropping a schema.
|
// Schema is the API for creating, migrating and dropping a schema.
|
||||||
type Schema struct {
|
type Schema struct {
|
||||||
drv dialect.Driver
|
drv dialect.Driver
|
||||||
universalID bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSchema creates a new schema client.
|
// NewSchema creates a new schema client.
|
||||||
|
|
@ -46,27 +42,23 @@ func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} }
|
||||||
|
|
||||||
// Create creates all schema resources.
|
// Create creates all schema resources.
|
||||||
func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error {
|
func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error {
|
||||||
|
return Create(ctx, s, Tables, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates all table resources using the given schema driver.
|
||||||
|
func Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error {
|
||||||
migrate, err := schema.NewMigrate(s.drv, opts...)
|
migrate, err := schema.NewMigrate(s.drv, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("ent/migrate: %w", err)
|
return fmt.Errorf("ent/migrate: %w", err)
|
||||||
}
|
}
|
||||||
return migrate.Create(ctx, Tables...)
|
return migrate.Create(ctx, tables...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteTo writes the schema changes to w instead of running them against the database.
|
// WriteTo writes the schema changes to w instead of running them against the database.
|
||||||
//
|
//
|
||||||
// if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil {
|
// if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil {
|
||||||
// log.Fatal(err)
|
// log.Fatal(err)
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error {
|
func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error {
|
||||||
drv := &schema.WriteDriver{
|
return Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...)
|
||||||
Writer: w,
|
|
||||||
Driver: s.drv,
|
|
||||||
}
|
|
||||||
migrate, err := schema.NewMigrate(drv, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("ent/migrate: %w", err)
|
|
||||||
}
|
|
||||||
return migrate.Create(ctx, Tables...)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package migrate
|
package migrate
|
||||||
|
|
||||||
|
|
@ -11,9 +11,9 @@ var (
|
||||||
// PasswordTokensColumns holds the columns for the "password_tokens" table.
|
// PasswordTokensColumns holds the columns for the "password_tokens" table.
|
||||||
PasswordTokensColumns = []*schema.Column{
|
PasswordTokensColumns = []*schema.Column{
|
||||||
{Name: "id", Type: field.TypeInt, Increment: true},
|
{Name: "id", Type: field.TypeInt, Increment: true},
|
||||||
{Name: "hash", Type: field.TypeString},
|
{Name: "token", Type: field.TypeString},
|
||||||
{Name: "created_at", Type: field.TypeTime},
|
{Name: "created_at", Type: field.TypeTime},
|
||||||
{Name: "password_token_user", Type: field.TypeInt, Nullable: true},
|
{Name: "user_id", Type: field.TypeInt},
|
||||||
}
|
}
|
||||||
// PasswordTokensTable holds the schema information for the "password_tokens" table.
|
// PasswordTokensTable holds the schema information for the "password_tokens" table.
|
||||||
PasswordTokensTable = &schema.Table{
|
PasswordTokensTable = &schema.Table{
|
||||||
|
|
@ -25,7 +25,7 @@ var (
|
||||||
Symbol: "password_tokens_users_user",
|
Symbol: "password_tokens_users_user",
|
||||||
Columns: []*schema.Column{PasswordTokensColumns[3]},
|
Columns: []*schema.Column{PasswordTokensColumns[3]},
|
||||||
RefColumns: []*schema.Column{UsersColumns[0]},
|
RefColumns: []*schema.Column{UsersColumns[0]},
|
||||||
OnDelete: schema.SetNull,
|
OnDelete: schema.NoAction,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -35,6 +35,8 @@ var (
|
||||||
{Name: "name", Type: field.TypeString},
|
{Name: "name", Type: field.TypeString},
|
||||||
{Name: "email", Type: field.TypeString, Unique: true},
|
{Name: "email", Type: field.TypeString, Unique: true},
|
||||||
{Name: "password", Type: field.TypeString},
|
{Name: "password", Type: field.TypeString},
|
||||||
|
{Name: "verified", Type: field.TypeBool, Default: false},
|
||||||
|
{Name: "admin", Type: field.TypeBool, Default: false},
|
||||||
{Name: "created_at", Type: field.TypeTime},
|
{Name: "created_at", Type: field.TypeTime},
|
||||||
}
|
}
|
||||||
// UsersTable holds the schema information for the "users" table.
|
// UsersTable holds the schema information for the "users" table.
|
||||||
|
|
|
||||||
344
ent/mutation.go
344
ent/mutation.go
|
|
@ -1,17 +1,19 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"goweb/ent/passwordtoken"
|
|
||||||
"goweb/ent/predicate"
|
|
||||||
"goweb/ent/user"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"entgo.io/ent"
|
"entgo.io/ent"
|
||||||
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/passwordtoken"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/predicate"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -33,7 +35,7 @@ type PasswordTokenMutation struct {
|
||||||
op Op
|
op Op
|
||||||
typ string
|
typ string
|
||||||
id *int
|
id *int
|
||||||
hash *string
|
token *string
|
||||||
created_at *time.Time
|
created_at *time.Time
|
||||||
clearedFields map[string]struct{}
|
clearedFields map[string]struct{}
|
||||||
user *int
|
user *int
|
||||||
|
|
@ -73,7 +75,7 @@ func withPasswordTokenID(id int) passwordtokenOption {
|
||||||
m.oldValue = func(ctx context.Context) (*PasswordToken, error) {
|
m.oldValue = func(ctx context.Context) (*PasswordToken, error) {
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
if m.done {
|
if m.done {
|
||||||
err = fmt.Errorf("querying old values post mutation is not allowed")
|
err = errors.New("querying old values post mutation is not allowed")
|
||||||
} else {
|
} else {
|
||||||
value, err = m.Client().PasswordToken.Get(ctx, id)
|
value, err = m.Client().PasswordToken.Get(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +108,7 @@ func (m PasswordTokenMutation) Client() *Client {
|
||||||
// it returns an error otherwise.
|
// it returns an error otherwise.
|
||||||
func (m PasswordTokenMutation) Tx() (*Tx, error) {
|
func (m PasswordTokenMutation) Tx() (*Tx, error) {
|
||||||
if _, ok := m.driver.(*txDriver); !ok {
|
if _, ok := m.driver.(*txDriver); !ok {
|
||||||
return nil, fmt.Errorf("ent: mutation is not running in a transaction")
|
return nil, errors.New("ent: mutation is not running in a transaction")
|
||||||
}
|
}
|
||||||
tx := &Tx{config: m.config}
|
tx := &Tx{config: m.config}
|
||||||
tx.init()
|
tx.init()
|
||||||
|
|
@ -122,40 +124,95 @@ func (m *PasswordTokenMutation) ID() (id int, exists bool) {
|
||||||
return *m.id, true
|
return *m.id, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHash sets the "hash" field.
|
// IDs queries the database and returns the entity ids that match the mutation's predicate.
|
||||||
func (m *PasswordTokenMutation) SetHash(s string) {
|
// That means, if the mutation is applied within a transaction with an isolation level such
|
||||||
m.hash = &s
|
// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated
|
||||||
|
// or updated by the mutation.
|
||||||
|
func (m *PasswordTokenMutation) IDs(ctx context.Context) ([]int, error) {
|
||||||
|
switch {
|
||||||
|
case m.op.Is(OpUpdateOne | OpDeleteOne):
|
||||||
|
id, exists := m.ID()
|
||||||
|
if exists {
|
||||||
|
return []int{id}, nil
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case m.op.Is(OpUpdate | OpDelete):
|
||||||
|
return m.Client().PasswordToken.Query().Where(m.predicates...).IDs(ctx)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash returns the value of the "hash" field in the mutation.
|
// SetToken sets the "token" field.
|
||||||
func (m *PasswordTokenMutation) Hash() (r string, exists bool) {
|
func (m *PasswordTokenMutation) SetToken(s string) {
|
||||||
v := m.hash
|
m.token = &s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token returns the value of the "token" field in the mutation.
|
||||||
|
func (m *PasswordTokenMutation) Token() (r string, exists bool) {
|
||||||
|
v := m.token
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return *v, true
|
return *v, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// OldHash returns the old "hash" field's value of the PasswordToken entity.
|
// OldToken returns the old "token" field's value of the PasswordToken entity.
|
||||||
// If the PasswordToken object wasn't provided to the builder, the object is fetched from the database.
|
// If the PasswordToken object wasn't provided to the builder, the object is fetched from the database.
|
||||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||||
func (m *PasswordTokenMutation) OldHash(ctx context.Context) (v string, err error) {
|
func (m *PasswordTokenMutation) OldToken(ctx context.Context) (v string, err error) {
|
||||||
if !m.op.Is(OpUpdateOne) {
|
if !m.op.Is(OpUpdateOne) {
|
||||||
return v, fmt.Errorf("OldHash is only allowed on UpdateOne operations")
|
return v, errors.New("OldToken is only allowed on UpdateOne operations")
|
||||||
}
|
}
|
||||||
if m.id == nil || m.oldValue == nil {
|
if m.id == nil || m.oldValue == nil {
|
||||||
return v, fmt.Errorf("OldHash requires an ID field in the mutation")
|
return v, errors.New("OldToken requires an ID field in the mutation")
|
||||||
}
|
}
|
||||||
oldValue, err := m.oldValue(ctx)
|
oldValue, err := m.oldValue(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return v, fmt.Errorf("querying old value for OldHash: %w", err)
|
return v, fmt.Errorf("querying old value for OldToken: %w", err)
|
||||||
}
|
}
|
||||||
return oldValue.Hash, nil
|
return oldValue.Token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetHash resets all changes to the "hash" field.
|
// ResetToken resets all changes to the "token" field.
|
||||||
func (m *PasswordTokenMutation) ResetHash() {
|
func (m *PasswordTokenMutation) ResetToken() {
|
||||||
m.hash = nil
|
m.token = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUserID sets the "user_id" field.
|
||||||
|
func (m *PasswordTokenMutation) SetUserID(i int) {
|
||||||
|
m.user = &i
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserID returns the value of the "user_id" field in the mutation.
|
||||||
|
func (m *PasswordTokenMutation) UserID() (r int, exists bool) {
|
||||||
|
v := m.user
|
||||||
|
if v == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return *v, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// OldUserID returns the old "user_id" field's value of the PasswordToken entity.
|
||||||
|
// If the PasswordToken object wasn't provided to the builder, the object is fetched from the database.
|
||||||
|
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||||
|
func (m *PasswordTokenMutation) OldUserID(ctx context.Context) (v int, err error) {
|
||||||
|
if !m.op.Is(OpUpdateOne) {
|
||||||
|
return v, errors.New("OldUserID is only allowed on UpdateOne operations")
|
||||||
|
}
|
||||||
|
if m.id == nil || m.oldValue == nil {
|
||||||
|
return v, errors.New("OldUserID requires an ID field in the mutation")
|
||||||
|
}
|
||||||
|
oldValue, err := m.oldValue(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return v, fmt.Errorf("querying old value for OldUserID: %w", err)
|
||||||
|
}
|
||||||
|
return oldValue.UserID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetUserID resets all changes to the "user_id" field.
|
||||||
|
func (m *PasswordTokenMutation) ResetUserID() {
|
||||||
|
m.user = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCreatedAt sets the "created_at" field.
|
// SetCreatedAt sets the "created_at" field.
|
||||||
|
|
@ -177,10 +234,10 @@ func (m *PasswordTokenMutation) CreatedAt() (r time.Time, exists bool) {
|
||||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||||
func (m *PasswordTokenMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) {
|
func (m *PasswordTokenMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) {
|
||||||
if !m.op.Is(OpUpdateOne) {
|
if !m.op.Is(OpUpdateOne) {
|
||||||
return v, fmt.Errorf("OldCreatedAt is only allowed on UpdateOne operations")
|
return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations")
|
||||||
}
|
}
|
||||||
if m.id == nil || m.oldValue == nil {
|
if m.id == nil || m.oldValue == nil {
|
||||||
return v, fmt.Errorf("OldCreatedAt requires an ID field in the mutation")
|
return v, errors.New("OldCreatedAt requires an ID field in the mutation")
|
||||||
}
|
}
|
||||||
oldValue, err := m.oldValue(ctx)
|
oldValue, err := m.oldValue(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -194,14 +251,10 @@ func (m *PasswordTokenMutation) ResetCreatedAt() {
|
||||||
m.created_at = nil
|
m.created_at = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUserID sets the "user" edge to the User entity by id.
|
|
||||||
func (m *PasswordTokenMutation) SetUserID(id int) {
|
|
||||||
m.user = &id
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClearUser clears the "user" edge to the User entity.
|
// ClearUser clears the "user" edge to the User entity.
|
||||||
func (m *PasswordTokenMutation) ClearUser() {
|
func (m *PasswordTokenMutation) ClearUser() {
|
||||||
m.cleareduser = true
|
m.cleareduser = true
|
||||||
|
m.clearedFields[passwordtoken.FieldUserID] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserCleared reports if the "user" edge to the User entity was cleared.
|
// UserCleared reports if the "user" edge to the User entity was cleared.
|
||||||
|
|
@ -209,14 +262,6 @@ func (m *PasswordTokenMutation) UserCleared() bool {
|
||||||
return m.cleareduser
|
return m.cleareduser
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserID returns the "user" edge ID in the mutation.
|
|
||||||
func (m *PasswordTokenMutation) UserID() (id int, exists bool) {
|
|
||||||
if m.user != nil {
|
|
||||||
return *m.user, true
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserIDs returns the "user" edge IDs in the mutation.
|
// UserIDs returns the "user" edge IDs in the mutation.
|
||||||
// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use
|
// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use
|
||||||
// UserID instead. It exists only for internal usage by the builders.
|
// UserID instead. It exists only for internal usage by the builders.
|
||||||
|
|
@ -238,11 +283,26 @@ func (m *PasswordTokenMutation) Where(ps ...predicate.PasswordToken) {
|
||||||
m.predicates = append(m.predicates, ps...)
|
m.predicates = append(m.predicates, ps...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WhereP appends storage-level predicates to the PasswordTokenMutation builder. Using this method,
|
||||||
|
// users can use type-assertion to append predicates that do not depend on any generated package.
|
||||||
|
func (m *PasswordTokenMutation) WhereP(ps ...func(*sql.Selector)) {
|
||||||
|
p := make([]predicate.PasswordToken, len(ps))
|
||||||
|
for i := range ps {
|
||||||
|
p[i] = ps[i]
|
||||||
|
}
|
||||||
|
m.Where(p...)
|
||||||
|
}
|
||||||
|
|
||||||
// Op returns the operation name.
|
// Op returns the operation name.
|
||||||
func (m *PasswordTokenMutation) Op() Op {
|
func (m *PasswordTokenMutation) Op() Op {
|
||||||
return m.op
|
return m.op
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetOp allows setting the mutation operation.
|
||||||
|
func (m *PasswordTokenMutation) SetOp(op Op) {
|
||||||
|
m.op = op
|
||||||
|
}
|
||||||
|
|
||||||
// Type returns the node type of this mutation (PasswordToken).
|
// Type returns the node type of this mutation (PasswordToken).
|
||||||
func (m *PasswordTokenMutation) Type() string {
|
func (m *PasswordTokenMutation) Type() string {
|
||||||
return m.typ
|
return m.typ
|
||||||
|
|
@ -252,9 +312,12 @@ func (m *PasswordTokenMutation) Type() string {
|
||||||
// order to get all numeric fields that were incremented/decremented, call
|
// order to get all numeric fields that were incremented/decremented, call
|
||||||
// AddedFields().
|
// AddedFields().
|
||||||
func (m *PasswordTokenMutation) Fields() []string {
|
func (m *PasswordTokenMutation) Fields() []string {
|
||||||
fields := make([]string, 0, 2)
|
fields := make([]string, 0, 3)
|
||||||
if m.hash != nil {
|
if m.token != nil {
|
||||||
fields = append(fields, passwordtoken.FieldHash)
|
fields = append(fields, passwordtoken.FieldToken)
|
||||||
|
}
|
||||||
|
if m.user != nil {
|
||||||
|
fields = append(fields, passwordtoken.FieldUserID)
|
||||||
}
|
}
|
||||||
if m.created_at != nil {
|
if m.created_at != nil {
|
||||||
fields = append(fields, passwordtoken.FieldCreatedAt)
|
fields = append(fields, passwordtoken.FieldCreatedAt)
|
||||||
|
|
@ -267,8 +330,10 @@ func (m *PasswordTokenMutation) Fields() []string {
|
||||||
// schema.
|
// schema.
|
||||||
func (m *PasswordTokenMutation) Field(name string) (ent.Value, bool) {
|
func (m *PasswordTokenMutation) Field(name string) (ent.Value, bool) {
|
||||||
switch name {
|
switch name {
|
||||||
case passwordtoken.FieldHash:
|
case passwordtoken.FieldToken:
|
||||||
return m.Hash()
|
return m.Token()
|
||||||
|
case passwordtoken.FieldUserID:
|
||||||
|
return m.UserID()
|
||||||
case passwordtoken.FieldCreatedAt:
|
case passwordtoken.FieldCreatedAt:
|
||||||
return m.CreatedAt()
|
return m.CreatedAt()
|
||||||
}
|
}
|
||||||
|
|
@ -280,8 +345,10 @@ func (m *PasswordTokenMutation) Field(name string) (ent.Value, bool) {
|
||||||
// database failed.
|
// database failed.
|
||||||
func (m *PasswordTokenMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
|
func (m *PasswordTokenMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
|
||||||
switch name {
|
switch name {
|
||||||
case passwordtoken.FieldHash:
|
case passwordtoken.FieldToken:
|
||||||
return m.OldHash(ctx)
|
return m.OldToken(ctx)
|
||||||
|
case passwordtoken.FieldUserID:
|
||||||
|
return m.OldUserID(ctx)
|
||||||
case passwordtoken.FieldCreatedAt:
|
case passwordtoken.FieldCreatedAt:
|
||||||
return m.OldCreatedAt(ctx)
|
return m.OldCreatedAt(ctx)
|
||||||
}
|
}
|
||||||
|
|
@ -293,12 +360,19 @@ func (m *PasswordTokenMutation) OldField(ctx context.Context, name string) (ent.
|
||||||
// type.
|
// type.
|
||||||
func (m *PasswordTokenMutation) SetField(name string, value ent.Value) error {
|
func (m *PasswordTokenMutation) SetField(name string, value ent.Value) error {
|
||||||
switch name {
|
switch name {
|
||||||
case passwordtoken.FieldHash:
|
case passwordtoken.FieldToken:
|
||||||
v, ok := value.(string)
|
v, ok := value.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||||
}
|
}
|
||||||
m.SetHash(v)
|
m.SetToken(v)
|
||||||
|
return nil
|
||||||
|
case passwordtoken.FieldUserID:
|
||||||
|
v, ok := value.(int)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||||
|
}
|
||||||
|
m.SetUserID(v)
|
||||||
return nil
|
return nil
|
||||||
case passwordtoken.FieldCreatedAt:
|
case passwordtoken.FieldCreatedAt:
|
||||||
v, ok := value.(time.Time)
|
v, ok := value.(time.Time)
|
||||||
|
|
@ -314,13 +388,16 @@ func (m *PasswordTokenMutation) SetField(name string, value ent.Value) error {
|
||||||
// AddedFields returns all numeric fields that were incremented/decremented during
|
// AddedFields returns all numeric fields that were incremented/decremented during
|
||||||
// this mutation.
|
// this mutation.
|
||||||
func (m *PasswordTokenMutation) AddedFields() []string {
|
func (m *PasswordTokenMutation) AddedFields() []string {
|
||||||
return nil
|
var fields []string
|
||||||
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddedField returns the numeric value that was incremented/decremented on a field
|
// AddedField returns the numeric value that was incremented/decremented on a field
|
||||||
// with the given name. The second boolean return value indicates that this field
|
// with the given name. The second boolean return value indicates that this field
|
||||||
// was not set, or was not defined in the schema.
|
// was not set, or was not defined in the schema.
|
||||||
func (m *PasswordTokenMutation) AddedField(name string) (ent.Value, bool) {
|
func (m *PasswordTokenMutation) AddedField(name string) (ent.Value, bool) {
|
||||||
|
switch name {
|
||||||
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -356,8 +433,11 @@ func (m *PasswordTokenMutation) ClearField(name string) error {
|
||||||
// It returns an error if the field is not defined in the schema.
|
// It returns an error if the field is not defined in the schema.
|
||||||
func (m *PasswordTokenMutation) ResetField(name string) error {
|
func (m *PasswordTokenMutation) ResetField(name string) error {
|
||||||
switch name {
|
switch name {
|
||||||
case passwordtoken.FieldHash:
|
case passwordtoken.FieldToken:
|
||||||
m.ResetHash()
|
m.ResetToken()
|
||||||
|
return nil
|
||||||
|
case passwordtoken.FieldUserID:
|
||||||
|
m.ResetUserID()
|
||||||
return nil
|
return nil
|
||||||
case passwordtoken.FieldCreatedAt:
|
case passwordtoken.FieldCreatedAt:
|
||||||
m.ResetCreatedAt()
|
m.ResetCreatedAt()
|
||||||
|
|
@ -396,8 +476,6 @@ func (m *PasswordTokenMutation) RemovedEdges() []string {
|
||||||
// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
|
// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
|
||||||
// the given name in this mutation.
|
// the given name in this mutation.
|
||||||
func (m *PasswordTokenMutation) RemovedIDs(name string) []ent.Value {
|
func (m *PasswordTokenMutation) RemovedIDs(name string) []ent.Value {
|
||||||
switch name {
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -451,6 +529,8 @@ type UserMutation struct {
|
||||||
name *string
|
name *string
|
||||||
email *string
|
email *string
|
||||||
password *string
|
password *string
|
||||||
|
verified *bool
|
||||||
|
admin *bool
|
||||||
created_at *time.Time
|
created_at *time.Time
|
||||||
clearedFields map[string]struct{}
|
clearedFields map[string]struct{}
|
||||||
owner map[int]struct{}
|
owner map[int]struct{}
|
||||||
|
|
@ -491,7 +571,7 @@ func withUserID(id int) userOption {
|
||||||
m.oldValue = func(ctx context.Context) (*User, error) {
|
m.oldValue = func(ctx context.Context) (*User, error) {
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
if m.done {
|
if m.done {
|
||||||
err = fmt.Errorf("querying old values post mutation is not allowed")
|
err = errors.New("querying old values post mutation is not allowed")
|
||||||
} else {
|
} else {
|
||||||
value, err = m.Client().User.Get(ctx, id)
|
value, err = m.Client().User.Get(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
@ -524,7 +604,7 @@ func (m UserMutation) Client() *Client {
|
||||||
// it returns an error otherwise.
|
// it returns an error otherwise.
|
||||||
func (m UserMutation) Tx() (*Tx, error) {
|
func (m UserMutation) Tx() (*Tx, error) {
|
||||||
if _, ok := m.driver.(*txDriver); !ok {
|
if _, ok := m.driver.(*txDriver); !ok {
|
||||||
return nil, fmt.Errorf("ent: mutation is not running in a transaction")
|
return nil, errors.New("ent: mutation is not running in a transaction")
|
||||||
}
|
}
|
||||||
tx := &Tx{config: m.config}
|
tx := &Tx{config: m.config}
|
||||||
tx.init()
|
tx.init()
|
||||||
|
|
@ -540,6 +620,25 @@ func (m *UserMutation) ID() (id int, exists bool) {
|
||||||
return *m.id, true
|
return *m.id, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IDs queries the database and returns the entity ids that match the mutation's predicate.
|
||||||
|
// That means, if the mutation is applied within a transaction with an isolation level such
|
||||||
|
// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated
|
||||||
|
// or updated by the mutation.
|
||||||
|
func (m *UserMutation) IDs(ctx context.Context) ([]int, error) {
|
||||||
|
switch {
|
||||||
|
case m.op.Is(OpUpdateOne | OpDeleteOne):
|
||||||
|
id, exists := m.ID()
|
||||||
|
if exists {
|
||||||
|
return []int{id}, nil
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case m.op.Is(OpUpdate | OpDelete):
|
||||||
|
return m.Client().User.Query().Where(m.predicates...).IDs(ctx)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetName sets the "name" field.
|
// SetName sets the "name" field.
|
||||||
func (m *UserMutation) SetName(s string) {
|
func (m *UserMutation) SetName(s string) {
|
||||||
m.name = &s
|
m.name = &s
|
||||||
|
|
@ -559,10 +658,10 @@ func (m *UserMutation) Name() (r string, exists bool) {
|
||||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||||
func (m *UserMutation) OldName(ctx context.Context) (v string, err error) {
|
func (m *UserMutation) OldName(ctx context.Context) (v string, err error) {
|
||||||
if !m.op.Is(OpUpdateOne) {
|
if !m.op.Is(OpUpdateOne) {
|
||||||
return v, fmt.Errorf("OldName is only allowed on UpdateOne operations")
|
return v, errors.New("OldName is only allowed on UpdateOne operations")
|
||||||
}
|
}
|
||||||
if m.id == nil || m.oldValue == nil {
|
if m.id == nil || m.oldValue == nil {
|
||||||
return v, fmt.Errorf("OldName requires an ID field in the mutation")
|
return v, errors.New("OldName requires an ID field in the mutation")
|
||||||
}
|
}
|
||||||
oldValue, err := m.oldValue(ctx)
|
oldValue, err := m.oldValue(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -595,10 +694,10 @@ func (m *UserMutation) Email() (r string, exists bool) {
|
||||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||||
func (m *UserMutation) OldEmail(ctx context.Context) (v string, err error) {
|
func (m *UserMutation) OldEmail(ctx context.Context) (v string, err error) {
|
||||||
if !m.op.Is(OpUpdateOne) {
|
if !m.op.Is(OpUpdateOne) {
|
||||||
return v, fmt.Errorf("OldEmail is only allowed on UpdateOne operations")
|
return v, errors.New("OldEmail is only allowed on UpdateOne operations")
|
||||||
}
|
}
|
||||||
if m.id == nil || m.oldValue == nil {
|
if m.id == nil || m.oldValue == nil {
|
||||||
return v, fmt.Errorf("OldEmail requires an ID field in the mutation")
|
return v, errors.New("OldEmail requires an ID field in the mutation")
|
||||||
}
|
}
|
||||||
oldValue, err := m.oldValue(ctx)
|
oldValue, err := m.oldValue(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -631,10 +730,10 @@ func (m *UserMutation) Password() (r string, exists bool) {
|
||||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||||
func (m *UserMutation) OldPassword(ctx context.Context) (v string, err error) {
|
func (m *UserMutation) OldPassword(ctx context.Context) (v string, err error) {
|
||||||
if !m.op.Is(OpUpdateOne) {
|
if !m.op.Is(OpUpdateOne) {
|
||||||
return v, fmt.Errorf("OldPassword is only allowed on UpdateOne operations")
|
return v, errors.New("OldPassword is only allowed on UpdateOne operations")
|
||||||
}
|
}
|
||||||
if m.id == nil || m.oldValue == nil {
|
if m.id == nil || m.oldValue == nil {
|
||||||
return v, fmt.Errorf("OldPassword requires an ID field in the mutation")
|
return v, errors.New("OldPassword requires an ID field in the mutation")
|
||||||
}
|
}
|
||||||
oldValue, err := m.oldValue(ctx)
|
oldValue, err := m.oldValue(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -648,6 +747,78 @@ func (m *UserMutation) ResetPassword() {
|
||||||
m.password = nil
|
m.password = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetVerified sets the "verified" field.
|
||||||
|
func (m *UserMutation) SetVerified(b bool) {
|
||||||
|
m.verified = &b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verified returns the value of the "verified" field in the mutation.
|
||||||
|
func (m *UserMutation) Verified() (r bool, exists bool) {
|
||||||
|
v := m.verified
|
||||||
|
if v == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return *v, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// OldVerified returns the old "verified" field's value of the User entity.
|
||||||
|
// If the User object wasn't provided to the builder, the object is fetched from the database.
|
||||||
|
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||||
|
func (m *UserMutation) OldVerified(ctx context.Context) (v bool, err error) {
|
||||||
|
if !m.op.Is(OpUpdateOne) {
|
||||||
|
return v, errors.New("OldVerified is only allowed on UpdateOne operations")
|
||||||
|
}
|
||||||
|
if m.id == nil || m.oldValue == nil {
|
||||||
|
return v, errors.New("OldVerified requires an ID field in the mutation")
|
||||||
|
}
|
||||||
|
oldValue, err := m.oldValue(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return v, fmt.Errorf("querying old value for OldVerified: %w", err)
|
||||||
|
}
|
||||||
|
return oldValue.Verified, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetVerified resets all changes to the "verified" field.
|
||||||
|
func (m *UserMutation) ResetVerified() {
|
||||||
|
m.verified = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAdmin sets the "admin" field.
|
||||||
|
func (m *UserMutation) SetAdmin(b bool) {
|
||||||
|
m.admin = &b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Admin returns the value of the "admin" field in the mutation.
|
||||||
|
func (m *UserMutation) Admin() (r bool, exists bool) {
|
||||||
|
v := m.admin
|
||||||
|
if v == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return *v, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// OldAdmin returns the old "admin" field's value of the User entity.
|
||||||
|
// If the User object wasn't provided to the builder, the object is fetched from the database.
|
||||||
|
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||||
|
func (m *UserMutation) OldAdmin(ctx context.Context) (v bool, err error) {
|
||||||
|
if !m.op.Is(OpUpdateOne) {
|
||||||
|
return v, errors.New("OldAdmin is only allowed on UpdateOne operations")
|
||||||
|
}
|
||||||
|
if m.id == nil || m.oldValue == nil {
|
||||||
|
return v, errors.New("OldAdmin requires an ID field in the mutation")
|
||||||
|
}
|
||||||
|
oldValue, err := m.oldValue(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return v, fmt.Errorf("querying old value for OldAdmin: %w", err)
|
||||||
|
}
|
||||||
|
return oldValue.Admin, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetAdmin resets all changes to the "admin" field.
|
||||||
|
func (m *UserMutation) ResetAdmin() {
|
||||||
|
m.admin = nil
|
||||||
|
}
|
||||||
|
|
||||||
// SetCreatedAt sets the "created_at" field.
|
// SetCreatedAt sets the "created_at" field.
|
||||||
func (m *UserMutation) SetCreatedAt(t time.Time) {
|
func (m *UserMutation) SetCreatedAt(t time.Time) {
|
||||||
m.created_at = &t
|
m.created_at = &t
|
||||||
|
|
@ -667,10 +838,10 @@ func (m *UserMutation) CreatedAt() (r time.Time, exists bool) {
|
||||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||||
func (m *UserMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) {
|
func (m *UserMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) {
|
||||||
if !m.op.Is(OpUpdateOne) {
|
if !m.op.Is(OpUpdateOne) {
|
||||||
return v, fmt.Errorf("OldCreatedAt is only allowed on UpdateOne operations")
|
return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations")
|
||||||
}
|
}
|
||||||
if m.id == nil || m.oldValue == nil {
|
if m.id == nil || m.oldValue == nil {
|
||||||
return v, fmt.Errorf("OldCreatedAt requires an ID field in the mutation")
|
return v, errors.New("OldCreatedAt requires an ID field in the mutation")
|
||||||
}
|
}
|
||||||
oldValue, err := m.oldValue(ctx)
|
oldValue, err := m.oldValue(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -743,11 +914,26 @@ func (m *UserMutation) Where(ps ...predicate.User) {
|
||||||
m.predicates = append(m.predicates, ps...)
|
m.predicates = append(m.predicates, ps...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WhereP appends storage-level predicates to the UserMutation builder. Using this method,
|
||||||
|
// users can use type-assertion to append predicates that do not depend on any generated package.
|
||||||
|
func (m *UserMutation) WhereP(ps ...func(*sql.Selector)) {
|
||||||
|
p := make([]predicate.User, len(ps))
|
||||||
|
for i := range ps {
|
||||||
|
p[i] = ps[i]
|
||||||
|
}
|
||||||
|
m.Where(p...)
|
||||||
|
}
|
||||||
|
|
||||||
// Op returns the operation name.
|
// Op returns the operation name.
|
||||||
func (m *UserMutation) Op() Op {
|
func (m *UserMutation) Op() Op {
|
||||||
return m.op
|
return m.op
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetOp allows setting the mutation operation.
|
||||||
|
func (m *UserMutation) SetOp(op Op) {
|
||||||
|
m.op = op
|
||||||
|
}
|
||||||
|
|
||||||
// Type returns the node type of this mutation (User).
|
// Type returns the node type of this mutation (User).
|
||||||
func (m *UserMutation) Type() string {
|
func (m *UserMutation) Type() string {
|
||||||
return m.typ
|
return m.typ
|
||||||
|
|
@ -757,7 +943,7 @@ func (m *UserMutation) Type() string {
|
||||||
// order to get all numeric fields that were incremented/decremented, call
|
// order to get all numeric fields that were incremented/decremented, call
|
||||||
// AddedFields().
|
// AddedFields().
|
||||||
func (m *UserMutation) Fields() []string {
|
func (m *UserMutation) Fields() []string {
|
||||||
fields := make([]string, 0, 4)
|
fields := make([]string, 0, 6)
|
||||||
if m.name != nil {
|
if m.name != nil {
|
||||||
fields = append(fields, user.FieldName)
|
fields = append(fields, user.FieldName)
|
||||||
}
|
}
|
||||||
|
|
@ -767,6 +953,12 @@ func (m *UserMutation) Fields() []string {
|
||||||
if m.password != nil {
|
if m.password != nil {
|
||||||
fields = append(fields, user.FieldPassword)
|
fields = append(fields, user.FieldPassword)
|
||||||
}
|
}
|
||||||
|
if m.verified != nil {
|
||||||
|
fields = append(fields, user.FieldVerified)
|
||||||
|
}
|
||||||
|
if m.admin != nil {
|
||||||
|
fields = append(fields, user.FieldAdmin)
|
||||||
|
}
|
||||||
if m.created_at != nil {
|
if m.created_at != nil {
|
||||||
fields = append(fields, user.FieldCreatedAt)
|
fields = append(fields, user.FieldCreatedAt)
|
||||||
}
|
}
|
||||||
|
|
@ -784,6 +976,10 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) {
|
||||||
return m.Email()
|
return m.Email()
|
||||||
case user.FieldPassword:
|
case user.FieldPassword:
|
||||||
return m.Password()
|
return m.Password()
|
||||||
|
case user.FieldVerified:
|
||||||
|
return m.Verified()
|
||||||
|
case user.FieldAdmin:
|
||||||
|
return m.Admin()
|
||||||
case user.FieldCreatedAt:
|
case user.FieldCreatedAt:
|
||||||
return m.CreatedAt()
|
return m.CreatedAt()
|
||||||
}
|
}
|
||||||
|
|
@ -801,6 +997,10 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er
|
||||||
return m.OldEmail(ctx)
|
return m.OldEmail(ctx)
|
||||||
case user.FieldPassword:
|
case user.FieldPassword:
|
||||||
return m.OldPassword(ctx)
|
return m.OldPassword(ctx)
|
||||||
|
case user.FieldVerified:
|
||||||
|
return m.OldVerified(ctx)
|
||||||
|
case user.FieldAdmin:
|
||||||
|
return m.OldAdmin(ctx)
|
||||||
case user.FieldCreatedAt:
|
case user.FieldCreatedAt:
|
||||||
return m.OldCreatedAt(ctx)
|
return m.OldCreatedAt(ctx)
|
||||||
}
|
}
|
||||||
|
|
@ -833,6 +1033,20 @@ func (m *UserMutation) SetField(name string, value ent.Value) error {
|
||||||
}
|
}
|
||||||
m.SetPassword(v)
|
m.SetPassword(v)
|
||||||
return nil
|
return nil
|
||||||
|
case user.FieldVerified:
|
||||||
|
v, ok := value.(bool)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||||
|
}
|
||||||
|
m.SetVerified(v)
|
||||||
|
return nil
|
||||||
|
case user.FieldAdmin:
|
||||||
|
v, ok := value.(bool)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||||
|
}
|
||||||
|
m.SetAdmin(v)
|
||||||
|
return nil
|
||||||
case user.FieldCreatedAt:
|
case user.FieldCreatedAt:
|
||||||
v, ok := value.(time.Time)
|
v, ok := value.(time.Time)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -898,6 +1112,12 @@ func (m *UserMutation) ResetField(name string) error {
|
||||||
case user.FieldPassword:
|
case user.FieldPassword:
|
||||||
m.ResetPassword()
|
m.ResetPassword()
|
||||||
return nil
|
return nil
|
||||||
|
case user.FieldVerified:
|
||||||
|
m.ResetVerified()
|
||||||
|
return nil
|
||||||
|
case user.FieldAdmin:
|
||||||
|
m.ResetAdmin()
|
||||||
|
return nil
|
||||||
case user.FieldCreatedAt:
|
case user.FieldCreatedAt:
|
||||||
m.ResetCreatedAt()
|
m.ResetCreatedAt()
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"goweb/ent/passwordtoken"
|
|
||||||
"goweb/ent/user"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"entgo.io/ent"
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/passwordtoken"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PasswordToken is the model entity for the PasswordToken schema.
|
// PasswordToken is the model entity for the PasswordToken schema.
|
||||||
|
|
@ -17,14 +18,16 @@ type PasswordToken struct {
|
||||||
config `json:"-"`
|
config `json:"-"`
|
||||||
// ID of the ent.
|
// ID of the ent.
|
||||||
ID int `json:"id,omitempty"`
|
ID int `json:"id,omitempty"`
|
||||||
// Hash holds the value of the "hash" field.
|
// Token holds the value of the "token" field.
|
||||||
Hash string `json:"-"`
|
Token string `json:"-"`
|
||||||
|
// UserID holds the value of the "user_id" field.
|
||||||
|
UserID int `json:"user_id,omitempty"`
|
||||||
// CreatedAt holds the value of the "created_at" field.
|
// CreatedAt holds the value of the "created_at" field.
|
||||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||||
// Edges holds the relations/edges for other nodes in the graph.
|
// Edges holds the relations/edges for other nodes in the graph.
|
||||||
// The values are being populated by the PasswordTokenQuery when eager-loading is set.
|
// The values are being populated by the PasswordTokenQuery when eager-loading is set.
|
||||||
Edges PasswordTokenEdges `json:"edges"`
|
Edges PasswordTokenEdges `json:"edges"`
|
||||||
password_token_user *int
|
selectValues sql.SelectValues
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordTokenEdges holds the relations/edges for other nodes in the graph.
|
// PasswordTokenEdges holds the relations/edges for other nodes in the graph.
|
||||||
|
|
@ -39,32 +42,27 @@ type PasswordTokenEdges struct {
|
||||||
// UserOrErr returns the User value or an error if the edge
|
// UserOrErr returns the User value or an error if the edge
|
||||||
// was not loaded in eager-loading, or loaded but was not found.
|
// was not loaded in eager-loading, or loaded but was not found.
|
||||||
func (e PasswordTokenEdges) UserOrErr() (*User, error) {
|
func (e PasswordTokenEdges) UserOrErr() (*User, error) {
|
||||||
if e.loadedTypes[0] {
|
if e.User != nil {
|
||||||
if e.User == nil {
|
|
||||||
// The edge user was loaded in eager-loading,
|
|
||||||
// but was not found.
|
|
||||||
return nil, &NotFoundError{label: user.Label}
|
|
||||||
}
|
|
||||||
return e.User, nil
|
return e.User, nil
|
||||||
|
} else if e.loadedTypes[0] {
|
||||||
|
return nil, &NotFoundError{label: user.Label}
|
||||||
}
|
}
|
||||||
return nil, &NotLoadedError{edge: "user"}
|
return nil, &NotLoadedError{edge: "user"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// scanValues returns the types for scanning values from sql.Rows.
|
// scanValues returns the types for scanning values from sql.Rows.
|
||||||
func (*PasswordToken) scanValues(columns []string) ([]interface{}, error) {
|
func (*PasswordToken) scanValues(columns []string) ([]any, error) {
|
||||||
values := make([]interface{}, len(columns))
|
values := make([]any, len(columns))
|
||||||
for i := range columns {
|
for i := range columns {
|
||||||
switch columns[i] {
|
switch columns[i] {
|
||||||
case passwordtoken.FieldID:
|
case passwordtoken.FieldID, passwordtoken.FieldUserID:
|
||||||
values[i] = new(sql.NullInt64)
|
values[i] = new(sql.NullInt64)
|
||||||
case passwordtoken.FieldHash:
|
case passwordtoken.FieldToken:
|
||||||
values[i] = new(sql.NullString)
|
values[i] = new(sql.NullString)
|
||||||
case passwordtoken.FieldCreatedAt:
|
case passwordtoken.FieldCreatedAt:
|
||||||
values[i] = new(sql.NullTime)
|
values[i] = new(sql.NullTime)
|
||||||
case passwordtoken.ForeignKeys[0]: // password_token_user
|
|
||||||
values[i] = new(sql.NullInt64)
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unexpected column %q for type PasswordToken", columns[i])
|
values[i] = new(sql.UnknownType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return values, nil
|
return values, nil
|
||||||
|
|
@ -72,7 +70,7 @@ func (*PasswordToken) scanValues(columns []string) ([]interface{}, error) {
|
||||||
|
|
||||||
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
||||||
// to the PasswordToken fields.
|
// to the PasswordToken fields.
|
||||||
func (pt *PasswordToken) assignValues(columns []string, values []interface{}) error {
|
func (_m *PasswordToken) assignValues(columns []string, values []any) error {
|
||||||
if m, n := len(values), len(columns); m < n {
|
if m, n := len(values), len(columns); m < n {
|
||||||
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
||||||
}
|
}
|
||||||
|
|
@ -83,71 +81,76 @@ func (pt *PasswordToken) assignValues(columns []string, values []interface{}) er
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unexpected type %T for field id", value)
|
return fmt.Errorf("unexpected type %T for field id", value)
|
||||||
}
|
}
|
||||||
pt.ID = int(value.Int64)
|
_m.ID = int(value.Int64)
|
||||||
case passwordtoken.FieldHash:
|
case passwordtoken.FieldToken:
|
||||||
if value, ok := values[i].(*sql.NullString); !ok {
|
if value, ok := values[i].(*sql.NullString); !ok {
|
||||||
return fmt.Errorf("unexpected type %T for field hash", values[i])
|
return fmt.Errorf("unexpected type %T for field token", values[i])
|
||||||
} else if value.Valid {
|
} else if value.Valid {
|
||||||
pt.Hash = value.String
|
_m.Token = value.String
|
||||||
|
}
|
||||||
|
case passwordtoken.FieldUserID:
|
||||||
|
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field user_id", values[i])
|
||||||
|
} else if value.Valid {
|
||||||
|
_m.UserID = int(value.Int64)
|
||||||
}
|
}
|
||||||
case passwordtoken.FieldCreatedAt:
|
case passwordtoken.FieldCreatedAt:
|
||||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||||
return fmt.Errorf("unexpected type %T for field created_at", values[i])
|
return fmt.Errorf("unexpected type %T for field created_at", values[i])
|
||||||
} else if value.Valid {
|
} else if value.Valid {
|
||||||
pt.CreatedAt = value.Time
|
_m.CreatedAt = value.Time
|
||||||
}
|
|
||||||
case passwordtoken.ForeignKeys[0]:
|
|
||||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
|
||||||
return fmt.Errorf("unexpected type %T for edge-field password_token_user", value)
|
|
||||||
} else if value.Valid {
|
|
||||||
pt.password_token_user = new(int)
|
|
||||||
*pt.password_token_user = int(value.Int64)
|
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
_m.selectValues.Set(columns[i], values[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Value returns the ent.Value that was dynamically selected and assigned to the PasswordToken.
|
||||||
|
// This includes values selected through modifiers, order, etc.
|
||||||
|
func (_m *PasswordToken) Value(name string) (ent.Value, error) {
|
||||||
|
return _m.selectValues.Get(name)
|
||||||
|
}
|
||||||
|
|
||||||
// QueryUser queries the "user" edge of the PasswordToken entity.
|
// QueryUser queries the "user" edge of the PasswordToken entity.
|
||||||
func (pt *PasswordToken) QueryUser() *UserQuery {
|
func (_m *PasswordToken) QueryUser() *UserQuery {
|
||||||
return (&PasswordTokenClient{config: pt.config}).QueryUser(pt)
|
return NewPasswordTokenClient(_m.config).QueryUser(_m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update returns a builder for updating this PasswordToken.
|
// Update returns a builder for updating this PasswordToken.
|
||||||
// Note that you need to call PasswordToken.Unwrap() before calling this method if this PasswordToken
|
// Note that you need to call PasswordToken.Unwrap() before calling this method if this PasswordToken
|
||||||
// was returned from a transaction, and the transaction was committed or rolled back.
|
// was returned from a transaction, and the transaction was committed or rolled back.
|
||||||
func (pt *PasswordToken) Update() *PasswordTokenUpdateOne {
|
func (_m *PasswordToken) Update() *PasswordTokenUpdateOne {
|
||||||
return (&PasswordTokenClient{config: pt.config}).UpdateOne(pt)
|
return NewPasswordTokenClient(_m.config).UpdateOne(_m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unwrap unwraps the PasswordToken entity that was returned from a transaction after it was closed,
|
// Unwrap unwraps the PasswordToken entity that was returned from a transaction after it was closed,
|
||||||
// so that all future queries will be executed through the driver which created the transaction.
|
// so that all future queries will be executed through the driver which created the transaction.
|
||||||
func (pt *PasswordToken) Unwrap() *PasswordToken {
|
func (_m *PasswordToken) Unwrap() *PasswordToken {
|
||||||
tx, ok := pt.config.driver.(*txDriver)
|
_tx, ok := _m.config.driver.(*txDriver)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("ent: PasswordToken is not a transactional entity")
|
panic("ent: PasswordToken is not a transactional entity")
|
||||||
}
|
}
|
||||||
pt.config.driver = tx.drv
|
_m.config.driver = _tx.drv
|
||||||
return pt
|
return _m
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements the fmt.Stringer.
|
// String implements the fmt.Stringer.
|
||||||
func (pt *PasswordToken) String() string {
|
func (_m *PasswordToken) String() string {
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
builder.WriteString("PasswordToken(")
|
builder.WriteString("PasswordToken(")
|
||||||
builder.WriteString(fmt.Sprintf("id=%v", pt.ID))
|
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
|
||||||
builder.WriteString(", hash=<sensitive>")
|
builder.WriteString("token=<sensitive>")
|
||||||
builder.WriteString(", created_at=")
|
builder.WriteString(", ")
|
||||||
builder.WriteString(pt.CreatedAt.Format(time.ANSIC))
|
builder.WriteString("user_id=")
|
||||||
|
builder.WriteString(fmt.Sprintf("%v", _m.UserID))
|
||||||
|
builder.WriteString(", ")
|
||||||
|
builder.WriteString("created_at=")
|
||||||
|
builder.WriteString(_m.CreatedAt.Format(time.ANSIC))
|
||||||
builder.WriteByte(')')
|
builder.WriteByte(')')
|
||||||
return builder.String()
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordTokens is a parsable slice of PasswordToken.
|
// PasswordTokens is a parsable slice of PasswordToken.
|
||||||
type PasswordTokens []*PasswordToken
|
type PasswordTokens []*PasswordToken
|
||||||
|
|
||||||
func (pt PasswordTokens) config(cfg config) {
|
|
||||||
for _i := range pt {
|
|
||||||
pt[_i].config = cfg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package passwordtoken
|
package passwordtoken
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"entgo.io/ent"
|
||||||
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -11,8 +15,10 @@ const (
|
||||||
Label = "password_token"
|
Label = "password_token"
|
||||||
// FieldID holds the string denoting the id field in the database.
|
// FieldID holds the string denoting the id field in the database.
|
||||||
FieldID = "id"
|
FieldID = "id"
|
||||||
// FieldHash holds the string denoting the hash field in the database.
|
// FieldToken holds the string denoting the token field in the database.
|
||||||
FieldHash = "hash"
|
FieldToken = "token"
|
||||||
|
// FieldUserID holds the string denoting the user_id field in the database.
|
||||||
|
FieldUserID = "user_id"
|
||||||
// FieldCreatedAt holds the string denoting the created_at field in the database.
|
// FieldCreatedAt holds the string denoting the created_at field in the database.
|
||||||
FieldCreatedAt = "created_at"
|
FieldCreatedAt = "created_at"
|
||||||
// EdgeUser holds the string denoting the user edge name in mutations.
|
// EdgeUser holds the string denoting the user edge name in mutations.
|
||||||
|
|
@ -25,22 +31,17 @@ const (
|
||||||
// It exists in this package in order to avoid circular dependency with the "user" package.
|
// It exists in this package in order to avoid circular dependency with the "user" package.
|
||||||
UserInverseTable = "users"
|
UserInverseTable = "users"
|
||||||
// UserColumn is the table column denoting the user relation/edge.
|
// UserColumn is the table column denoting the user relation/edge.
|
||||||
UserColumn = "password_token_user"
|
UserColumn = "user_id"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Columns holds all SQL columns for passwordtoken fields.
|
// Columns holds all SQL columns for passwordtoken fields.
|
||||||
var Columns = []string{
|
var Columns = []string{
|
||||||
FieldID,
|
FieldID,
|
||||||
FieldHash,
|
FieldToken,
|
||||||
|
FieldUserID,
|
||||||
FieldCreatedAt,
|
FieldCreatedAt,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForeignKeys holds the SQL foreign-keys that are owned by the "password_tokens"
|
|
||||||
// table and are not defined as standalone fields in the schema.
|
|
||||||
var ForeignKeys = []string{
|
|
||||||
"password_token_user",
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidColumn reports if the column name is valid (part of the table columns).
|
// ValidColumn reports if the column name is valid (part of the table columns).
|
||||||
func ValidColumn(column string) bool {
|
func ValidColumn(column string) bool {
|
||||||
for i := range Columns {
|
for i := range Columns {
|
||||||
|
|
@ -48,17 +49,55 @@ func ValidColumn(column string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := range ForeignKeys {
|
|
||||||
if column == ForeignKeys[i] {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note that the variables below are initialized by the runtime
|
||||||
|
// package on the initialization of the application. Therefore,
|
||||||
|
// it should be imported in the main as follows:
|
||||||
|
//
|
||||||
|
// import _ "github.com/mikestefanello/pagoda/ent/runtime"
|
||||||
var (
|
var (
|
||||||
// HashValidator is a validator for the "hash" field. It is called by the builders before save.
|
Hooks [1]ent.Hook
|
||||||
HashValidator func(string) error
|
// TokenValidator is a validator for the "token" field. It is called by the builders before save.
|
||||||
|
TokenValidator func(string) error
|
||||||
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
|
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
|
||||||
DefaultCreatedAt func() time.Time
|
DefaultCreatedAt func() time.Time
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// OrderOption defines the ordering options for the PasswordToken queries.
|
||||||
|
type OrderOption func(*sql.Selector)
|
||||||
|
|
||||||
|
// ByID orders the results by the id field.
|
||||||
|
func ByID(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldID, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByToken orders the results by the token field.
|
||||||
|
func ByToken(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldToken, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByUserID orders the results by the user_id field.
|
||||||
|
func ByUserID(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldUserID, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByCreatedAt orders the results by the created_at field.
|
||||||
|
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByUserField orders the results by user field.
|
||||||
|
func ByUserField(field string, opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return func(s *sql.Selector) {
|
||||||
|
sqlgraph.OrderByNeighborTerms(s, newUserStep(), sql.OrderByField(field, opts...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func newUserStep() *sqlgraph.Step {
|
||||||
|
return sqlgraph.NewStep(
|
||||||
|
sqlgraph.From(Table, FieldID),
|
||||||
|
sqlgraph.To(UserInverseTable, FieldID),
|
||||||
|
sqlgraph.Edge(sqlgraph.M2O, false, UserTable, UserColumn),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,297 +1,198 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package passwordtoken
|
package passwordtoken
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"goweb/ent/predicate"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/predicate"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ID filters vertices based on their ID field.
|
// ID filters vertices based on their ID field.
|
||||||
func ID(id int) predicate.PasswordToken {
|
func ID(id int) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldEQ(FieldID, id))
|
||||||
s.Where(sql.EQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDEQ applies the EQ predicate on the ID field.
|
// IDEQ applies the EQ predicate on the ID field.
|
||||||
func IDEQ(id int) predicate.PasswordToken {
|
func IDEQ(id int) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldEQ(FieldID, id))
|
||||||
s.Where(sql.EQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDNEQ applies the NEQ predicate on the ID field.
|
// IDNEQ applies the NEQ predicate on the ID field.
|
||||||
func IDNEQ(id int) predicate.PasswordToken {
|
func IDNEQ(id int) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldNEQ(FieldID, id))
|
||||||
s.Where(sql.NEQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDIn applies the In predicate on the ID field.
|
// IDIn applies the In predicate on the ID field.
|
||||||
func IDIn(ids ...int) predicate.PasswordToken {
|
func IDIn(ids ...int) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldIn(FieldID, ids...))
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(ids) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v := make([]interface{}, len(ids))
|
|
||||||
for i := range v {
|
|
||||||
v[i] = ids[i]
|
|
||||||
}
|
|
||||||
s.Where(sql.In(s.C(FieldID), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDNotIn applies the NotIn predicate on the ID field.
|
// IDNotIn applies the NotIn predicate on the ID field.
|
||||||
func IDNotIn(ids ...int) predicate.PasswordToken {
|
func IDNotIn(ids ...int) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldNotIn(FieldID, ids...))
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(ids) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v := make([]interface{}, len(ids))
|
|
||||||
for i := range v {
|
|
||||||
v[i] = ids[i]
|
|
||||||
}
|
|
||||||
s.Where(sql.NotIn(s.C(FieldID), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDGT applies the GT predicate on the ID field.
|
// IDGT applies the GT predicate on the ID field.
|
||||||
func IDGT(id int) predicate.PasswordToken {
|
func IDGT(id int) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldGT(FieldID, id))
|
||||||
s.Where(sql.GT(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDGTE applies the GTE predicate on the ID field.
|
// IDGTE applies the GTE predicate on the ID field.
|
||||||
func IDGTE(id int) predicate.PasswordToken {
|
func IDGTE(id int) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldGTE(FieldID, id))
|
||||||
s.Where(sql.GTE(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDLT applies the LT predicate on the ID field.
|
// IDLT applies the LT predicate on the ID field.
|
||||||
func IDLT(id int) predicate.PasswordToken {
|
func IDLT(id int) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldLT(FieldID, id))
|
||||||
s.Where(sql.LT(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDLTE applies the LTE predicate on the ID field.
|
// IDLTE applies the LTE predicate on the ID field.
|
||||||
func IDLTE(id int) predicate.PasswordToken {
|
func IDLTE(id int) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldLTE(FieldID, id))
|
||||||
s.Where(sql.LTE(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash applies equality check predicate on the "hash" field. It's identical to HashEQ.
|
// Token applies equality check predicate on the "token" field. It's identical to TokenEQ.
|
||||||
func Hash(v string) predicate.PasswordToken {
|
func Token(v string) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldEQ(FieldToken, v))
|
||||||
s.Where(sql.EQ(s.C(FieldHash), v))
|
}
|
||||||
})
|
|
||||||
|
// UserID applies equality check predicate on the "user_id" field. It's identical to UserIDEQ.
|
||||||
|
func UserID(v int) predicate.PasswordToken {
|
||||||
|
return predicate.PasswordToken(sql.FieldEQ(FieldUserID, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
||||||
func CreatedAt(v time.Time) predicate.PasswordToken {
|
func CreatedAt(v time.Time) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashEQ applies the EQ predicate on the "hash" field.
|
// TokenEQ applies the EQ predicate on the "token" field.
|
||||||
func HashEQ(v string) predicate.PasswordToken {
|
func TokenEQ(v string) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldEQ(FieldToken, v))
|
||||||
s.Where(sql.EQ(s.C(FieldHash), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashNEQ applies the NEQ predicate on the "hash" field.
|
// TokenNEQ applies the NEQ predicate on the "token" field.
|
||||||
func HashNEQ(v string) predicate.PasswordToken {
|
func TokenNEQ(v string) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldNEQ(FieldToken, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldHash), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashIn applies the In predicate on the "hash" field.
|
// TokenIn applies the In predicate on the "token" field.
|
||||||
func HashIn(vs ...string) predicate.PasswordToken {
|
func TokenIn(vs ...string) predicate.PasswordToken {
|
||||||
v := make([]interface{}, len(vs))
|
return predicate.PasswordToken(sql.FieldIn(FieldToken, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(v) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Where(sql.In(s.C(FieldHash), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashNotIn applies the NotIn predicate on the "hash" field.
|
// TokenNotIn applies the NotIn predicate on the "token" field.
|
||||||
func HashNotIn(vs ...string) predicate.PasswordToken {
|
func TokenNotIn(vs ...string) predicate.PasswordToken {
|
||||||
v := make([]interface{}, len(vs))
|
return predicate.PasswordToken(sql.FieldNotIn(FieldToken, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(v) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Where(sql.NotIn(s.C(FieldHash), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashGT applies the GT predicate on the "hash" field.
|
// TokenGT applies the GT predicate on the "token" field.
|
||||||
func HashGT(v string) predicate.PasswordToken {
|
func TokenGT(v string) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldGT(FieldToken, v))
|
||||||
s.Where(sql.GT(s.C(FieldHash), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashGTE applies the GTE predicate on the "hash" field.
|
// TokenGTE applies the GTE predicate on the "token" field.
|
||||||
func HashGTE(v string) predicate.PasswordToken {
|
func TokenGTE(v string) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldGTE(FieldToken, v))
|
||||||
s.Where(sql.GTE(s.C(FieldHash), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashLT applies the LT predicate on the "hash" field.
|
// TokenLT applies the LT predicate on the "token" field.
|
||||||
func HashLT(v string) predicate.PasswordToken {
|
func TokenLT(v string) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldLT(FieldToken, v))
|
||||||
s.Where(sql.LT(s.C(FieldHash), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashLTE applies the LTE predicate on the "hash" field.
|
// TokenLTE applies the LTE predicate on the "token" field.
|
||||||
func HashLTE(v string) predicate.PasswordToken {
|
func TokenLTE(v string) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldLTE(FieldToken, v))
|
||||||
s.Where(sql.LTE(s.C(FieldHash), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashContains applies the Contains predicate on the "hash" field.
|
// TokenContains applies the Contains predicate on the "token" field.
|
||||||
func HashContains(v string) predicate.PasswordToken {
|
func TokenContains(v string) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldContains(FieldToken, v))
|
||||||
s.Where(sql.Contains(s.C(FieldHash), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashHasPrefix applies the HasPrefix predicate on the "hash" field.
|
// TokenHasPrefix applies the HasPrefix predicate on the "token" field.
|
||||||
func HashHasPrefix(v string) predicate.PasswordToken {
|
func TokenHasPrefix(v string) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldHasPrefix(FieldToken, v))
|
||||||
s.Where(sql.HasPrefix(s.C(FieldHash), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashHasSuffix applies the HasSuffix predicate on the "hash" field.
|
// TokenHasSuffix applies the HasSuffix predicate on the "token" field.
|
||||||
func HashHasSuffix(v string) predicate.PasswordToken {
|
func TokenHasSuffix(v string) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldHasSuffix(FieldToken, v))
|
||||||
s.Where(sql.HasSuffix(s.C(FieldHash), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashEqualFold applies the EqualFold predicate on the "hash" field.
|
// TokenEqualFold applies the EqualFold predicate on the "token" field.
|
||||||
func HashEqualFold(v string) predicate.PasswordToken {
|
func TokenEqualFold(v string) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldEqualFold(FieldToken, v))
|
||||||
s.Where(sql.EqualFold(s.C(FieldHash), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashContainsFold applies the ContainsFold predicate on the "hash" field.
|
// TokenContainsFold applies the ContainsFold predicate on the "token" field.
|
||||||
func HashContainsFold(v string) predicate.PasswordToken {
|
func TokenContainsFold(v string) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldContainsFold(FieldToken, v))
|
||||||
s.Where(sql.ContainsFold(s.C(FieldHash), v))
|
}
|
||||||
})
|
|
||||||
|
// UserIDEQ applies the EQ predicate on the "user_id" field.
|
||||||
|
func UserIDEQ(v int) predicate.PasswordToken {
|
||||||
|
return predicate.PasswordToken(sql.FieldEQ(FieldUserID, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserIDNEQ applies the NEQ predicate on the "user_id" field.
|
||||||
|
func UserIDNEQ(v int) predicate.PasswordToken {
|
||||||
|
return predicate.PasswordToken(sql.FieldNEQ(FieldUserID, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserIDIn applies the In predicate on the "user_id" field.
|
||||||
|
func UserIDIn(vs ...int) predicate.PasswordToken {
|
||||||
|
return predicate.PasswordToken(sql.FieldIn(FieldUserID, vs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserIDNotIn applies the NotIn predicate on the "user_id" field.
|
||||||
|
func UserIDNotIn(vs ...int) predicate.PasswordToken {
|
||||||
|
return predicate.PasswordToken(sql.FieldNotIn(FieldUserID, vs...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||||
func CreatedAtEQ(v time.Time) predicate.PasswordToken {
|
func CreatedAtEQ(v time.Time) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
||||||
func CreatedAtNEQ(v time.Time) predicate.PasswordToken {
|
func CreatedAtNEQ(v time.Time) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldNEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtIn applies the In predicate on the "created_at" field.
|
// CreatedAtIn applies the In predicate on the "created_at" field.
|
||||||
func CreatedAtIn(vs ...time.Time) predicate.PasswordToken {
|
func CreatedAtIn(vs ...time.Time) predicate.PasswordToken {
|
||||||
v := make([]interface{}, len(vs))
|
return predicate.PasswordToken(sql.FieldIn(FieldCreatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(v) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Where(sql.In(s.C(FieldCreatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
||||||
func CreatedAtNotIn(vs ...time.Time) predicate.PasswordToken {
|
func CreatedAtNotIn(vs ...time.Time) predicate.PasswordToken {
|
||||||
v := make([]interface{}, len(vs))
|
return predicate.PasswordToken(sql.FieldNotIn(FieldCreatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(v) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Where(sql.NotIn(s.C(FieldCreatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
||||||
func CreatedAtGT(v time.Time) predicate.PasswordToken {
|
func CreatedAtGT(v time.Time) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldGT(FieldCreatedAt, v))
|
||||||
s.Where(sql.GT(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
||||||
func CreatedAtGTE(v time.Time) predicate.PasswordToken {
|
func CreatedAtGTE(v time.Time) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldGTE(FieldCreatedAt, v))
|
||||||
s.Where(sql.GTE(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
||||||
func CreatedAtLT(v time.Time) predicate.PasswordToken {
|
func CreatedAtLT(v time.Time) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldLT(FieldCreatedAt, v))
|
||||||
s.Where(sql.LT(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
||||||
func CreatedAtLTE(v time.Time) predicate.PasswordToken {
|
func CreatedAtLTE(v time.Time) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.FieldLTE(FieldCreatedAt, v))
|
||||||
s.Where(sql.LTE(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasUser applies the HasEdge predicate on the "user" edge.
|
// HasUser applies the HasEdge predicate on the "user" edge.
|
||||||
|
|
@ -299,7 +200,6 @@ func HasUser() predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(Table, FieldID),
|
sqlgraph.From(Table, FieldID),
|
||||||
sqlgraph.To(UserTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.M2O, false, UserTable, UserColumn),
|
sqlgraph.Edge(sqlgraph.M2O, false, UserTable, UserColumn),
|
||||||
)
|
)
|
||||||
sqlgraph.HasNeighbors(s, step)
|
sqlgraph.HasNeighbors(s, step)
|
||||||
|
|
@ -309,11 +209,7 @@ func HasUser() predicate.PasswordToken {
|
||||||
// HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates).
|
// HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates).
|
||||||
func HasUserWith(preds ...predicate.User) predicate.PasswordToken {
|
func HasUserWith(preds ...predicate.User) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := newUserStep()
|
||||||
sqlgraph.From(Table, FieldID),
|
|
||||||
sqlgraph.To(UserInverseTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.M2O, false, UserTable, UserColumn),
|
|
||||||
)
|
|
||||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||||
for _, p := range preds {
|
for _, p := range preds {
|
||||||
p(s)
|
p(s)
|
||||||
|
|
@ -324,32 +220,15 @@ func HasUserWith(preds ...predicate.User) predicate.PasswordToken {
|
||||||
|
|
||||||
// And groups predicates with the AND operator between them.
|
// And groups predicates with the AND operator between them.
|
||||||
func And(predicates ...predicate.PasswordToken) predicate.PasswordToken {
|
func And(predicates ...predicate.PasswordToken) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.AndPredicates(predicates...))
|
||||||
s1 := s.Clone().SetP(nil)
|
|
||||||
for _, p := range predicates {
|
|
||||||
p(s1)
|
|
||||||
}
|
|
||||||
s.Where(s1.P())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Or groups predicates with the OR operator between them.
|
// Or groups predicates with the OR operator between them.
|
||||||
func Or(predicates ...predicate.PasswordToken) predicate.PasswordToken {
|
func Or(predicates ...predicate.PasswordToken) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.OrPredicates(predicates...))
|
||||||
s1 := s.Clone().SetP(nil)
|
|
||||||
for i, p := range predicates {
|
|
||||||
if i > 0 {
|
|
||||||
s1.Or()
|
|
||||||
}
|
|
||||||
p(s1)
|
|
||||||
}
|
|
||||||
s.Where(s1.P())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not applies the not operator on the given predicate.
|
// Not applies the not operator on the given predicate.
|
||||||
func Not(p predicate.PasswordToken) predicate.PasswordToken {
|
func Not(p predicate.PasswordToken) predicate.PasswordToken {
|
||||||
return predicate.PasswordToken(func(s *sql.Selector) {
|
return predicate.PasswordToken(sql.NotPredicates(p))
|
||||||
p(s.Not())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
|
|
@ -6,12 +6,12 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"goweb/ent/passwordtoken"
|
|
||||||
"goweb/ent/user"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
"entgo.io/ent/schema/field"
|
"entgo.io/ent/schema/field"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/passwordtoken"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PasswordTokenCreate is the builder for creating a PasswordToken entity.
|
// PasswordTokenCreate is the builder for creating a PasswordToken entity.
|
||||||
|
|
@ -21,87 +21,53 @@ type PasswordTokenCreate struct {
|
||||||
hooks []Hook
|
hooks []Hook
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHash sets the "hash" field.
|
// SetToken sets the "token" field.
|
||||||
func (ptc *PasswordTokenCreate) SetHash(s string) *PasswordTokenCreate {
|
func (_c *PasswordTokenCreate) SetToken(v string) *PasswordTokenCreate {
|
||||||
ptc.mutation.SetHash(s)
|
_c.mutation.SetToken(v)
|
||||||
return ptc
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUserID sets the "user_id" field.
|
||||||
|
func (_c *PasswordTokenCreate) SetUserID(v int) *PasswordTokenCreate {
|
||||||
|
_c.mutation.SetUserID(v)
|
||||||
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCreatedAt sets the "created_at" field.
|
// SetCreatedAt sets the "created_at" field.
|
||||||
func (ptc *PasswordTokenCreate) SetCreatedAt(t time.Time) *PasswordTokenCreate {
|
func (_c *PasswordTokenCreate) SetCreatedAt(v time.Time) *PasswordTokenCreate {
|
||||||
ptc.mutation.SetCreatedAt(t)
|
_c.mutation.SetCreatedAt(v)
|
||||||
return ptc
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
|
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
|
||||||
func (ptc *PasswordTokenCreate) SetNillableCreatedAt(t *time.Time) *PasswordTokenCreate {
|
func (_c *PasswordTokenCreate) SetNillableCreatedAt(v *time.Time) *PasswordTokenCreate {
|
||||||
if t != nil {
|
if v != nil {
|
||||||
ptc.SetCreatedAt(*t)
|
_c.SetCreatedAt(*v)
|
||||||
}
|
}
|
||||||
return ptc
|
return _c
|
||||||
}
|
|
||||||
|
|
||||||
// SetUserID sets the "user" edge to the User entity by ID.
|
|
||||||
func (ptc *PasswordTokenCreate) SetUserID(id int) *PasswordTokenCreate {
|
|
||||||
ptc.mutation.SetUserID(id)
|
|
||||||
return ptc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUser sets the "user" edge to the User entity.
|
// SetUser sets the "user" edge to the User entity.
|
||||||
func (ptc *PasswordTokenCreate) SetUser(u *User) *PasswordTokenCreate {
|
func (_c *PasswordTokenCreate) SetUser(v *User) *PasswordTokenCreate {
|
||||||
return ptc.SetUserID(u.ID)
|
return _c.SetUserID(v.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutation returns the PasswordTokenMutation object of the builder.
|
// Mutation returns the PasswordTokenMutation object of the builder.
|
||||||
func (ptc *PasswordTokenCreate) Mutation() *PasswordTokenMutation {
|
func (_c *PasswordTokenCreate) Mutation() *PasswordTokenMutation {
|
||||||
return ptc.mutation
|
return _c.mutation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save creates the PasswordToken in the database.
|
// Save creates the PasswordToken in the database.
|
||||||
func (ptc *PasswordTokenCreate) Save(ctx context.Context) (*PasswordToken, error) {
|
func (_c *PasswordTokenCreate) Save(ctx context.Context) (*PasswordToken, error) {
|
||||||
var (
|
if err := _c.defaults(); err != nil {
|
||||||
err error
|
return nil, err
|
||||||
node *PasswordToken
|
|
||||||
)
|
|
||||||
ptc.defaults()
|
|
||||||
if len(ptc.hooks) == 0 {
|
|
||||||
if err = ptc.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
node, err = ptc.sqlSave(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*PasswordTokenMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
if err = ptc.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ptc.mutation = mutation
|
|
||||||
if node, err = ptc.sqlSave(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mutation.id = &node.ID
|
|
||||||
mutation.done = true
|
|
||||||
return node, err
|
|
||||||
})
|
|
||||||
for i := len(ptc.hooks) - 1; i >= 0; i-- {
|
|
||||||
if ptc.hooks[i] == nil {
|
|
||||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = ptc.hooks[i](mut)
|
|
||||||
}
|
|
||||||
if _, err := mut.Mutate(ctx, ptc.mutation); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return node, err
|
return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX calls Save and panics if Save returns an error.
|
// SaveX calls Save and panics if Save returns an error.
|
||||||
func (ptc *PasswordTokenCreate) SaveX(ctx context.Context) *PasswordToken {
|
func (_c *PasswordTokenCreate) SaveX(ctx context.Context) *PasswordToken {
|
||||||
v, err := ptc.Save(ctx)
|
v, err := _c.Save(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -109,86 +75,84 @@ func (ptc *PasswordTokenCreate) SaveX(ctx context.Context) *PasswordToken {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the query.
|
// Exec executes the query.
|
||||||
func (ptc *PasswordTokenCreate) Exec(ctx context.Context) error {
|
func (_c *PasswordTokenCreate) Exec(ctx context.Context) error {
|
||||||
_, err := ptc.Save(ctx)
|
_, err := _c.Save(ctx)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (ptc *PasswordTokenCreate) ExecX(ctx context.Context) {
|
func (_c *PasswordTokenCreate) ExecX(ctx context.Context) {
|
||||||
if err := ptc.Exec(ctx); err != nil {
|
if err := _c.Exec(ctx); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaults sets the default values of the builder before save.
|
// defaults sets the default values of the builder before save.
|
||||||
func (ptc *PasswordTokenCreate) defaults() {
|
func (_c *PasswordTokenCreate) defaults() error {
|
||||||
if _, ok := ptc.mutation.CreatedAt(); !ok {
|
if _, ok := _c.mutation.CreatedAt(); !ok {
|
||||||
v := passwordtoken.DefaultCreatedAt()
|
if passwordtoken.DefaultCreatedAt == nil {
|
||||||
ptc.mutation.SetCreatedAt(v)
|
return fmt.Errorf("ent: uninitialized passwordtoken.DefaultCreatedAt (forgotten import ent/runtime?)")
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check runs all checks and user-defined validators on the builder.
|
|
||||||
func (ptc *PasswordTokenCreate) check() error {
|
|
||||||
if _, ok := ptc.mutation.Hash(); !ok {
|
|
||||||
return &ValidationError{Name: "hash", err: errors.New(`ent: missing required field "hash"`)}
|
|
||||||
}
|
|
||||||
if v, ok := ptc.mutation.Hash(); ok {
|
|
||||||
if err := passwordtoken.HashValidator(v); err != nil {
|
|
||||||
return &ValidationError{Name: "hash", err: fmt.Errorf(`ent: validator failed for field "hash": %w`, err)}
|
|
||||||
}
|
}
|
||||||
}
|
v := passwordtoken.DefaultCreatedAt()
|
||||||
if _, ok := ptc.mutation.CreatedAt(); !ok {
|
_c.mutation.SetCreatedAt(v)
|
||||||
return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "created_at"`)}
|
|
||||||
}
|
|
||||||
if _, ok := ptc.mutation.UserID(); !ok {
|
|
||||||
return &ValidationError{Name: "user", err: errors.New("ent: missing required edge \"user\"")}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ptc *PasswordTokenCreate) sqlSave(ctx context.Context) (*PasswordToken, error) {
|
// check runs all checks and user-defined validators on the builder.
|
||||||
_node, _spec := ptc.createSpec()
|
func (_c *PasswordTokenCreate) check() error {
|
||||||
if err := sqlgraph.CreateNode(ctx, ptc.driver, _spec); err != nil {
|
if _, ok := _c.mutation.Token(); !ok {
|
||||||
|
return &ValidationError{Name: "token", err: errors.New(`ent: missing required field "PasswordToken.token"`)}
|
||||||
|
}
|
||||||
|
if v, ok := _c.mutation.Token(); ok {
|
||||||
|
if err := passwordtoken.TokenValidator(v); err != nil {
|
||||||
|
return &ValidationError{Name: "token", err: fmt.Errorf(`ent: validator failed for field "PasswordToken.token": %w`, err)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, ok := _c.mutation.UserID(); !ok {
|
||||||
|
return &ValidationError{Name: "user_id", err: errors.New(`ent: missing required field "PasswordToken.user_id"`)}
|
||||||
|
}
|
||||||
|
if _, ok := _c.mutation.CreatedAt(); !ok {
|
||||||
|
return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "PasswordToken.created_at"`)}
|
||||||
|
}
|
||||||
|
if len(_c.mutation.UserIDs()) == 0 {
|
||||||
|
return &ValidationError{Name: "user", err: errors.New(`ent: missing required edge "PasswordToken.user"`)}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_c *PasswordTokenCreate) sqlSave(ctx context.Context) (*PasswordToken, error) {
|
||||||
|
if err := _c.check(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_node, _spec := _c.createSpec()
|
||||||
|
if err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil {
|
||||||
if sqlgraph.IsConstraintError(err) {
|
if sqlgraph.IsConstraintError(err) {
|
||||||
err = &ConstraintError{err.Error(), err}
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
id := _spec.ID.Value.(int64)
|
id := _spec.ID.Value.(int64)
|
||||||
_node.ID = int(id)
|
_node.ID = int(id)
|
||||||
|
_c.mutation.id = &_node.ID
|
||||||
|
_c.mutation.done = true
|
||||||
return _node, nil
|
return _node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ptc *PasswordTokenCreate) createSpec() (*PasswordToken, *sqlgraph.CreateSpec) {
|
func (_c *PasswordTokenCreate) createSpec() (*PasswordToken, *sqlgraph.CreateSpec) {
|
||||||
var (
|
var (
|
||||||
_node = &PasswordToken{config: ptc.config}
|
_node = &PasswordToken{config: _c.config}
|
||||||
_spec = &sqlgraph.CreateSpec{
|
_spec = sqlgraph.NewCreateSpec(passwordtoken.Table, sqlgraph.NewFieldSpec(passwordtoken.FieldID, field.TypeInt))
|
||||||
Table: passwordtoken.Table,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: passwordtoken.FieldID,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
if value, ok := ptc.mutation.Hash(); ok {
|
if value, ok := _c.mutation.Token(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(passwordtoken.FieldToken, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
_node.Token = value
|
||||||
Value: value,
|
|
||||||
Column: passwordtoken.FieldHash,
|
|
||||||
})
|
|
||||||
_node.Hash = value
|
|
||||||
}
|
}
|
||||||
if value, ok := ptc.mutation.CreatedAt(); ok {
|
if value, ok := _c.mutation.CreatedAt(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(passwordtoken.FieldCreatedAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: passwordtoken.FieldCreatedAt,
|
|
||||||
})
|
|
||||||
_node.CreatedAt = value
|
_node.CreatedAt = value
|
||||||
}
|
}
|
||||||
if nodes := ptc.mutation.UserIDs(); len(nodes) > 0 {
|
if nodes := _c.mutation.UserIDs(); len(nodes) > 0 {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.M2O,
|
Rel: sqlgraph.M2O,
|
||||||
Inverse: false,
|
Inverse: false,
|
||||||
|
|
@ -196,16 +160,13 @@ func (ptc *PasswordTokenCreate) createSpec() (*PasswordToken, *sqlgraph.CreateSp
|
||||||
Columns: []string{passwordtoken.UserColumn},
|
Columns: []string{passwordtoken.UserColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt),
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: user.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
edge.Target.Nodes = append(edge.Target.Nodes, k)
|
||||||
}
|
}
|
||||||
_node.password_token_user = &nodes[0]
|
_node.UserID = nodes[0]
|
||||||
_spec.Edges = append(_spec.Edges, edge)
|
_spec.Edges = append(_spec.Edges, edge)
|
||||||
}
|
}
|
||||||
return _node, _spec
|
return _node, _spec
|
||||||
|
|
@ -214,17 +175,21 @@ func (ptc *PasswordTokenCreate) createSpec() (*PasswordToken, *sqlgraph.CreateSp
|
||||||
// PasswordTokenCreateBulk is the builder for creating many PasswordToken entities in bulk.
|
// PasswordTokenCreateBulk is the builder for creating many PasswordToken entities in bulk.
|
||||||
type PasswordTokenCreateBulk struct {
|
type PasswordTokenCreateBulk struct {
|
||||||
config
|
config
|
||||||
|
err error
|
||||||
builders []*PasswordTokenCreate
|
builders []*PasswordTokenCreate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save creates the PasswordToken entities in the database.
|
// Save creates the PasswordToken entities in the database.
|
||||||
func (ptcb *PasswordTokenCreateBulk) Save(ctx context.Context) ([]*PasswordToken, error) {
|
func (_c *PasswordTokenCreateBulk) Save(ctx context.Context) ([]*PasswordToken, error) {
|
||||||
specs := make([]*sqlgraph.CreateSpec, len(ptcb.builders))
|
if _c.err != nil {
|
||||||
nodes := make([]*PasswordToken, len(ptcb.builders))
|
return nil, _c.err
|
||||||
mutators := make([]Mutator, len(ptcb.builders))
|
}
|
||||||
for i := range ptcb.builders {
|
specs := make([]*sqlgraph.CreateSpec, len(_c.builders))
|
||||||
|
nodes := make([]*PasswordToken, len(_c.builders))
|
||||||
|
mutators := make([]Mutator, len(_c.builders))
|
||||||
|
for i := range _c.builders {
|
||||||
func(i int, root context.Context) {
|
func(i int, root context.Context) {
|
||||||
builder := ptcb.builders[i]
|
builder := _c.builders[i]
|
||||||
builder.defaults()
|
builder.defaults()
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||||
mutation, ok := m.(*PasswordTokenMutation)
|
mutation, ok := m.(*PasswordTokenMutation)
|
||||||
|
|
@ -235,16 +200,16 @@ func (ptcb *PasswordTokenCreateBulk) Save(ctx context.Context) ([]*PasswordToken
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
builder.mutation = mutation
|
builder.mutation = mutation
|
||||||
nodes[i], specs[i] = builder.createSpec()
|
|
||||||
var err error
|
var err error
|
||||||
|
nodes[i], specs[i] = builder.createSpec()
|
||||||
if i < len(mutators)-1 {
|
if i < len(mutators)-1 {
|
||||||
_, err = mutators[i+1].Mutate(root, ptcb.builders[i+1].mutation)
|
_, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation)
|
||||||
} else {
|
} else {
|
||||||
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
|
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
|
||||||
// Invoke the actual operation on the latest mutation in the chain.
|
// Invoke the actual operation on the latest mutation in the chain.
|
||||||
if err = sqlgraph.BatchCreate(ctx, ptcb.driver, spec); err != nil {
|
if err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil {
|
||||||
if sqlgraph.IsConstraintError(err) {
|
if sqlgraph.IsConstraintError(err) {
|
||||||
err = &ConstraintError{err.Error(), err}
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -252,11 +217,11 @@ func (ptcb *PasswordTokenCreateBulk) Save(ctx context.Context) ([]*PasswordToken
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
mutation.id = &nodes[i].ID
|
mutation.id = &nodes[i].ID
|
||||||
mutation.done = true
|
|
||||||
if specs[i].ID.Value != nil {
|
if specs[i].ID.Value != nil {
|
||||||
id := specs[i].ID.Value.(int64)
|
id := specs[i].ID.Value.(int64)
|
||||||
nodes[i].ID = int(id)
|
nodes[i].ID = int(id)
|
||||||
}
|
}
|
||||||
|
mutation.done = true
|
||||||
return nodes[i], nil
|
return nodes[i], nil
|
||||||
})
|
})
|
||||||
for i := len(builder.hooks) - 1; i >= 0; i-- {
|
for i := len(builder.hooks) - 1; i >= 0; i-- {
|
||||||
|
|
@ -266,7 +231,7 @@ func (ptcb *PasswordTokenCreateBulk) Save(ctx context.Context) ([]*PasswordToken
|
||||||
}(i, ctx)
|
}(i, ctx)
|
||||||
}
|
}
|
||||||
if len(mutators) > 0 {
|
if len(mutators) > 0 {
|
||||||
if _, err := mutators[0].Mutate(ctx, ptcb.builders[0].mutation); err != nil {
|
if _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -274,8 +239,8 @@ func (ptcb *PasswordTokenCreateBulk) Save(ctx context.Context) ([]*PasswordToken
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX is like Save, but panics if an error occurs.
|
// SaveX is like Save, but panics if an error occurs.
|
||||||
func (ptcb *PasswordTokenCreateBulk) SaveX(ctx context.Context) []*PasswordToken {
|
func (_c *PasswordTokenCreateBulk) SaveX(ctx context.Context) []*PasswordToken {
|
||||||
v, err := ptcb.Save(ctx)
|
v, err := _c.Save(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -283,14 +248,14 @@ func (ptcb *PasswordTokenCreateBulk) SaveX(ctx context.Context) []*PasswordToken
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the query.
|
// Exec executes the query.
|
||||||
func (ptcb *PasswordTokenCreateBulk) Exec(ctx context.Context) error {
|
func (_c *PasswordTokenCreateBulk) Exec(ctx context.Context) error {
|
||||||
_, err := ptcb.Save(ctx)
|
_, err := _c.Save(ctx)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (ptcb *PasswordTokenCreateBulk) ExecX(ctx context.Context) {
|
func (_c *PasswordTokenCreateBulk) ExecX(ctx context.Context) {
|
||||||
if err := ptcb.Exec(ctx); err != nil {
|
if err := _c.Exec(ctx); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"goweb/ent/passwordtoken"
|
|
||||||
"goweb/ent/predicate"
|
|
||||||
|
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
"entgo.io/ent/schema/field"
|
"entgo.io/ent/schema/field"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/passwordtoken"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/predicate"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PasswordTokenDelete is the builder for deleting a PasswordToken entity.
|
// PasswordTokenDelete is the builder for deleting a PasswordToken entity.
|
||||||
|
|
@ -21,80 +20,56 @@ type PasswordTokenDelete struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Where appends a list predicates to the PasswordTokenDelete builder.
|
// Where appends a list predicates to the PasswordTokenDelete builder.
|
||||||
func (ptd *PasswordTokenDelete) Where(ps ...predicate.PasswordToken) *PasswordTokenDelete {
|
func (_d *PasswordTokenDelete) Where(ps ...predicate.PasswordToken) *PasswordTokenDelete {
|
||||||
ptd.mutation.Where(ps...)
|
_d.mutation.Where(ps...)
|
||||||
return ptd
|
return _d
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the deletion query and returns how many vertices were deleted.
|
// Exec executes the deletion query and returns how many vertices were deleted.
|
||||||
func (ptd *PasswordTokenDelete) Exec(ctx context.Context) (int, error) {
|
func (_d *PasswordTokenDelete) Exec(ctx context.Context) (int, error) {
|
||||||
var (
|
return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks)
|
||||||
err error
|
|
||||||
affected int
|
|
||||||
)
|
|
||||||
if len(ptd.hooks) == 0 {
|
|
||||||
affected, err = ptd.sqlExec(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*PasswordTokenMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
ptd.mutation = mutation
|
|
||||||
affected, err = ptd.sqlExec(ctx)
|
|
||||||
mutation.done = true
|
|
||||||
return affected, err
|
|
||||||
})
|
|
||||||
for i := len(ptd.hooks) - 1; i >= 0; i-- {
|
|
||||||
if ptd.hooks[i] == nil {
|
|
||||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = ptd.hooks[i](mut)
|
|
||||||
}
|
|
||||||
if _, err := mut.Mutate(ctx, ptd.mutation); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return affected, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (ptd *PasswordTokenDelete) ExecX(ctx context.Context) int {
|
func (_d *PasswordTokenDelete) ExecX(ctx context.Context) int {
|
||||||
n, err := ptd.Exec(ctx)
|
n, err := _d.Exec(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ptd *PasswordTokenDelete) sqlExec(ctx context.Context) (int, error) {
|
func (_d *PasswordTokenDelete) sqlExec(ctx context.Context) (int, error) {
|
||||||
_spec := &sqlgraph.DeleteSpec{
|
_spec := sqlgraph.NewDeleteSpec(passwordtoken.Table, sqlgraph.NewFieldSpec(passwordtoken.FieldID, field.TypeInt))
|
||||||
Node: &sqlgraph.NodeSpec{
|
if ps := _d.mutation.predicates; len(ps) > 0 {
|
||||||
Table: passwordtoken.Table,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: passwordtoken.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if ps := ptd.mutation.predicates; len(ps) > 0 {
|
|
||||||
_spec.Predicate = func(selector *sql.Selector) {
|
_spec.Predicate = func(selector *sql.Selector) {
|
||||||
for i := range ps {
|
for i := range ps {
|
||||||
ps[i](selector)
|
ps[i](selector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sqlgraph.DeleteNodes(ctx, ptd.driver, _spec)
|
affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec)
|
||||||
|
if err != nil && sqlgraph.IsConstraintError(err) {
|
||||||
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
|
}
|
||||||
|
_d.mutation.done = true
|
||||||
|
return affected, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordTokenDeleteOne is the builder for deleting a single PasswordToken entity.
|
// PasswordTokenDeleteOne is the builder for deleting a single PasswordToken entity.
|
||||||
type PasswordTokenDeleteOne struct {
|
type PasswordTokenDeleteOne struct {
|
||||||
ptd *PasswordTokenDelete
|
_d *PasswordTokenDelete
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where appends a list predicates to the PasswordTokenDelete builder.
|
||||||
|
func (_d *PasswordTokenDeleteOne) Where(ps ...predicate.PasswordToken) *PasswordTokenDeleteOne {
|
||||||
|
_d._d.mutation.Where(ps...)
|
||||||
|
return _d
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the deletion query.
|
// Exec executes the deletion query.
|
||||||
func (ptdo *PasswordTokenDeleteOne) Exec(ctx context.Context) error {
|
func (_d *PasswordTokenDeleteOne) Exec(ctx context.Context) error {
|
||||||
n, err := ptdo.ptd.Exec(ctx)
|
n, err := _d._d.Exec(ctx)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return err
|
return err
|
||||||
|
|
@ -106,6 +81,8 @@ func (ptdo *PasswordTokenDeleteOne) Exec(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (ptdo *PasswordTokenDeleteOne) ExecX(ctx context.Context) {
|
func (_d *PasswordTokenDeleteOne) ExecX(ctx context.Context) {
|
||||||
ptdo.ptd.ExecX(ctx)
|
if err := _d.Exec(ctx); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
|
|
@ -6,14 +6,14 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"goweb/ent/passwordtoken"
|
|
||||||
"goweb/ent/predicate"
|
|
||||||
"goweb/ent/user"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
"entgo.io/ent/schema/field"
|
"entgo.io/ent/schema/field"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/passwordtoken"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/predicate"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PasswordTokenUpdate is the builder for updating PasswordToken entities.
|
// PasswordTokenUpdate is the builder for updating PasswordToken entities.
|
||||||
|
|
@ -24,94 +24,77 @@ type PasswordTokenUpdate struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Where appends a list predicates to the PasswordTokenUpdate builder.
|
// Where appends a list predicates to the PasswordTokenUpdate builder.
|
||||||
func (ptu *PasswordTokenUpdate) Where(ps ...predicate.PasswordToken) *PasswordTokenUpdate {
|
func (_u *PasswordTokenUpdate) Where(ps ...predicate.PasswordToken) *PasswordTokenUpdate {
|
||||||
ptu.mutation.Where(ps...)
|
_u.mutation.Where(ps...)
|
||||||
return ptu
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHash sets the "hash" field.
|
// SetToken sets the "token" field.
|
||||||
func (ptu *PasswordTokenUpdate) SetHash(s string) *PasswordTokenUpdate {
|
func (_u *PasswordTokenUpdate) SetToken(v string) *PasswordTokenUpdate {
|
||||||
ptu.mutation.SetHash(s)
|
_u.mutation.SetToken(v)
|
||||||
return ptu
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableToken sets the "token" field if the given value is not nil.
|
||||||
|
func (_u *PasswordTokenUpdate) SetNillableToken(v *string) *PasswordTokenUpdate {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetToken(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUserID sets the "user_id" field.
|
||||||
|
func (_u *PasswordTokenUpdate) SetUserID(v int) *PasswordTokenUpdate {
|
||||||
|
_u.mutation.SetUserID(v)
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableUserID sets the "user_id" field if the given value is not nil.
|
||||||
|
func (_u *PasswordTokenUpdate) SetNillableUserID(v *int) *PasswordTokenUpdate {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetUserID(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCreatedAt sets the "created_at" field.
|
// SetCreatedAt sets the "created_at" field.
|
||||||
func (ptu *PasswordTokenUpdate) SetCreatedAt(t time.Time) *PasswordTokenUpdate {
|
func (_u *PasswordTokenUpdate) SetCreatedAt(v time.Time) *PasswordTokenUpdate {
|
||||||
ptu.mutation.SetCreatedAt(t)
|
_u.mutation.SetCreatedAt(v)
|
||||||
return ptu
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
|
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
|
||||||
func (ptu *PasswordTokenUpdate) SetNillableCreatedAt(t *time.Time) *PasswordTokenUpdate {
|
func (_u *PasswordTokenUpdate) SetNillableCreatedAt(v *time.Time) *PasswordTokenUpdate {
|
||||||
if t != nil {
|
if v != nil {
|
||||||
ptu.SetCreatedAt(*t)
|
_u.SetCreatedAt(*v)
|
||||||
}
|
}
|
||||||
return ptu
|
return _u
|
||||||
}
|
|
||||||
|
|
||||||
// SetUserID sets the "user" edge to the User entity by ID.
|
|
||||||
func (ptu *PasswordTokenUpdate) SetUserID(id int) *PasswordTokenUpdate {
|
|
||||||
ptu.mutation.SetUserID(id)
|
|
||||||
return ptu
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUser sets the "user" edge to the User entity.
|
// SetUser sets the "user" edge to the User entity.
|
||||||
func (ptu *PasswordTokenUpdate) SetUser(u *User) *PasswordTokenUpdate {
|
func (_u *PasswordTokenUpdate) SetUser(v *User) *PasswordTokenUpdate {
|
||||||
return ptu.SetUserID(u.ID)
|
return _u.SetUserID(v.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutation returns the PasswordTokenMutation object of the builder.
|
// Mutation returns the PasswordTokenMutation object of the builder.
|
||||||
func (ptu *PasswordTokenUpdate) Mutation() *PasswordTokenMutation {
|
func (_u *PasswordTokenUpdate) Mutation() *PasswordTokenMutation {
|
||||||
return ptu.mutation
|
return _u.mutation
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearUser clears the "user" edge to the User entity.
|
// ClearUser clears the "user" edge to the User entity.
|
||||||
func (ptu *PasswordTokenUpdate) ClearUser() *PasswordTokenUpdate {
|
func (_u *PasswordTokenUpdate) ClearUser() *PasswordTokenUpdate {
|
||||||
ptu.mutation.ClearUser()
|
_u.mutation.ClearUser()
|
||||||
return ptu
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save executes the query and returns the number of nodes affected by the update operation.
|
// Save executes the query and returns the number of nodes affected by the update operation.
|
||||||
func (ptu *PasswordTokenUpdate) Save(ctx context.Context) (int, error) {
|
func (_u *PasswordTokenUpdate) Save(ctx context.Context) (int, error) {
|
||||||
var (
|
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
|
||||||
err error
|
|
||||||
affected int
|
|
||||||
)
|
|
||||||
if len(ptu.hooks) == 0 {
|
|
||||||
if err = ptu.check(); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
affected, err = ptu.sqlSave(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*PasswordTokenMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
if err = ptu.check(); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
ptu.mutation = mutation
|
|
||||||
affected, err = ptu.sqlSave(ctx)
|
|
||||||
mutation.done = true
|
|
||||||
return affected, err
|
|
||||||
})
|
|
||||||
for i := len(ptu.hooks) - 1; i >= 0; i-- {
|
|
||||||
if ptu.hooks[i] == nil {
|
|
||||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = ptu.hooks[i](mut)
|
|
||||||
}
|
|
||||||
if _, err := mut.Mutate(ctx, ptu.mutation); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return affected, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX is like Save, but panics if an error occurs.
|
// SaveX is like Save, but panics if an error occurs.
|
||||||
func (ptu *PasswordTokenUpdate) SaveX(ctx context.Context) int {
|
func (_u *PasswordTokenUpdate) SaveX(ctx context.Context) int {
|
||||||
affected, err := ptu.Save(ctx)
|
affected, err := _u.Save(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -119,64 +102,50 @@ func (ptu *PasswordTokenUpdate) SaveX(ctx context.Context) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the query.
|
// Exec executes the query.
|
||||||
func (ptu *PasswordTokenUpdate) Exec(ctx context.Context) error {
|
func (_u *PasswordTokenUpdate) Exec(ctx context.Context) error {
|
||||||
_, err := ptu.Save(ctx)
|
_, err := _u.Save(ctx)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (ptu *PasswordTokenUpdate) ExecX(ctx context.Context) {
|
func (_u *PasswordTokenUpdate) ExecX(ctx context.Context) {
|
||||||
if err := ptu.Exec(ctx); err != nil {
|
if err := _u.Exec(ctx); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check runs all checks and user-defined validators on the builder.
|
// check runs all checks and user-defined validators on the builder.
|
||||||
func (ptu *PasswordTokenUpdate) check() error {
|
func (_u *PasswordTokenUpdate) check() error {
|
||||||
if v, ok := ptu.mutation.Hash(); ok {
|
if v, ok := _u.mutation.Token(); ok {
|
||||||
if err := passwordtoken.HashValidator(v); err != nil {
|
if err := passwordtoken.TokenValidator(v); err != nil {
|
||||||
return &ValidationError{Name: "hash", err: fmt.Errorf("ent: validator failed for field \"hash\": %w", err)}
|
return &ValidationError{Name: "token", err: fmt.Errorf(`ent: validator failed for field "PasswordToken.token": %w`, err)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, ok := ptu.mutation.UserID(); ptu.mutation.UserCleared() && !ok {
|
if _u.mutation.UserCleared() && len(_u.mutation.UserIDs()) > 0 {
|
||||||
return errors.New("ent: clearing a required unique edge \"user\"")
|
return errors.New(`ent: clearing a required unique edge "PasswordToken.user"`)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ptu *PasswordTokenUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
func (_u *PasswordTokenUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
||||||
_spec := &sqlgraph.UpdateSpec{
|
if err := _u.check(); err != nil {
|
||||||
Node: &sqlgraph.NodeSpec{
|
return _node, err
|
||||||
Table: passwordtoken.Table,
|
|
||||||
Columns: passwordtoken.Columns,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: passwordtoken.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
if ps := ptu.mutation.predicates; len(ps) > 0 {
|
_spec := sqlgraph.NewUpdateSpec(passwordtoken.Table, passwordtoken.Columns, sqlgraph.NewFieldSpec(passwordtoken.FieldID, field.TypeInt))
|
||||||
|
if ps := _u.mutation.predicates; len(ps) > 0 {
|
||||||
_spec.Predicate = func(selector *sql.Selector) {
|
_spec.Predicate = func(selector *sql.Selector) {
|
||||||
for i := range ps {
|
for i := range ps {
|
||||||
ps[i](selector)
|
ps[i](selector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if value, ok := ptu.mutation.Hash(); ok {
|
if value, ok := _u.mutation.Token(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(passwordtoken.FieldToken, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
|
||||||
Value: value,
|
|
||||||
Column: passwordtoken.FieldHash,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if value, ok := ptu.mutation.CreatedAt(); ok {
|
if value, ok := _u.mutation.CreatedAt(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(passwordtoken.FieldCreatedAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: passwordtoken.FieldCreatedAt,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if ptu.mutation.UserCleared() {
|
if _u.mutation.UserCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.M2O,
|
Rel: sqlgraph.M2O,
|
||||||
Inverse: false,
|
Inverse: false,
|
||||||
|
|
@ -184,15 +153,12 @@ func (ptu *PasswordTokenUpdate) sqlSave(ctx context.Context) (n int, err error)
|
||||||
Columns: []string{passwordtoken.UserColumn},
|
Columns: []string{passwordtoken.UserColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt),
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: user.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
}
|
}
|
||||||
if nodes := ptu.mutation.UserIDs(); len(nodes) > 0 {
|
if nodes := _u.mutation.UserIDs(); len(nodes) > 0 {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.M2O,
|
Rel: sqlgraph.M2O,
|
||||||
Inverse: false,
|
Inverse: false,
|
||||||
|
|
@ -200,10 +166,7 @@ func (ptu *PasswordTokenUpdate) sqlSave(ctx context.Context) (n int, err error)
|
||||||
Columns: []string{passwordtoken.UserColumn},
|
Columns: []string{passwordtoken.UserColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt),
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: user.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
|
|
@ -211,15 +174,16 @@ func (ptu *PasswordTokenUpdate) sqlSave(ctx context.Context) (n int, err error)
|
||||||
}
|
}
|
||||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||||
}
|
}
|
||||||
if n, err = sqlgraph.UpdateNodes(ctx, ptu.driver, _spec); err != nil {
|
if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil {
|
||||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||||
err = &NotFoundError{passwordtoken.Label}
|
err = &NotFoundError{passwordtoken.Label}
|
||||||
} else if sqlgraph.IsConstraintError(err) {
|
} else if sqlgraph.IsConstraintError(err) {
|
||||||
err = &ConstraintError{err.Error(), err}
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
}
|
}
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return n, nil
|
_u.mutation.done = true
|
||||||
|
return _node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordTokenUpdateOne is the builder for updating a single PasswordToken entity.
|
// PasswordTokenUpdateOne is the builder for updating a single PasswordToken entity.
|
||||||
|
|
@ -230,96 +194,85 @@ type PasswordTokenUpdateOne struct {
|
||||||
mutation *PasswordTokenMutation
|
mutation *PasswordTokenMutation
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHash sets the "hash" field.
|
// SetToken sets the "token" field.
|
||||||
func (ptuo *PasswordTokenUpdateOne) SetHash(s string) *PasswordTokenUpdateOne {
|
func (_u *PasswordTokenUpdateOne) SetToken(v string) *PasswordTokenUpdateOne {
|
||||||
ptuo.mutation.SetHash(s)
|
_u.mutation.SetToken(v)
|
||||||
return ptuo
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableToken sets the "token" field if the given value is not nil.
|
||||||
|
func (_u *PasswordTokenUpdateOne) SetNillableToken(v *string) *PasswordTokenUpdateOne {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetToken(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUserID sets the "user_id" field.
|
||||||
|
func (_u *PasswordTokenUpdateOne) SetUserID(v int) *PasswordTokenUpdateOne {
|
||||||
|
_u.mutation.SetUserID(v)
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableUserID sets the "user_id" field if the given value is not nil.
|
||||||
|
func (_u *PasswordTokenUpdateOne) SetNillableUserID(v *int) *PasswordTokenUpdateOne {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetUserID(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCreatedAt sets the "created_at" field.
|
// SetCreatedAt sets the "created_at" field.
|
||||||
func (ptuo *PasswordTokenUpdateOne) SetCreatedAt(t time.Time) *PasswordTokenUpdateOne {
|
func (_u *PasswordTokenUpdateOne) SetCreatedAt(v time.Time) *PasswordTokenUpdateOne {
|
||||||
ptuo.mutation.SetCreatedAt(t)
|
_u.mutation.SetCreatedAt(v)
|
||||||
return ptuo
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
|
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
|
||||||
func (ptuo *PasswordTokenUpdateOne) SetNillableCreatedAt(t *time.Time) *PasswordTokenUpdateOne {
|
func (_u *PasswordTokenUpdateOne) SetNillableCreatedAt(v *time.Time) *PasswordTokenUpdateOne {
|
||||||
if t != nil {
|
if v != nil {
|
||||||
ptuo.SetCreatedAt(*t)
|
_u.SetCreatedAt(*v)
|
||||||
}
|
}
|
||||||
return ptuo
|
return _u
|
||||||
}
|
|
||||||
|
|
||||||
// SetUserID sets the "user" edge to the User entity by ID.
|
|
||||||
func (ptuo *PasswordTokenUpdateOne) SetUserID(id int) *PasswordTokenUpdateOne {
|
|
||||||
ptuo.mutation.SetUserID(id)
|
|
||||||
return ptuo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetUser sets the "user" edge to the User entity.
|
// SetUser sets the "user" edge to the User entity.
|
||||||
func (ptuo *PasswordTokenUpdateOne) SetUser(u *User) *PasswordTokenUpdateOne {
|
func (_u *PasswordTokenUpdateOne) SetUser(v *User) *PasswordTokenUpdateOne {
|
||||||
return ptuo.SetUserID(u.ID)
|
return _u.SetUserID(v.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutation returns the PasswordTokenMutation object of the builder.
|
// Mutation returns the PasswordTokenMutation object of the builder.
|
||||||
func (ptuo *PasswordTokenUpdateOne) Mutation() *PasswordTokenMutation {
|
func (_u *PasswordTokenUpdateOne) Mutation() *PasswordTokenMutation {
|
||||||
return ptuo.mutation
|
return _u.mutation
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearUser clears the "user" edge to the User entity.
|
// ClearUser clears the "user" edge to the User entity.
|
||||||
func (ptuo *PasswordTokenUpdateOne) ClearUser() *PasswordTokenUpdateOne {
|
func (_u *PasswordTokenUpdateOne) ClearUser() *PasswordTokenUpdateOne {
|
||||||
ptuo.mutation.ClearUser()
|
_u.mutation.ClearUser()
|
||||||
return ptuo
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where appends a list predicates to the PasswordTokenUpdate builder.
|
||||||
|
func (_u *PasswordTokenUpdateOne) Where(ps ...predicate.PasswordToken) *PasswordTokenUpdateOne {
|
||||||
|
_u.mutation.Where(ps...)
|
||||||
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select allows selecting one or more fields (columns) of the returned entity.
|
// Select allows selecting one or more fields (columns) of the returned entity.
|
||||||
// The default is selecting all fields defined in the entity schema.
|
// The default is selecting all fields defined in the entity schema.
|
||||||
func (ptuo *PasswordTokenUpdateOne) Select(field string, fields ...string) *PasswordTokenUpdateOne {
|
func (_u *PasswordTokenUpdateOne) Select(field string, fields ...string) *PasswordTokenUpdateOne {
|
||||||
ptuo.fields = append([]string{field}, fields...)
|
_u.fields = append([]string{field}, fields...)
|
||||||
return ptuo
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save executes the query and returns the updated PasswordToken entity.
|
// Save executes the query and returns the updated PasswordToken entity.
|
||||||
func (ptuo *PasswordTokenUpdateOne) Save(ctx context.Context) (*PasswordToken, error) {
|
func (_u *PasswordTokenUpdateOne) Save(ctx context.Context) (*PasswordToken, error) {
|
||||||
var (
|
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
|
||||||
err error
|
|
||||||
node *PasswordToken
|
|
||||||
)
|
|
||||||
if len(ptuo.hooks) == 0 {
|
|
||||||
if err = ptuo.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
node, err = ptuo.sqlSave(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*PasswordTokenMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
if err = ptuo.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ptuo.mutation = mutation
|
|
||||||
node, err = ptuo.sqlSave(ctx)
|
|
||||||
mutation.done = true
|
|
||||||
return node, err
|
|
||||||
})
|
|
||||||
for i := len(ptuo.hooks) - 1; i >= 0; i-- {
|
|
||||||
if ptuo.hooks[i] == nil {
|
|
||||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = ptuo.hooks[i](mut)
|
|
||||||
}
|
|
||||||
if _, err := mut.Mutate(ctx, ptuo.mutation); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return node, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX is like Save, but panics if an error occurs.
|
// SaveX is like Save, but panics if an error occurs.
|
||||||
func (ptuo *PasswordTokenUpdateOne) SaveX(ctx context.Context) *PasswordToken {
|
func (_u *PasswordTokenUpdateOne) SaveX(ctx context.Context) *PasswordToken {
|
||||||
node, err := ptuo.Save(ctx)
|
node, err := _u.Save(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -327,48 +280,42 @@ func (ptuo *PasswordTokenUpdateOne) SaveX(ctx context.Context) *PasswordToken {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the query on the entity.
|
// Exec executes the query on the entity.
|
||||||
func (ptuo *PasswordTokenUpdateOne) Exec(ctx context.Context) error {
|
func (_u *PasswordTokenUpdateOne) Exec(ctx context.Context) error {
|
||||||
_, err := ptuo.Save(ctx)
|
_, err := _u.Save(ctx)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (ptuo *PasswordTokenUpdateOne) ExecX(ctx context.Context) {
|
func (_u *PasswordTokenUpdateOne) ExecX(ctx context.Context) {
|
||||||
if err := ptuo.Exec(ctx); err != nil {
|
if err := _u.Exec(ctx); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check runs all checks and user-defined validators on the builder.
|
// check runs all checks and user-defined validators on the builder.
|
||||||
func (ptuo *PasswordTokenUpdateOne) check() error {
|
func (_u *PasswordTokenUpdateOne) check() error {
|
||||||
if v, ok := ptuo.mutation.Hash(); ok {
|
if v, ok := _u.mutation.Token(); ok {
|
||||||
if err := passwordtoken.HashValidator(v); err != nil {
|
if err := passwordtoken.TokenValidator(v); err != nil {
|
||||||
return &ValidationError{Name: "hash", err: fmt.Errorf("ent: validator failed for field \"hash\": %w", err)}
|
return &ValidationError{Name: "token", err: fmt.Errorf(`ent: validator failed for field "PasswordToken.token": %w`, err)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, ok := ptuo.mutation.UserID(); ptuo.mutation.UserCleared() && !ok {
|
if _u.mutation.UserCleared() && len(_u.mutation.UserIDs()) > 0 {
|
||||||
return errors.New("ent: clearing a required unique edge \"user\"")
|
return errors.New(`ent: clearing a required unique edge "PasswordToken.user"`)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ptuo *PasswordTokenUpdateOne) sqlSave(ctx context.Context) (_node *PasswordToken, err error) {
|
func (_u *PasswordTokenUpdateOne) sqlSave(ctx context.Context) (_node *PasswordToken, err error) {
|
||||||
_spec := &sqlgraph.UpdateSpec{
|
if err := _u.check(); err != nil {
|
||||||
Node: &sqlgraph.NodeSpec{
|
return _node, err
|
||||||
Table: passwordtoken.Table,
|
|
||||||
Columns: passwordtoken.Columns,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: passwordtoken.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
id, ok := ptuo.mutation.ID()
|
_spec := sqlgraph.NewUpdateSpec(passwordtoken.Table, passwordtoken.Columns, sqlgraph.NewFieldSpec(passwordtoken.FieldID, field.TypeInt))
|
||||||
|
id, ok := _u.mutation.ID()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, &ValidationError{Name: "ID", err: fmt.Errorf("missing PasswordToken.ID for update")}
|
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "PasswordToken.id" for update`)}
|
||||||
}
|
}
|
||||||
_spec.Node.ID.Value = id
|
_spec.Node.ID.Value = id
|
||||||
if fields := ptuo.fields; len(fields) > 0 {
|
if fields := _u.fields; len(fields) > 0 {
|
||||||
_spec.Node.Columns = make([]string, 0, len(fields))
|
_spec.Node.Columns = make([]string, 0, len(fields))
|
||||||
_spec.Node.Columns = append(_spec.Node.Columns, passwordtoken.FieldID)
|
_spec.Node.Columns = append(_spec.Node.Columns, passwordtoken.FieldID)
|
||||||
for _, f := range fields {
|
for _, f := range fields {
|
||||||
|
|
@ -380,28 +327,20 @@ func (ptuo *PasswordTokenUpdateOne) sqlSave(ctx context.Context) (_node *Passwor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ps := ptuo.mutation.predicates; len(ps) > 0 {
|
if ps := _u.mutation.predicates; len(ps) > 0 {
|
||||||
_spec.Predicate = func(selector *sql.Selector) {
|
_spec.Predicate = func(selector *sql.Selector) {
|
||||||
for i := range ps {
|
for i := range ps {
|
||||||
ps[i](selector)
|
ps[i](selector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if value, ok := ptuo.mutation.Hash(); ok {
|
if value, ok := _u.mutation.Token(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(passwordtoken.FieldToken, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
|
||||||
Value: value,
|
|
||||||
Column: passwordtoken.FieldHash,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if value, ok := ptuo.mutation.CreatedAt(); ok {
|
if value, ok := _u.mutation.CreatedAt(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(passwordtoken.FieldCreatedAt, field.TypeTime, value)
|
||||||
Type: field.TypeTime,
|
|
||||||
Value: value,
|
|
||||||
Column: passwordtoken.FieldCreatedAt,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if ptuo.mutation.UserCleared() {
|
if _u.mutation.UserCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.M2O,
|
Rel: sqlgraph.M2O,
|
||||||
Inverse: false,
|
Inverse: false,
|
||||||
|
|
@ -409,15 +348,12 @@ func (ptuo *PasswordTokenUpdateOne) sqlSave(ctx context.Context) (_node *Passwor
|
||||||
Columns: []string{passwordtoken.UserColumn},
|
Columns: []string{passwordtoken.UserColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt),
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: user.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
}
|
}
|
||||||
if nodes := ptuo.mutation.UserIDs(); len(nodes) > 0 {
|
if nodes := _u.mutation.UserIDs(); len(nodes) > 0 {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.M2O,
|
Rel: sqlgraph.M2O,
|
||||||
Inverse: false,
|
Inverse: false,
|
||||||
|
|
@ -425,10 +361,7 @@ func (ptuo *PasswordTokenUpdateOne) sqlSave(ctx context.Context) (_node *Passwor
|
||||||
Columns: []string{passwordtoken.UserColumn},
|
Columns: []string{passwordtoken.UserColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt),
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: user.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
|
|
@ -436,16 +369,17 @@ func (ptuo *PasswordTokenUpdateOne) sqlSave(ctx context.Context) (_node *Passwor
|
||||||
}
|
}
|
||||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||||
}
|
}
|
||||||
_node = &PasswordToken{config: ptuo.config}
|
_node = &PasswordToken{config: _u.config}
|
||||||
_spec.Assign = _node.assignValues
|
_spec.Assign = _node.assignValues
|
||||||
_spec.ScanValues = _node.scanValues
|
_spec.ScanValues = _node.scanValues
|
||||||
if err = sqlgraph.UpdateNode(ctx, ptuo.driver, _spec); err != nil {
|
if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil {
|
||||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||||
err = &NotFoundError{passwordtoken.Label}
|
err = &NotFoundError{passwordtoken.Label}
|
||||||
} else if sqlgraph.IsConstraintError(err) {
|
} else if sqlgraph.IsConstraintError(err) {
|
||||||
err = &ConstraintError{err.Error(), err}
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
_u.mutation.done = true
|
||||||
return _node, nil
|
return _node, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package predicate
|
package predicate
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
// The schema-stitching logic is generated in goweb/ent/runtime/runtime.go
|
// The schema-stitching logic is generated in github.com/mikestefanello/pagoda/ent/runtime/runtime.go
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,29 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"goweb/ent/passwordtoken"
|
|
||||||
"goweb/ent/schema"
|
|
||||||
"goweb/ent/user"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/mikestefanello/pagoda/ent/passwordtoken"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/schema"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The init function reads all schema descriptors with runtime code
|
// The init function reads all schema descriptors with runtime code
|
||||||
// (default values, validators, hooks and policies) and stitches it
|
// (default values, validators, hooks and policies) and stitches it
|
||||||
// to their package variables.
|
// to their package variables.
|
||||||
func init() {
|
func init() {
|
||||||
|
passwordtokenHooks := schema.PasswordToken{}.Hooks()
|
||||||
|
passwordtoken.Hooks[0] = passwordtokenHooks[0]
|
||||||
passwordtokenFields := schema.PasswordToken{}.Fields()
|
passwordtokenFields := schema.PasswordToken{}.Fields()
|
||||||
_ = passwordtokenFields
|
_ = passwordtokenFields
|
||||||
// passwordtokenDescHash is the schema descriptor for hash field.
|
// passwordtokenDescToken is the schema descriptor for token field.
|
||||||
passwordtokenDescHash := passwordtokenFields[0].Descriptor()
|
passwordtokenDescToken := passwordtokenFields[0].Descriptor()
|
||||||
// passwordtoken.HashValidator is a validator for the "hash" field. It is called by the builders before save.
|
// passwordtoken.TokenValidator is a validator for the "token" field. It is called by the builders before save.
|
||||||
passwordtoken.HashValidator = passwordtokenDescHash.Validators[0].(func(string) error)
|
passwordtoken.TokenValidator = passwordtokenDescToken.Validators[0].(func(string) error)
|
||||||
// passwordtokenDescCreatedAt is the schema descriptor for created_at field.
|
// passwordtokenDescCreatedAt is the schema descriptor for created_at field.
|
||||||
passwordtokenDescCreatedAt := passwordtokenFields[1].Descriptor()
|
passwordtokenDescCreatedAt := passwordtokenFields[2].Descriptor()
|
||||||
// passwordtoken.DefaultCreatedAt holds the default value on creation for the created_at field.
|
// passwordtoken.DefaultCreatedAt holds the default value on creation for the created_at field.
|
||||||
passwordtoken.DefaultCreatedAt = passwordtokenDescCreatedAt.Default.(func() time.Time)
|
passwordtoken.DefaultCreatedAt = passwordtokenDescCreatedAt.Default.(func() time.Time)
|
||||||
userHooks := schema.User{}.Hooks()
|
userHooks := schema.User{}.Hooks()
|
||||||
|
|
@ -34,18 +37,40 @@ func init() {
|
||||||
// userDescEmail is the schema descriptor for email field.
|
// userDescEmail is the schema descriptor for email field.
|
||||||
userDescEmail := userFields[1].Descriptor()
|
userDescEmail := userFields[1].Descriptor()
|
||||||
// user.EmailValidator is a validator for the "email" field. It is called by the builders before save.
|
// user.EmailValidator is a validator for the "email" field. It is called by the builders before save.
|
||||||
user.EmailValidator = userDescEmail.Validators[0].(func(string) error)
|
user.EmailValidator = func() func(string) error {
|
||||||
|
validators := userDescEmail.Validators
|
||||||
|
fns := [...]func(string) error{
|
||||||
|
validators[0].(func(string) error),
|
||||||
|
validators[1].(func(string) error),
|
||||||
|
}
|
||||||
|
return func(email string) error {
|
||||||
|
for _, fn := range fns {
|
||||||
|
if err := fn(email); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}()
|
||||||
// userDescPassword is the schema descriptor for password field.
|
// userDescPassword is the schema descriptor for password field.
|
||||||
userDescPassword := userFields[2].Descriptor()
|
userDescPassword := userFields[2].Descriptor()
|
||||||
// user.PasswordValidator is a validator for the "password" field. It is called by the builders before save.
|
// user.PasswordValidator is a validator for the "password" field. It is called by the builders before save.
|
||||||
user.PasswordValidator = userDescPassword.Validators[0].(func(string) error)
|
user.PasswordValidator = userDescPassword.Validators[0].(func(string) error)
|
||||||
|
// userDescVerified is the schema descriptor for verified field.
|
||||||
|
userDescVerified := userFields[3].Descriptor()
|
||||||
|
// user.DefaultVerified holds the default value on creation for the verified field.
|
||||||
|
user.DefaultVerified = userDescVerified.Default.(bool)
|
||||||
|
// userDescAdmin is the schema descriptor for admin field.
|
||||||
|
userDescAdmin := userFields[4].Descriptor()
|
||||||
|
// user.DefaultAdmin holds the default value on creation for the admin field.
|
||||||
|
user.DefaultAdmin = userDescAdmin.Default.(bool)
|
||||||
// userDescCreatedAt is the schema descriptor for created_at field.
|
// userDescCreatedAt is the schema descriptor for created_at field.
|
||||||
userDescCreatedAt := userFields[3].Descriptor()
|
userDescCreatedAt := userFields[5].Descriptor()
|
||||||
// user.DefaultCreatedAt holds the default value on creation for the created_at field.
|
// user.DefaultCreatedAt holds the default value on creation for the created_at field.
|
||||||
user.DefaultCreatedAt = userDescCreatedAt.Default.(func() time.Time)
|
user.DefaultCreatedAt = userDescCreatedAt.Default.(func() time.Time)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "v0.9.1" // Version of ent codegen.
|
Version = "v0.14.5" // Version of ent codegen.
|
||||||
Sum = "h1:IG8andyeD79GG24U8Q+1Y45hQXj6gY5evSBcva5gtBk=" // Sum of ent codegen.
|
Sum = "h1:Rj2WOYJtCkWyFo6a+5wB3EfBRP0rnx1fMk6gGA0UUe4=" // Sum of ent codegen.
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
package schema
|
package schema
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"entgo.io/ent"
|
"entgo.io/ent"
|
||||||
"entgo.io/ent/schema/edge"
|
"entgo.io/ent/schema/edge"
|
||||||
"entgo.io/ent/schema/field"
|
"entgo.io/ent/schema/field"
|
||||||
|
ge "github.com/mikestefanello/pagoda/ent"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/hook"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PasswordToken holds the schema definition for the PasswordToken entity.
|
// PasswordToken holds the schema definition for the PasswordToken entity.
|
||||||
|
|
@ -16,9 +20,10 @@ type PasswordToken struct {
|
||||||
// Fields of the PasswordToken.
|
// Fields of the PasswordToken.
|
||||||
func (PasswordToken) Fields() []ent.Field {
|
func (PasswordToken) Fields() []ent.Field {
|
||||||
return []ent.Field{
|
return []ent.Field{
|
||||||
field.String("hash").
|
field.String("token").
|
||||||
Sensitive().
|
Sensitive().
|
||||||
NotEmpty(),
|
NotEmpty(),
|
||||||
|
field.Int("user_id"),
|
||||||
field.Time("created_at").
|
field.Time("created_at").
|
||||||
Default(time.Now),
|
Default(time.Now),
|
||||||
}
|
}
|
||||||
|
|
@ -28,7 +33,30 @@ func (PasswordToken) Fields() []ent.Field {
|
||||||
func (PasswordToken) Edges() []ent.Edge {
|
func (PasswordToken) Edges() []ent.Edge {
|
||||||
return []ent.Edge{
|
return []ent.Edge{
|
||||||
edge.To("user", User.Type).
|
edge.To("user", User.Type).
|
||||||
|
Field("user_id").
|
||||||
Required().
|
Required().
|
||||||
Unique(),
|
Unique(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hooks of the PasswordToken.
|
||||||
|
func (PasswordToken) Hooks() []ent.Hook {
|
||||||
|
return []ent.Hook{
|
||||||
|
hook.On(
|
||||||
|
func(next ent.Mutator) ent.Mutator {
|
||||||
|
return hook.PasswordTokenFunc(func(ctx context.Context, m *ge.PasswordTokenMutation) (ent.Value, error) {
|
||||||
|
if v, exists := m.Token(); exists {
|
||||||
|
hash, err := bcrypt.GenerateFromPassword([]byte(v), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
m.SetToken(string(hash))
|
||||||
|
}
|
||||||
|
return next.Mutate(ctx, m)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// Limit the hook only for these operations.
|
||||||
|
ent.OpCreate|ent.OpUpdate|ent.OpUpdateOne,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ package schema
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net/mail"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ge "goweb/ent"
|
ge "github.com/mikestefanello/pagoda/ent"
|
||||||
"goweb/ent/hook"
|
"github.com/mikestefanello/pagoda/ent/hook"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
"entgo.io/ent"
|
"entgo.io/ent"
|
||||||
"entgo.io/ent/schema/edge"
|
"entgo.io/ent/schema/edge"
|
||||||
|
|
@ -25,10 +27,18 @@ func (User) Fields() []ent.Field {
|
||||||
NotEmpty(),
|
NotEmpty(),
|
||||||
field.String("email").
|
field.String("email").
|
||||||
NotEmpty().
|
NotEmpty().
|
||||||
Unique(),
|
Unique().
|
||||||
|
Validate(func(s string) error {
|
||||||
|
_, err := mail.ParseAddress(s)
|
||||||
|
return err
|
||||||
|
}),
|
||||||
field.String("password").
|
field.String("password").
|
||||||
Sensitive().
|
Sensitive().
|
||||||
NotEmpty(),
|
NotEmpty(),
|
||||||
|
field.Bool("verified").
|
||||||
|
Default(false),
|
||||||
|
field.Bool("admin").
|
||||||
|
Default(false),
|
||||||
field.Time("created_at").
|
field.Time("created_at").
|
||||||
Default(time.Now).
|
Default(time.Now).
|
||||||
Immutable(),
|
Immutable(),
|
||||||
|
|
@ -52,6 +62,14 @@ func (User) Hooks() []ent.Hook {
|
||||||
if v, exists := m.Email(); exists {
|
if v, exists := m.Email(); exists {
|
||||||
m.SetEmail(strings.ToLower(v))
|
m.SetEmail(strings.ToLower(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if v, exists := m.Password(); exists {
|
||||||
|
hash, err := bcrypt.GenerateFromPassword([]byte(v), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
m.SetPassword(string(hash))
|
||||||
|
}
|
||||||
return next.Mutate(ctx, m)
|
return next.Mutate(ctx, m)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
|
||||||
50
ent/tx.go
50
ent/tx.go
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
|
|
@ -20,19 +20,13 @@ type Tx struct {
|
||||||
// lazily loaded.
|
// lazily loaded.
|
||||||
client *Client
|
client *Client
|
||||||
clientOnce sync.Once
|
clientOnce sync.Once
|
||||||
|
|
||||||
// completion callbacks.
|
|
||||||
mu sync.Mutex
|
|
||||||
onCommit []CommitHook
|
|
||||||
onRollback []RollbackHook
|
|
||||||
|
|
||||||
// ctx lives for the life of the transaction. It is
|
// ctx lives for the life of the transaction. It is
|
||||||
// the same context used by the underlying connection.
|
// the same context used by the underlying connection.
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// Committer is the interface that wraps the Committer method.
|
// Committer is the interface that wraps the Commit method.
|
||||||
Committer interface {
|
Committer interface {
|
||||||
Commit(context.Context, *Tx) error
|
Commit(context.Context, *Tx) error
|
||||||
}
|
}
|
||||||
|
|
@ -46,7 +40,7 @@ type (
|
||||||
// and returns a Committer. For example:
|
// and returns a Committer. For example:
|
||||||
//
|
//
|
||||||
// hook := func(next ent.Committer) ent.Committer {
|
// hook := func(next ent.Committer) ent.Committer {
|
||||||
// return ent.CommitFunc(func(context.Context, tx *ent.Tx) error {
|
// return ent.CommitFunc(func(ctx context.Context, tx *ent.Tx) error {
|
||||||
// // Do some stuff before.
|
// // Do some stuff before.
|
||||||
// if err := next.Commit(ctx, tx); err != nil {
|
// if err := next.Commit(ctx, tx); err != nil {
|
||||||
// return err
|
// return err
|
||||||
|
|
@ -70,9 +64,9 @@ func (tx *Tx) Commit() error {
|
||||||
var fn Committer = CommitFunc(func(context.Context, *Tx) error {
|
var fn Committer = CommitFunc(func(context.Context, *Tx) error {
|
||||||
return txDriver.tx.Commit()
|
return txDriver.tx.Commit()
|
||||||
})
|
})
|
||||||
tx.mu.Lock()
|
txDriver.mu.Lock()
|
||||||
hooks := append([]CommitHook(nil), tx.onCommit...)
|
hooks := append([]CommitHook(nil), txDriver.onCommit...)
|
||||||
tx.mu.Unlock()
|
txDriver.mu.Unlock()
|
||||||
for i := len(hooks) - 1; i >= 0; i-- {
|
for i := len(hooks) - 1; i >= 0; i-- {
|
||||||
fn = hooks[i](fn)
|
fn = hooks[i](fn)
|
||||||
}
|
}
|
||||||
|
|
@ -81,13 +75,14 @@ func (tx *Tx) Commit() error {
|
||||||
|
|
||||||
// OnCommit adds a hook to call on commit.
|
// OnCommit adds a hook to call on commit.
|
||||||
func (tx *Tx) OnCommit(f CommitHook) {
|
func (tx *Tx) OnCommit(f CommitHook) {
|
||||||
tx.mu.Lock()
|
txDriver := tx.config.driver.(*txDriver)
|
||||||
defer tx.mu.Unlock()
|
txDriver.mu.Lock()
|
||||||
tx.onCommit = append(tx.onCommit, f)
|
txDriver.onCommit = append(txDriver.onCommit, f)
|
||||||
|
txDriver.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// Rollbacker is the interface that wraps the Rollbacker method.
|
// Rollbacker is the interface that wraps the Rollback method.
|
||||||
Rollbacker interface {
|
Rollbacker interface {
|
||||||
Rollback(context.Context, *Tx) error
|
Rollback(context.Context, *Tx) error
|
||||||
}
|
}
|
||||||
|
|
@ -101,7 +96,7 @@ type (
|
||||||
// and returns a Rollbacker. For example:
|
// and returns a Rollbacker. For example:
|
||||||
//
|
//
|
||||||
// hook := func(next ent.Rollbacker) ent.Rollbacker {
|
// hook := func(next ent.Rollbacker) ent.Rollbacker {
|
||||||
// return ent.RollbackFunc(func(context.Context, tx *ent.Tx) error {
|
// return ent.RollbackFunc(func(ctx context.Context, tx *ent.Tx) error {
|
||||||
// // Do some stuff before.
|
// // Do some stuff before.
|
||||||
// if err := next.Rollback(ctx, tx); err != nil {
|
// if err := next.Rollback(ctx, tx); err != nil {
|
||||||
// return err
|
// return err
|
||||||
|
|
@ -125,9 +120,9 @@ func (tx *Tx) Rollback() error {
|
||||||
var fn Rollbacker = RollbackFunc(func(context.Context, *Tx) error {
|
var fn Rollbacker = RollbackFunc(func(context.Context, *Tx) error {
|
||||||
return txDriver.tx.Rollback()
|
return txDriver.tx.Rollback()
|
||||||
})
|
})
|
||||||
tx.mu.Lock()
|
txDriver.mu.Lock()
|
||||||
hooks := append([]RollbackHook(nil), tx.onRollback...)
|
hooks := append([]RollbackHook(nil), txDriver.onRollback...)
|
||||||
tx.mu.Unlock()
|
txDriver.mu.Unlock()
|
||||||
for i := len(hooks) - 1; i >= 0; i-- {
|
for i := len(hooks) - 1; i >= 0; i-- {
|
||||||
fn = hooks[i](fn)
|
fn = hooks[i](fn)
|
||||||
}
|
}
|
||||||
|
|
@ -136,9 +131,10 @@ func (tx *Tx) Rollback() error {
|
||||||
|
|
||||||
// OnRollback adds a hook to call on rollback.
|
// OnRollback adds a hook to call on rollback.
|
||||||
func (tx *Tx) OnRollback(f RollbackHook) {
|
func (tx *Tx) OnRollback(f RollbackHook) {
|
||||||
tx.mu.Lock()
|
txDriver := tx.config.driver.(*txDriver)
|
||||||
defer tx.mu.Unlock()
|
txDriver.mu.Lock()
|
||||||
tx.onRollback = append(tx.onRollback, f)
|
txDriver.onRollback = append(txDriver.onRollback, f)
|
||||||
|
txDriver.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client returns a Client that binds to current transaction.
|
// Client returns a Client that binds to current transaction.
|
||||||
|
|
@ -171,6 +167,10 @@ type txDriver struct {
|
||||||
drv dialect.Driver
|
drv dialect.Driver
|
||||||
// tx is the underlying transaction.
|
// tx is the underlying transaction.
|
||||||
tx dialect.Tx
|
tx dialect.Tx
|
||||||
|
// completion hooks.
|
||||||
|
mu sync.Mutex
|
||||||
|
onCommit []CommitHook
|
||||||
|
onRollback []RollbackHook
|
||||||
}
|
}
|
||||||
|
|
||||||
// newTx creates a new transactional driver.
|
// newTx creates a new transactional driver.
|
||||||
|
|
@ -201,12 +201,12 @@ func (*txDriver) Commit() error { return nil }
|
||||||
func (*txDriver) Rollback() error { return nil }
|
func (*txDriver) Rollback() error { return nil }
|
||||||
|
|
||||||
// Exec calls tx.Exec.
|
// Exec calls tx.Exec.
|
||||||
func (tx *txDriver) Exec(ctx context.Context, query string, args, v interface{}) error {
|
func (tx *txDriver) Exec(ctx context.Context, query string, args, v any) error {
|
||||||
return tx.tx.Exec(ctx, query, args, v)
|
return tx.tx.Exec(ctx, query, args, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query calls tx.Query.
|
// Query calls tx.Query.
|
||||||
func (tx *txDriver) Query(ctx context.Context, query string, args, v interface{}) error {
|
func (tx *txDriver) Query(ctx context.Context, query string, args, v any) error {
|
||||||
return tx.tx.Query(ctx, query, args, v)
|
return tx.tx.Query(ctx, query, args, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
101
ent/user.go
101
ent/user.go
|
|
@ -1,14 +1,15 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"goweb/ent/user"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"entgo.io/ent"
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// User is the model entity for the User schema.
|
// User is the model entity for the User schema.
|
||||||
|
|
@ -22,11 +23,16 @@ type User struct {
|
||||||
Email string `json:"email,omitempty"`
|
Email string `json:"email,omitempty"`
|
||||||
// Password holds the value of the "password" field.
|
// Password holds the value of the "password" field.
|
||||||
Password string `json:"-"`
|
Password string `json:"-"`
|
||||||
|
// Verified holds the value of the "verified" field.
|
||||||
|
Verified bool `json:"verified,omitempty"`
|
||||||
|
// Admin holds the value of the "admin" field.
|
||||||
|
Admin bool `json:"admin,omitempty"`
|
||||||
// CreatedAt holds the value of the "created_at" field.
|
// CreatedAt holds the value of the "created_at" field.
|
||||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
CreatedAt time.Time `json:"created_at,omitempty"`
|
||||||
// Edges holds the relations/edges for other nodes in the graph.
|
// Edges holds the relations/edges for other nodes in the graph.
|
||||||
// The values are being populated by the UserQuery when eager-loading is set.
|
// The values are being populated by the UserQuery when eager-loading is set.
|
||||||
Edges UserEdges `json:"edges"`
|
Edges UserEdges `json:"edges"`
|
||||||
|
selectValues sql.SelectValues
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserEdges holds the relations/edges for other nodes in the graph.
|
// UserEdges holds the relations/edges for other nodes in the graph.
|
||||||
|
|
@ -48,10 +54,12 @@ func (e UserEdges) OwnerOrErr() ([]*PasswordToken, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// scanValues returns the types for scanning values from sql.Rows.
|
// scanValues returns the types for scanning values from sql.Rows.
|
||||||
func (*User) scanValues(columns []string) ([]interface{}, error) {
|
func (*User) scanValues(columns []string) ([]any, error) {
|
||||||
values := make([]interface{}, len(columns))
|
values := make([]any, len(columns))
|
||||||
for i := range columns {
|
for i := range columns {
|
||||||
switch columns[i] {
|
switch columns[i] {
|
||||||
|
case user.FieldVerified, user.FieldAdmin:
|
||||||
|
values[i] = new(sql.NullBool)
|
||||||
case user.FieldID:
|
case user.FieldID:
|
||||||
values[i] = new(sql.NullInt64)
|
values[i] = new(sql.NullInt64)
|
||||||
case user.FieldName, user.FieldEmail, user.FieldPassword:
|
case user.FieldName, user.FieldEmail, user.FieldPassword:
|
||||||
|
|
@ -59,7 +67,7 @@ func (*User) scanValues(columns []string) ([]interface{}, error) {
|
||||||
case user.FieldCreatedAt:
|
case user.FieldCreatedAt:
|
||||||
values[i] = new(sql.NullTime)
|
values[i] = new(sql.NullTime)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unexpected column %q for type User", columns[i])
|
values[i] = new(sql.UnknownType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return values, nil
|
return values, nil
|
||||||
|
|
@ -67,7 +75,7 @@ func (*User) scanValues(columns []string) ([]interface{}, error) {
|
||||||
|
|
||||||
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
||||||
// to the User fields.
|
// to the User fields.
|
||||||
func (u *User) assignValues(columns []string, values []interface{}) error {
|
func (_m *User) assignValues(columns []string, values []any) error {
|
||||||
if m, n := len(values), len(columns); m < n {
|
if m, n := len(values), len(columns); m < n {
|
||||||
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
||||||
}
|
}
|
||||||
|
|
@ -78,80 +86,103 @@ func (u *User) assignValues(columns []string, values []interface{}) error {
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unexpected type %T for field id", value)
|
return fmt.Errorf("unexpected type %T for field id", value)
|
||||||
}
|
}
|
||||||
u.ID = int(value.Int64)
|
_m.ID = int(value.Int64)
|
||||||
case user.FieldName:
|
case user.FieldName:
|
||||||
if value, ok := values[i].(*sql.NullString); !ok {
|
if value, ok := values[i].(*sql.NullString); !ok {
|
||||||
return fmt.Errorf("unexpected type %T for field name", values[i])
|
return fmt.Errorf("unexpected type %T for field name", values[i])
|
||||||
} else if value.Valid {
|
} else if value.Valid {
|
||||||
u.Name = value.String
|
_m.Name = value.String
|
||||||
}
|
}
|
||||||
case user.FieldEmail:
|
case user.FieldEmail:
|
||||||
if value, ok := values[i].(*sql.NullString); !ok {
|
if value, ok := values[i].(*sql.NullString); !ok {
|
||||||
return fmt.Errorf("unexpected type %T for field email", values[i])
|
return fmt.Errorf("unexpected type %T for field email", values[i])
|
||||||
} else if value.Valid {
|
} else if value.Valid {
|
||||||
u.Email = value.String
|
_m.Email = value.String
|
||||||
}
|
}
|
||||||
case user.FieldPassword:
|
case user.FieldPassword:
|
||||||
if value, ok := values[i].(*sql.NullString); !ok {
|
if value, ok := values[i].(*sql.NullString); !ok {
|
||||||
return fmt.Errorf("unexpected type %T for field password", values[i])
|
return fmt.Errorf("unexpected type %T for field password", values[i])
|
||||||
} else if value.Valid {
|
} else if value.Valid {
|
||||||
u.Password = value.String
|
_m.Password = value.String
|
||||||
|
}
|
||||||
|
case user.FieldVerified:
|
||||||
|
if value, ok := values[i].(*sql.NullBool); !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field verified", values[i])
|
||||||
|
} else if value.Valid {
|
||||||
|
_m.Verified = value.Bool
|
||||||
|
}
|
||||||
|
case user.FieldAdmin:
|
||||||
|
if value, ok := values[i].(*sql.NullBool); !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field admin", values[i])
|
||||||
|
} else if value.Valid {
|
||||||
|
_m.Admin = value.Bool
|
||||||
}
|
}
|
||||||
case user.FieldCreatedAt:
|
case user.FieldCreatedAt:
|
||||||
if value, ok := values[i].(*sql.NullTime); !ok {
|
if value, ok := values[i].(*sql.NullTime); !ok {
|
||||||
return fmt.Errorf("unexpected type %T for field created_at", values[i])
|
return fmt.Errorf("unexpected type %T for field created_at", values[i])
|
||||||
} else if value.Valid {
|
} else if value.Valid {
|
||||||
u.CreatedAt = value.Time
|
_m.CreatedAt = value.Time
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
_m.selectValues.Set(columns[i], values[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Value returns the ent.Value that was dynamically selected and assigned to the User.
|
||||||
|
// This includes values selected through modifiers, order, etc.
|
||||||
|
func (_m *User) Value(name string) (ent.Value, error) {
|
||||||
|
return _m.selectValues.Get(name)
|
||||||
|
}
|
||||||
|
|
||||||
// QueryOwner queries the "owner" edge of the User entity.
|
// QueryOwner queries the "owner" edge of the User entity.
|
||||||
func (u *User) QueryOwner() *PasswordTokenQuery {
|
func (_m *User) QueryOwner() *PasswordTokenQuery {
|
||||||
return (&UserClient{config: u.config}).QueryOwner(u)
|
return NewUserClient(_m.config).QueryOwner(_m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update returns a builder for updating this User.
|
// Update returns a builder for updating this User.
|
||||||
// Note that you need to call User.Unwrap() before calling this method if this User
|
// Note that you need to call User.Unwrap() before calling this method if this User
|
||||||
// was returned from a transaction, and the transaction was committed or rolled back.
|
// was returned from a transaction, and the transaction was committed or rolled back.
|
||||||
func (u *User) Update() *UserUpdateOne {
|
func (_m *User) Update() *UserUpdateOne {
|
||||||
return (&UserClient{config: u.config}).UpdateOne(u)
|
return NewUserClient(_m.config).UpdateOne(_m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unwrap unwraps the User entity that was returned from a transaction after it was closed,
|
// Unwrap unwraps the User entity that was returned from a transaction after it was closed,
|
||||||
// so that all future queries will be executed through the driver which created the transaction.
|
// so that all future queries will be executed through the driver which created the transaction.
|
||||||
func (u *User) Unwrap() *User {
|
func (_m *User) Unwrap() *User {
|
||||||
tx, ok := u.config.driver.(*txDriver)
|
_tx, ok := _m.config.driver.(*txDriver)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("ent: User is not a transactional entity")
|
panic("ent: User is not a transactional entity")
|
||||||
}
|
}
|
||||||
u.config.driver = tx.drv
|
_m.config.driver = _tx.drv
|
||||||
return u
|
return _m
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements the fmt.Stringer.
|
// String implements the fmt.Stringer.
|
||||||
func (u *User) String() string {
|
func (_m *User) String() string {
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
builder.WriteString("User(")
|
builder.WriteString("User(")
|
||||||
builder.WriteString(fmt.Sprintf("id=%v", u.ID))
|
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
|
||||||
builder.WriteString(", name=")
|
builder.WriteString("name=")
|
||||||
builder.WriteString(u.Name)
|
builder.WriteString(_m.Name)
|
||||||
builder.WriteString(", email=")
|
builder.WriteString(", ")
|
||||||
builder.WriteString(u.Email)
|
builder.WriteString("email=")
|
||||||
builder.WriteString(", password=<sensitive>")
|
builder.WriteString(_m.Email)
|
||||||
builder.WriteString(", created_at=")
|
builder.WriteString(", ")
|
||||||
builder.WriteString(u.CreatedAt.Format(time.ANSIC))
|
builder.WriteString("password=<sensitive>")
|
||||||
|
builder.WriteString(", ")
|
||||||
|
builder.WriteString("verified=")
|
||||||
|
builder.WriteString(fmt.Sprintf("%v", _m.Verified))
|
||||||
|
builder.WriteString(", ")
|
||||||
|
builder.WriteString("admin=")
|
||||||
|
builder.WriteString(fmt.Sprintf("%v", _m.Admin))
|
||||||
|
builder.WriteString(", ")
|
||||||
|
builder.WriteString("created_at=")
|
||||||
|
builder.WriteString(_m.CreatedAt.Format(time.ANSIC))
|
||||||
builder.WriteByte(')')
|
builder.WriteByte(')')
|
||||||
return builder.String()
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Users is a parsable slice of User.
|
// Users is a parsable slice of User.
|
||||||
type Users []*User
|
type Users []*User
|
||||||
|
|
||||||
func (u Users) config(cfg config) {
|
|
||||||
for _i := range u {
|
|
||||||
u[_i].config = cfg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package user
|
package user
|
||||||
|
|
||||||
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"entgo.io/ent"
|
"entgo.io/ent"
|
||||||
|
"entgo.io/ent/dialect/sql"
|
||||||
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -19,6 +21,10 @@ const (
|
||||||
FieldEmail = "email"
|
FieldEmail = "email"
|
||||||
// FieldPassword holds the string denoting the password field in the database.
|
// FieldPassword holds the string denoting the password field in the database.
|
||||||
FieldPassword = "password"
|
FieldPassword = "password"
|
||||||
|
// FieldVerified holds the string denoting the verified field in the database.
|
||||||
|
FieldVerified = "verified"
|
||||||
|
// FieldAdmin holds the string denoting the admin field in the database.
|
||||||
|
FieldAdmin = "admin"
|
||||||
// FieldCreatedAt holds the string denoting the created_at field in the database.
|
// FieldCreatedAt holds the string denoting the created_at field in the database.
|
||||||
FieldCreatedAt = "created_at"
|
FieldCreatedAt = "created_at"
|
||||||
// EdgeOwner holds the string denoting the owner edge name in mutations.
|
// EdgeOwner holds the string denoting the owner edge name in mutations.
|
||||||
|
|
@ -31,7 +37,7 @@ const (
|
||||||
// It exists in this package in order to avoid circular dependency with the "passwordtoken" package.
|
// It exists in this package in order to avoid circular dependency with the "passwordtoken" package.
|
||||||
OwnerInverseTable = "password_tokens"
|
OwnerInverseTable = "password_tokens"
|
||||||
// OwnerColumn is the table column denoting the owner relation/edge.
|
// OwnerColumn is the table column denoting the owner relation/edge.
|
||||||
OwnerColumn = "password_token_user"
|
OwnerColumn = "user_id"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Columns holds all SQL columns for user fields.
|
// Columns holds all SQL columns for user fields.
|
||||||
|
|
@ -40,6 +46,8 @@ var Columns = []string{
|
||||||
FieldName,
|
FieldName,
|
||||||
FieldEmail,
|
FieldEmail,
|
||||||
FieldPassword,
|
FieldPassword,
|
||||||
|
FieldVerified,
|
||||||
|
FieldAdmin,
|
||||||
FieldCreatedAt,
|
FieldCreatedAt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,8 +65,7 @@ func ValidColumn(column string) bool {
|
||||||
// package on the initialization of the application. Therefore,
|
// package on the initialization of the application. Therefore,
|
||||||
// it should be imported in the main as follows:
|
// it should be imported in the main as follows:
|
||||||
//
|
//
|
||||||
// import _ "goweb/ent/runtime"
|
// import _ "github.com/mikestefanello/pagoda/ent/runtime"
|
||||||
//
|
|
||||||
var (
|
var (
|
||||||
Hooks [1]ent.Hook
|
Hooks [1]ent.Hook
|
||||||
// NameValidator is a validator for the "name" field. It is called by the builders before save.
|
// NameValidator is a validator for the "name" field. It is called by the builders before save.
|
||||||
|
|
@ -67,6 +74,69 @@ var (
|
||||||
EmailValidator func(string) error
|
EmailValidator func(string) error
|
||||||
// PasswordValidator is a validator for the "password" field. It is called by the builders before save.
|
// PasswordValidator is a validator for the "password" field. It is called by the builders before save.
|
||||||
PasswordValidator func(string) error
|
PasswordValidator func(string) error
|
||||||
|
// DefaultVerified holds the default value on creation for the "verified" field.
|
||||||
|
DefaultVerified bool
|
||||||
|
// DefaultAdmin holds the default value on creation for the "admin" field.
|
||||||
|
DefaultAdmin bool
|
||||||
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
|
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
|
||||||
DefaultCreatedAt func() time.Time
|
DefaultCreatedAt func() time.Time
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// OrderOption defines the ordering options for the User queries.
|
||||||
|
type OrderOption func(*sql.Selector)
|
||||||
|
|
||||||
|
// ByID orders the results by the id field.
|
||||||
|
func ByID(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldID, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByName orders the results by the name field.
|
||||||
|
func ByName(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldName, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByEmail orders the results by the email field.
|
||||||
|
func ByEmail(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldEmail, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByPassword orders the results by the password field.
|
||||||
|
func ByPassword(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldPassword, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByVerified orders the results by the verified field.
|
||||||
|
func ByVerified(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldVerified, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByAdmin orders the results by the admin field.
|
||||||
|
func ByAdmin(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldAdmin, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByCreatedAt orders the results by the created_at field.
|
||||||
|
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByOwnerCount orders the results by owner count.
|
||||||
|
func ByOwnerCount(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return func(s *sql.Selector) {
|
||||||
|
sqlgraph.OrderByNeighborsCount(s, newOwnerStep(), opts...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ByOwner orders the results by owner terms.
|
||||||
|
func ByOwner(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
|
||||||
|
return func(s *sql.Selector) {
|
||||||
|
sqlgraph.OrderByNeighborTerms(s, newOwnerStep(), append([]sql.OrderTerm{term}, terms...)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func newOwnerStep() *sqlgraph.Step {
|
||||||
|
return sqlgraph.NewStep(
|
||||||
|
sqlgraph.From(Table, FieldID),
|
||||||
|
sqlgraph.To(OwnerInverseTable, FieldID),
|
||||||
|
sqlgraph.Edge(sqlgraph.O2M, true, OwnerTable, OwnerColumn),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,533 +1,343 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"goweb/ent/predicate"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/predicate"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ID filters vertices based on their ID field.
|
// ID filters vertices based on their ID field.
|
||||||
func ID(id int) predicate.User {
|
func ID(id int) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldEQ(FieldID, id))
|
||||||
s.Where(sql.EQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDEQ applies the EQ predicate on the ID field.
|
// IDEQ applies the EQ predicate on the ID field.
|
||||||
func IDEQ(id int) predicate.User {
|
func IDEQ(id int) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldEQ(FieldID, id))
|
||||||
s.Where(sql.EQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDNEQ applies the NEQ predicate on the ID field.
|
// IDNEQ applies the NEQ predicate on the ID field.
|
||||||
func IDNEQ(id int) predicate.User {
|
func IDNEQ(id int) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldNEQ(FieldID, id))
|
||||||
s.Where(sql.NEQ(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDIn applies the In predicate on the ID field.
|
// IDIn applies the In predicate on the ID field.
|
||||||
func IDIn(ids ...int) predicate.User {
|
func IDIn(ids ...int) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldIn(FieldID, ids...))
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(ids) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v := make([]interface{}, len(ids))
|
|
||||||
for i := range v {
|
|
||||||
v[i] = ids[i]
|
|
||||||
}
|
|
||||||
s.Where(sql.In(s.C(FieldID), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDNotIn applies the NotIn predicate on the ID field.
|
// IDNotIn applies the NotIn predicate on the ID field.
|
||||||
func IDNotIn(ids ...int) predicate.User {
|
func IDNotIn(ids ...int) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldNotIn(FieldID, ids...))
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(ids) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
v := make([]interface{}, len(ids))
|
|
||||||
for i := range v {
|
|
||||||
v[i] = ids[i]
|
|
||||||
}
|
|
||||||
s.Where(sql.NotIn(s.C(FieldID), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDGT applies the GT predicate on the ID field.
|
// IDGT applies the GT predicate on the ID field.
|
||||||
func IDGT(id int) predicate.User {
|
func IDGT(id int) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldGT(FieldID, id))
|
||||||
s.Where(sql.GT(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDGTE applies the GTE predicate on the ID field.
|
// IDGTE applies the GTE predicate on the ID field.
|
||||||
func IDGTE(id int) predicate.User {
|
func IDGTE(id int) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldGTE(FieldID, id))
|
||||||
s.Where(sql.GTE(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDLT applies the LT predicate on the ID field.
|
// IDLT applies the LT predicate on the ID field.
|
||||||
func IDLT(id int) predicate.User {
|
func IDLT(id int) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldLT(FieldID, id))
|
||||||
s.Where(sql.LT(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IDLTE applies the LTE predicate on the ID field.
|
// IDLTE applies the LTE predicate on the ID field.
|
||||||
func IDLTE(id int) predicate.User {
|
func IDLTE(id int) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldLTE(FieldID, id))
|
||||||
s.Where(sql.LTE(s.C(FieldID), id))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name applies equality check predicate on the "name" field. It's identical to NameEQ.
|
// Name applies equality check predicate on the "name" field. It's identical to NameEQ.
|
||||||
func Name(v string) predicate.User {
|
func Name(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldEQ(FieldName, v))
|
||||||
s.Where(sql.EQ(s.C(FieldName), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Email applies equality check predicate on the "email" field. It's identical to EmailEQ.
|
// Email applies equality check predicate on the "email" field. It's identical to EmailEQ.
|
||||||
func Email(v string) predicate.User {
|
func Email(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldEQ(FieldEmail, v))
|
||||||
s.Where(sql.EQ(s.C(FieldEmail), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Password applies equality check predicate on the "password" field. It's identical to PasswordEQ.
|
// Password applies equality check predicate on the "password" field. It's identical to PasswordEQ.
|
||||||
func Password(v string) predicate.User {
|
func Password(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldEQ(FieldPassword, v))
|
||||||
s.Where(sql.EQ(s.C(FieldPassword), v))
|
}
|
||||||
})
|
|
||||||
|
// Verified applies equality check predicate on the "verified" field. It's identical to VerifiedEQ.
|
||||||
|
func Verified(v bool) predicate.User {
|
||||||
|
return predicate.User(sql.FieldEQ(FieldVerified, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Admin applies equality check predicate on the "admin" field. It's identical to AdminEQ.
|
||||||
|
func Admin(v bool) predicate.User {
|
||||||
|
return predicate.User(sql.FieldEQ(FieldAdmin, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ.
|
||||||
func CreatedAt(v time.Time) predicate.User {
|
func CreatedAt(v time.Time) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameEQ applies the EQ predicate on the "name" field.
|
// NameEQ applies the EQ predicate on the "name" field.
|
||||||
func NameEQ(v string) predicate.User {
|
func NameEQ(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldEQ(FieldName, v))
|
||||||
s.Where(sql.EQ(s.C(FieldName), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameNEQ applies the NEQ predicate on the "name" field.
|
// NameNEQ applies the NEQ predicate on the "name" field.
|
||||||
func NameNEQ(v string) predicate.User {
|
func NameNEQ(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldNEQ(FieldName, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldName), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameIn applies the In predicate on the "name" field.
|
// NameIn applies the In predicate on the "name" field.
|
||||||
func NameIn(vs ...string) predicate.User {
|
func NameIn(vs ...string) predicate.User {
|
||||||
v := make([]interface{}, len(vs))
|
return predicate.User(sql.FieldIn(FieldName, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.User(func(s *sql.Selector) {
|
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(v) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Where(sql.In(s.C(FieldName), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameNotIn applies the NotIn predicate on the "name" field.
|
// NameNotIn applies the NotIn predicate on the "name" field.
|
||||||
func NameNotIn(vs ...string) predicate.User {
|
func NameNotIn(vs ...string) predicate.User {
|
||||||
v := make([]interface{}, len(vs))
|
return predicate.User(sql.FieldNotIn(FieldName, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.User(func(s *sql.Selector) {
|
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(v) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Where(sql.NotIn(s.C(FieldName), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameGT applies the GT predicate on the "name" field.
|
// NameGT applies the GT predicate on the "name" field.
|
||||||
func NameGT(v string) predicate.User {
|
func NameGT(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldGT(FieldName, v))
|
||||||
s.Where(sql.GT(s.C(FieldName), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameGTE applies the GTE predicate on the "name" field.
|
// NameGTE applies the GTE predicate on the "name" field.
|
||||||
func NameGTE(v string) predicate.User {
|
func NameGTE(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldGTE(FieldName, v))
|
||||||
s.Where(sql.GTE(s.C(FieldName), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameLT applies the LT predicate on the "name" field.
|
// NameLT applies the LT predicate on the "name" field.
|
||||||
func NameLT(v string) predicate.User {
|
func NameLT(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldLT(FieldName, v))
|
||||||
s.Where(sql.LT(s.C(FieldName), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameLTE applies the LTE predicate on the "name" field.
|
// NameLTE applies the LTE predicate on the "name" field.
|
||||||
func NameLTE(v string) predicate.User {
|
func NameLTE(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldLTE(FieldName, v))
|
||||||
s.Where(sql.LTE(s.C(FieldName), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameContains applies the Contains predicate on the "name" field.
|
// NameContains applies the Contains predicate on the "name" field.
|
||||||
func NameContains(v string) predicate.User {
|
func NameContains(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldContains(FieldName, v))
|
||||||
s.Where(sql.Contains(s.C(FieldName), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameHasPrefix applies the HasPrefix predicate on the "name" field.
|
// NameHasPrefix applies the HasPrefix predicate on the "name" field.
|
||||||
func NameHasPrefix(v string) predicate.User {
|
func NameHasPrefix(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldHasPrefix(FieldName, v))
|
||||||
s.Where(sql.HasPrefix(s.C(FieldName), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameHasSuffix applies the HasSuffix predicate on the "name" field.
|
// NameHasSuffix applies the HasSuffix predicate on the "name" field.
|
||||||
func NameHasSuffix(v string) predicate.User {
|
func NameHasSuffix(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldHasSuffix(FieldName, v))
|
||||||
s.Where(sql.HasSuffix(s.C(FieldName), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameEqualFold applies the EqualFold predicate on the "name" field.
|
// NameEqualFold applies the EqualFold predicate on the "name" field.
|
||||||
func NameEqualFold(v string) predicate.User {
|
func NameEqualFold(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldEqualFold(FieldName, v))
|
||||||
s.Where(sql.EqualFold(s.C(FieldName), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NameContainsFold applies the ContainsFold predicate on the "name" field.
|
// NameContainsFold applies the ContainsFold predicate on the "name" field.
|
||||||
func NameContainsFold(v string) predicate.User {
|
func NameContainsFold(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldContainsFold(FieldName, v))
|
||||||
s.Where(sql.ContainsFold(s.C(FieldName), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmailEQ applies the EQ predicate on the "email" field.
|
// EmailEQ applies the EQ predicate on the "email" field.
|
||||||
func EmailEQ(v string) predicate.User {
|
func EmailEQ(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldEQ(FieldEmail, v))
|
||||||
s.Where(sql.EQ(s.C(FieldEmail), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmailNEQ applies the NEQ predicate on the "email" field.
|
// EmailNEQ applies the NEQ predicate on the "email" field.
|
||||||
func EmailNEQ(v string) predicate.User {
|
func EmailNEQ(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldNEQ(FieldEmail, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldEmail), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmailIn applies the In predicate on the "email" field.
|
// EmailIn applies the In predicate on the "email" field.
|
||||||
func EmailIn(vs ...string) predicate.User {
|
func EmailIn(vs ...string) predicate.User {
|
||||||
v := make([]interface{}, len(vs))
|
return predicate.User(sql.FieldIn(FieldEmail, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.User(func(s *sql.Selector) {
|
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(v) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Where(sql.In(s.C(FieldEmail), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmailNotIn applies the NotIn predicate on the "email" field.
|
// EmailNotIn applies the NotIn predicate on the "email" field.
|
||||||
func EmailNotIn(vs ...string) predicate.User {
|
func EmailNotIn(vs ...string) predicate.User {
|
||||||
v := make([]interface{}, len(vs))
|
return predicate.User(sql.FieldNotIn(FieldEmail, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.User(func(s *sql.Selector) {
|
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(v) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Where(sql.NotIn(s.C(FieldEmail), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmailGT applies the GT predicate on the "email" field.
|
// EmailGT applies the GT predicate on the "email" field.
|
||||||
func EmailGT(v string) predicate.User {
|
func EmailGT(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldGT(FieldEmail, v))
|
||||||
s.Where(sql.GT(s.C(FieldEmail), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmailGTE applies the GTE predicate on the "email" field.
|
// EmailGTE applies the GTE predicate on the "email" field.
|
||||||
func EmailGTE(v string) predicate.User {
|
func EmailGTE(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldGTE(FieldEmail, v))
|
||||||
s.Where(sql.GTE(s.C(FieldEmail), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmailLT applies the LT predicate on the "email" field.
|
// EmailLT applies the LT predicate on the "email" field.
|
||||||
func EmailLT(v string) predicate.User {
|
func EmailLT(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldLT(FieldEmail, v))
|
||||||
s.Where(sql.LT(s.C(FieldEmail), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmailLTE applies the LTE predicate on the "email" field.
|
// EmailLTE applies the LTE predicate on the "email" field.
|
||||||
func EmailLTE(v string) predicate.User {
|
func EmailLTE(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldLTE(FieldEmail, v))
|
||||||
s.Where(sql.LTE(s.C(FieldEmail), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmailContains applies the Contains predicate on the "email" field.
|
// EmailContains applies the Contains predicate on the "email" field.
|
||||||
func EmailContains(v string) predicate.User {
|
func EmailContains(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldContains(FieldEmail, v))
|
||||||
s.Where(sql.Contains(s.C(FieldEmail), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmailHasPrefix applies the HasPrefix predicate on the "email" field.
|
// EmailHasPrefix applies the HasPrefix predicate on the "email" field.
|
||||||
func EmailHasPrefix(v string) predicate.User {
|
func EmailHasPrefix(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldHasPrefix(FieldEmail, v))
|
||||||
s.Where(sql.HasPrefix(s.C(FieldEmail), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmailHasSuffix applies the HasSuffix predicate on the "email" field.
|
// EmailHasSuffix applies the HasSuffix predicate on the "email" field.
|
||||||
func EmailHasSuffix(v string) predicate.User {
|
func EmailHasSuffix(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldHasSuffix(FieldEmail, v))
|
||||||
s.Where(sql.HasSuffix(s.C(FieldEmail), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmailEqualFold applies the EqualFold predicate on the "email" field.
|
// EmailEqualFold applies the EqualFold predicate on the "email" field.
|
||||||
func EmailEqualFold(v string) predicate.User {
|
func EmailEqualFold(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldEqualFold(FieldEmail, v))
|
||||||
s.Where(sql.EqualFold(s.C(FieldEmail), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmailContainsFold applies the ContainsFold predicate on the "email" field.
|
// EmailContainsFold applies the ContainsFold predicate on the "email" field.
|
||||||
func EmailContainsFold(v string) predicate.User {
|
func EmailContainsFold(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldContainsFold(FieldEmail, v))
|
||||||
s.Where(sql.ContainsFold(s.C(FieldEmail), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordEQ applies the EQ predicate on the "password" field.
|
// PasswordEQ applies the EQ predicate on the "password" field.
|
||||||
func PasswordEQ(v string) predicate.User {
|
func PasswordEQ(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldEQ(FieldPassword, v))
|
||||||
s.Where(sql.EQ(s.C(FieldPassword), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordNEQ applies the NEQ predicate on the "password" field.
|
// PasswordNEQ applies the NEQ predicate on the "password" field.
|
||||||
func PasswordNEQ(v string) predicate.User {
|
func PasswordNEQ(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldNEQ(FieldPassword, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldPassword), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordIn applies the In predicate on the "password" field.
|
// PasswordIn applies the In predicate on the "password" field.
|
||||||
func PasswordIn(vs ...string) predicate.User {
|
func PasswordIn(vs ...string) predicate.User {
|
||||||
v := make([]interface{}, len(vs))
|
return predicate.User(sql.FieldIn(FieldPassword, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.User(func(s *sql.Selector) {
|
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(v) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Where(sql.In(s.C(FieldPassword), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordNotIn applies the NotIn predicate on the "password" field.
|
// PasswordNotIn applies the NotIn predicate on the "password" field.
|
||||||
func PasswordNotIn(vs ...string) predicate.User {
|
func PasswordNotIn(vs ...string) predicate.User {
|
||||||
v := make([]interface{}, len(vs))
|
return predicate.User(sql.FieldNotIn(FieldPassword, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.User(func(s *sql.Selector) {
|
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(v) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Where(sql.NotIn(s.C(FieldPassword), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordGT applies the GT predicate on the "password" field.
|
// PasswordGT applies the GT predicate on the "password" field.
|
||||||
func PasswordGT(v string) predicate.User {
|
func PasswordGT(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldGT(FieldPassword, v))
|
||||||
s.Where(sql.GT(s.C(FieldPassword), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordGTE applies the GTE predicate on the "password" field.
|
// PasswordGTE applies the GTE predicate on the "password" field.
|
||||||
func PasswordGTE(v string) predicate.User {
|
func PasswordGTE(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldGTE(FieldPassword, v))
|
||||||
s.Where(sql.GTE(s.C(FieldPassword), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordLT applies the LT predicate on the "password" field.
|
// PasswordLT applies the LT predicate on the "password" field.
|
||||||
func PasswordLT(v string) predicate.User {
|
func PasswordLT(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldLT(FieldPassword, v))
|
||||||
s.Where(sql.LT(s.C(FieldPassword), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordLTE applies the LTE predicate on the "password" field.
|
// PasswordLTE applies the LTE predicate on the "password" field.
|
||||||
func PasswordLTE(v string) predicate.User {
|
func PasswordLTE(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldLTE(FieldPassword, v))
|
||||||
s.Where(sql.LTE(s.C(FieldPassword), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordContains applies the Contains predicate on the "password" field.
|
// PasswordContains applies the Contains predicate on the "password" field.
|
||||||
func PasswordContains(v string) predicate.User {
|
func PasswordContains(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldContains(FieldPassword, v))
|
||||||
s.Where(sql.Contains(s.C(FieldPassword), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordHasPrefix applies the HasPrefix predicate on the "password" field.
|
// PasswordHasPrefix applies the HasPrefix predicate on the "password" field.
|
||||||
func PasswordHasPrefix(v string) predicate.User {
|
func PasswordHasPrefix(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldHasPrefix(FieldPassword, v))
|
||||||
s.Where(sql.HasPrefix(s.C(FieldPassword), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordHasSuffix applies the HasSuffix predicate on the "password" field.
|
// PasswordHasSuffix applies the HasSuffix predicate on the "password" field.
|
||||||
func PasswordHasSuffix(v string) predicate.User {
|
func PasswordHasSuffix(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldHasSuffix(FieldPassword, v))
|
||||||
s.Where(sql.HasSuffix(s.C(FieldPassword), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordEqualFold applies the EqualFold predicate on the "password" field.
|
// PasswordEqualFold applies the EqualFold predicate on the "password" field.
|
||||||
func PasswordEqualFold(v string) predicate.User {
|
func PasswordEqualFold(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldEqualFold(FieldPassword, v))
|
||||||
s.Where(sql.EqualFold(s.C(FieldPassword), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordContainsFold applies the ContainsFold predicate on the "password" field.
|
// PasswordContainsFold applies the ContainsFold predicate on the "password" field.
|
||||||
func PasswordContainsFold(v string) predicate.User {
|
func PasswordContainsFold(v string) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldContainsFold(FieldPassword, v))
|
||||||
s.Where(sql.ContainsFold(s.C(FieldPassword), v))
|
}
|
||||||
})
|
|
||||||
|
// VerifiedEQ applies the EQ predicate on the "verified" field.
|
||||||
|
func VerifiedEQ(v bool) predicate.User {
|
||||||
|
return predicate.User(sql.FieldEQ(FieldVerified, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifiedNEQ applies the NEQ predicate on the "verified" field.
|
||||||
|
func VerifiedNEQ(v bool) predicate.User {
|
||||||
|
return predicate.User(sql.FieldNEQ(FieldVerified, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdminEQ applies the EQ predicate on the "admin" field.
|
||||||
|
func AdminEQ(v bool) predicate.User {
|
||||||
|
return predicate.User(sql.FieldEQ(FieldAdmin, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdminNEQ applies the NEQ predicate on the "admin" field.
|
||||||
|
func AdminNEQ(v bool) predicate.User {
|
||||||
|
return predicate.User(sql.FieldNEQ(FieldAdmin, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||||
func CreatedAtEQ(v time.Time) predicate.User {
|
func CreatedAtEQ(v time.Time) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.EQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
|
||||||
func CreatedAtNEQ(v time.Time) predicate.User {
|
func CreatedAtNEQ(v time.Time) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldNEQ(FieldCreatedAt, v))
|
||||||
s.Where(sql.NEQ(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtIn applies the In predicate on the "created_at" field.
|
// CreatedAtIn applies the In predicate on the "created_at" field.
|
||||||
func CreatedAtIn(vs ...time.Time) predicate.User {
|
func CreatedAtIn(vs ...time.Time) predicate.User {
|
||||||
v := make([]interface{}, len(vs))
|
return predicate.User(sql.FieldIn(FieldCreatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.User(func(s *sql.Selector) {
|
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(v) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Where(sql.In(s.C(FieldCreatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
|
||||||
func CreatedAtNotIn(vs ...time.Time) predicate.User {
|
func CreatedAtNotIn(vs ...time.Time) predicate.User {
|
||||||
v := make([]interface{}, len(vs))
|
return predicate.User(sql.FieldNotIn(FieldCreatedAt, vs...))
|
||||||
for i := range v {
|
|
||||||
v[i] = vs[i]
|
|
||||||
}
|
|
||||||
return predicate.User(func(s *sql.Selector) {
|
|
||||||
// if not arguments were provided, append the FALSE constants,
|
|
||||||
// since we can't apply "IN ()". This will make this predicate falsy.
|
|
||||||
if len(v) == 0 {
|
|
||||||
s.Where(sql.False())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Where(sql.NotIn(s.C(FieldCreatedAt), v...))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
// CreatedAtGT applies the GT predicate on the "created_at" field.
|
||||||
func CreatedAtGT(v time.Time) predicate.User {
|
func CreatedAtGT(v time.Time) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldGT(FieldCreatedAt, v))
|
||||||
s.Where(sql.GT(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
|
||||||
func CreatedAtGTE(v time.Time) predicate.User {
|
func CreatedAtGTE(v time.Time) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldGTE(FieldCreatedAt, v))
|
||||||
s.Where(sql.GTE(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
// CreatedAtLT applies the LT predicate on the "created_at" field.
|
||||||
func CreatedAtLT(v time.Time) predicate.User {
|
func CreatedAtLT(v time.Time) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldLT(FieldCreatedAt, v))
|
||||||
s.Where(sql.LT(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
|
||||||
func CreatedAtLTE(v time.Time) predicate.User {
|
func CreatedAtLTE(v time.Time) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.FieldLTE(FieldCreatedAt, v))
|
||||||
s.Where(sql.LTE(s.C(FieldCreatedAt), v))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasOwner applies the HasEdge predicate on the "owner" edge.
|
// HasOwner applies the HasEdge predicate on the "owner" edge.
|
||||||
|
|
@ -535,7 +345,6 @@ func HasOwner() predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := sqlgraph.NewStep(
|
||||||
sqlgraph.From(Table, FieldID),
|
sqlgraph.From(Table, FieldID),
|
||||||
sqlgraph.To(OwnerTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.O2M, true, OwnerTable, OwnerColumn),
|
sqlgraph.Edge(sqlgraph.O2M, true, OwnerTable, OwnerColumn),
|
||||||
)
|
)
|
||||||
sqlgraph.HasNeighbors(s, step)
|
sqlgraph.HasNeighbors(s, step)
|
||||||
|
|
@ -545,11 +354,7 @@ func HasOwner() predicate.User {
|
||||||
// HasOwnerWith applies the HasEdge predicate on the "owner" edge with a given conditions (other predicates).
|
// HasOwnerWith applies the HasEdge predicate on the "owner" edge with a given conditions (other predicates).
|
||||||
func HasOwnerWith(preds ...predicate.PasswordToken) predicate.User {
|
func HasOwnerWith(preds ...predicate.PasswordToken) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(func(s *sql.Selector) {
|
||||||
step := sqlgraph.NewStep(
|
step := newOwnerStep()
|
||||||
sqlgraph.From(Table, FieldID),
|
|
||||||
sqlgraph.To(OwnerInverseTable, FieldID),
|
|
||||||
sqlgraph.Edge(sqlgraph.O2M, true, OwnerTable, OwnerColumn),
|
|
||||||
)
|
|
||||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||||
for _, p := range preds {
|
for _, p := range preds {
|
||||||
p(s)
|
p(s)
|
||||||
|
|
@ -560,32 +365,15 @@ func HasOwnerWith(preds ...predicate.PasswordToken) predicate.User {
|
||||||
|
|
||||||
// And groups predicates with the AND operator between them.
|
// And groups predicates with the AND operator between them.
|
||||||
func And(predicates ...predicate.User) predicate.User {
|
func And(predicates ...predicate.User) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.AndPredicates(predicates...))
|
||||||
s1 := s.Clone().SetP(nil)
|
|
||||||
for _, p := range predicates {
|
|
||||||
p(s1)
|
|
||||||
}
|
|
||||||
s.Where(s1.P())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Or groups predicates with the OR operator between them.
|
// Or groups predicates with the OR operator between them.
|
||||||
func Or(predicates ...predicate.User) predicate.User {
|
func Or(predicates ...predicate.User) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.OrPredicates(predicates...))
|
||||||
s1 := s.Clone().SetP(nil)
|
|
||||||
for i, p := range predicates {
|
|
||||||
if i > 0 {
|
|
||||||
s1.Or()
|
|
||||||
}
|
|
||||||
p(s1)
|
|
||||||
}
|
|
||||||
s.Where(s1.P())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not applies the not operator on the given predicate.
|
// Not applies the not operator on the given predicate.
|
||||||
func Not(p predicate.User) predicate.User {
|
func Not(p predicate.User) predicate.User {
|
||||||
return predicate.User(func(s *sql.Selector) {
|
return predicate.User(sql.NotPredicates(p))
|
||||||
p(s.Not())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
|
|
@ -6,12 +6,12 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"goweb/ent/passwordtoken"
|
|
||||||
"goweb/ent/user"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
"entgo.io/ent/schema/field"
|
"entgo.io/ent/schema/field"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/passwordtoken"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UserCreate is the builder for creating a User entity.
|
// UserCreate is the builder for creating a User entity.
|
||||||
|
|
@ -22,104 +22,96 @@ type UserCreate struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetName sets the "name" field.
|
// SetName sets the "name" field.
|
||||||
func (uc *UserCreate) SetName(s string) *UserCreate {
|
func (_c *UserCreate) SetName(v string) *UserCreate {
|
||||||
uc.mutation.SetName(s)
|
_c.mutation.SetName(v)
|
||||||
return uc
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetEmail sets the "email" field.
|
// SetEmail sets the "email" field.
|
||||||
func (uc *UserCreate) SetEmail(s string) *UserCreate {
|
func (_c *UserCreate) SetEmail(v string) *UserCreate {
|
||||||
uc.mutation.SetEmail(s)
|
_c.mutation.SetEmail(v)
|
||||||
return uc
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPassword sets the "password" field.
|
// SetPassword sets the "password" field.
|
||||||
func (uc *UserCreate) SetPassword(s string) *UserCreate {
|
func (_c *UserCreate) SetPassword(v string) *UserCreate {
|
||||||
uc.mutation.SetPassword(s)
|
_c.mutation.SetPassword(v)
|
||||||
return uc
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetVerified sets the "verified" field.
|
||||||
|
func (_c *UserCreate) SetVerified(v bool) *UserCreate {
|
||||||
|
_c.mutation.SetVerified(v)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableVerified sets the "verified" field if the given value is not nil.
|
||||||
|
func (_c *UserCreate) SetNillableVerified(v *bool) *UserCreate {
|
||||||
|
if v != nil {
|
||||||
|
_c.SetVerified(*v)
|
||||||
|
}
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAdmin sets the "admin" field.
|
||||||
|
func (_c *UserCreate) SetAdmin(v bool) *UserCreate {
|
||||||
|
_c.mutation.SetAdmin(v)
|
||||||
|
return _c
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableAdmin sets the "admin" field if the given value is not nil.
|
||||||
|
func (_c *UserCreate) SetNillableAdmin(v *bool) *UserCreate {
|
||||||
|
if v != nil {
|
||||||
|
_c.SetAdmin(*v)
|
||||||
|
}
|
||||||
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCreatedAt sets the "created_at" field.
|
// SetCreatedAt sets the "created_at" field.
|
||||||
func (uc *UserCreate) SetCreatedAt(t time.Time) *UserCreate {
|
func (_c *UserCreate) SetCreatedAt(v time.Time) *UserCreate {
|
||||||
uc.mutation.SetCreatedAt(t)
|
_c.mutation.SetCreatedAt(v)
|
||||||
return uc
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
|
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
|
||||||
func (uc *UserCreate) SetNillableCreatedAt(t *time.Time) *UserCreate {
|
func (_c *UserCreate) SetNillableCreatedAt(v *time.Time) *UserCreate {
|
||||||
if t != nil {
|
if v != nil {
|
||||||
uc.SetCreatedAt(*t)
|
_c.SetCreatedAt(*v)
|
||||||
}
|
}
|
||||||
return uc
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddOwnerIDs adds the "owner" edge to the PasswordToken entity by IDs.
|
// AddOwnerIDs adds the "owner" edge to the PasswordToken entity by IDs.
|
||||||
func (uc *UserCreate) AddOwnerIDs(ids ...int) *UserCreate {
|
func (_c *UserCreate) AddOwnerIDs(ids ...int) *UserCreate {
|
||||||
uc.mutation.AddOwnerIDs(ids...)
|
_c.mutation.AddOwnerIDs(ids...)
|
||||||
return uc
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddOwner adds the "owner" edges to the PasswordToken entity.
|
// AddOwner adds the "owner" edges to the PasswordToken entity.
|
||||||
func (uc *UserCreate) AddOwner(p ...*PasswordToken) *UserCreate {
|
func (_c *UserCreate) AddOwner(v ...*PasswordToken) *UserCreate {
|
||||||
ids := make([]int, len(p))
|
ids := make([]int, len(v))
|
||||||
for i := range p {
|
for i := range v {
|
||||||
ids[i] = p[i].ID
|
ids[i] = v[i].ID
|
||||||
}
|
}
|
||||||
return uc.AddOwnerIDs(ids...)
|
return _c.AddOwnerIDs(ids...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutation returns the UserMutation object of the builder.
|
// Mutation returns the UserMutation object of the builder.
|
||||||
func (uc *UserCreate) Mutation() *UserMutation {
|
func (_c *UserCreate) Mutation() *UserMutation {
|
||||||
return uc.mutation
|
return _c.mutation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save creates the User in the database.
|
// Save creates the User in the database.
|
||||||
func (uc *UserCreate) Save(ctx context.Context) (*User, error) {
|
func (_c *UserCreate) Save(ctx context.Context) (*User, error) {
|
||||||
var (
|
if err := _c.defaults(); err != nil {
|
||||||
err error
|
|
||||||
node *User
|
|
||||||
)
|
|
||||||
if err := uc.defaults(); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(uc.hooks) == 0 {
|
return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks)
|
||||||
if err = uc.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
node, err = uc.sqlSave(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*UserMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
if err = uc.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
uc.mutation = mutation
|
|
||||||
if node, err = uc.sqlSave(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mutation.id = &node.ID
|
|
||||||
mutation.done = true
|
|
||||||
return node, err
|
|
||||||
})
|
|
||||||
for i := len(uc.hooks) - 1; i >= 0; i-- {
|
|
||||||
if uc.hooks[i] == nil {
|
|
||||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = uc.hooks[i](mut)
|
|
||||||
}
|
|
||||||
if _, err := mut.Mutate(ctx, uc.mutation); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return node, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX calls Save and panics if Save returns an error.
|
// SaveX calls Save and panics if Save returns an error.
|
||||||
func (uc *UserCreate) SaveX(ctx context.Context) *User {
|
func (_c *UserCreate) SaveX(ctx context.Context) *User {
|
||||||
v, err := uc.Save(ctx)
|
v, err := _c.Save(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -127,119 +119,124 @@ func (uc *UserCreate) SaveX(ctx context.Context) *User {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the query.
|
// Exec executes the query.
|
||||||
func (uc *UserCreate) Exec(ctx context.Context) error {
|
func (_c *UserCreate) Exec(ctx context.Context) error {
|
||||||
_, err := uc.Save(ctx)
|
_, err := _c.Save(ctx)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (uc *UserCreate) ExecX(ctx context.Context) {
|
func (_c *UserCreate) ExecX(ctx context.Context) {
|
||||||
if err := uc.Exec(ctx); err != nil {
|
if err := _c.Exec(ctx); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaults sets the default values of the builder before save.
|
// defaults sets the default values of the builder before save.
|
||||||
func (uc *UserCreate) defaults() error {
|
func (_c *UserCreate) defaults() error {
|
||||||
if _, ok := uc.mutation.CreatedAt(); !ok {
|
if _, ok := _c.mutation.Verified(); !ok {
|
||||||
|
v := user.DefaultVerified
|
||||||
|
_c.mutation.SetVerified(v)
|
||||||
|
}
|
||||||
|
if _, ok := _c.mutation.Admin(); !ok {
|
||||||
|
v := user.DefaultAdmin
|
||||||
|
_c.mutation.SetAdmin(v)
|
||||||
|
}
|
||||||
|
if _, ok := _c.mutation.CreatedAt(); !ok {
|
||||||
if user.DefaultCreatedAt == nil {
|
if user.DefaultCreatedAt == nil {
|
||||||
return fmt.Errorf("ent: uninitialized user.DefaultCreatedAt (forgotten import ent/runtime?)")
|
return fmt.Errorf("ent: uninitialized user.DefaultCreatedAt (forgotten import ent/runtime?)")
|
||||||
}
|
}
|
||||||
v := user.DefaultCreatedAt()
|
v := user.DefaultCreatedAt()
|
||||||
uc.mutation.SetCreatedAt(v)
|
_c.mutation.SetCreatedAt(v)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// check runs all checks and user-defined validators on the builder.
|
// check runs all checks and user-defined validators on the builder.
|
||||||
func (uc *UserCreate) check() error {
|
func (_c *UserCreate) check() error {
|
||||||
if _, ok := uc.mutation.Name(); !ok {
|
if _, ok := _c.mutation.Name(); !ok {
|
||||||
return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "name"`)}
|
return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "User.name"`)}
|
||||||
}
|
}
|
||||||
if v, ok := uc.mutation.Name(); ok {
|
if v, ok := _c.mutation.Name(); ok {
|
||||||
if err := user.NameValidator(v); err != nil {
|
if err := user.NameValidator(v); err != nil {
|
||||||
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "name": %w`, err)}
|
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "User.name": %w`, err)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, ok := uc.mutation.Email(); !ok {
|
if _, ok := _c.mutation.Email(); !ok {
|
||||||
return &ValidationError{Name: "email", err: errors.New(`ent: missing required field "email"`)}
|
return &ValidationError{Name: "email", err: errors.New(`ent: missing required field "User.email"`)}
|
||||||
}
|
}
|
||||||
if v, ok := uc.mutation.Email(); ok {
|
if v, ok := _c.mutation.Email(); ok {
|
||||||
if err := user.EmailValidator(v); err != nil {
|
if err := user.EmailValidator(v); err != nil {
|
||||||
return &ValidationError{Name: "email", err: fmt.Errorf(`ent: validator failed for field "email": %w`, err)}
|
return &ValidationError{Name: "email", err: fmt.Errorf(`ent: validator failed for field "User.email": %w`, err)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, ok := uc.mutation.Password(); !ok {
|
if _, ok := _c.mutation.Password(); !ok {
|
||||||
return &ValidationError{Name: "password", err: errors.New(`ent: missing required field "password"`)}
|
return &ValidationError{Name: "password", err: errors.New(`ent: missing required field "User.password"`)}
|
||||||
}
|
}
|
||||||
if v, ok := uc.mutation.Password(); ok {
|
if v, ok := _c.mutation.Password(); ok {
|
||||||
if err := user.PasswordValidator(v); err != nil {
|
if err := user.PasswordValidator(v); err != nil {
|
||||||
return &ValidationError{Name: "password", err: fmt.Errorf(`ent: validator failed for field "password": %w`, err)}
|
return &ValidationError{Name: "password", err: fmt.Errorf(`ent: validator failed for field "User.password": %w`, err)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, ok := uc.mutation.CreatedAt(); !ok {
|
if _, ok := _c.mutation.Verified(); !ok {
|
||||||
return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "created_at"`)}
|
return &ValidationError{Name: "verified", err: errors.New(`ent: missing required field "User.verified"`)}
|
||||||
|
}
|
||||||
|
if _, ok := _c.mutation.Admin(); !ok {
|
||||||
|
return &ValidationError{Name: "admin", err: errors.New(`ent: missing required field "User.admin"`)}
|
||||||
|
}
|
||||||
|
if _, ok := _c.mutation.CreatedAt(); !ok {
|
||||||
|
return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "User.created_at"`)}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uc *UserCreate) sqlSave(ctx context.Context) (*User, error) {
|
func (_c *UserCreate) sqlSave(ctx context.Context) (*User, error) {
|
||||||
_node, _spec := uc.createSpec()
|
if err := _c.check(); err != nil {
|
||||||
if err := sqlgraph.CreateNode(ctx, uc.driver, _spec); err != nil {
|
return nil, err
|
||||||
|
}
|
||||||
|
_node, _spec := _c.createSpec()
|
||||||
|
if err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil {
|
||||||
if sqlgraph.IsConstraintError(err) {
|
if sqlgraph.IsConstraintError(err) {
|
||||||
err = &ConstraintError{err.Error(), err}
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
id := _spec.ID.Value.(int64)
|
id := _spec.ID.Value.(int64)
|
||||||
_node.ID = int(id)
|
_node.ID = int(id)
|
||||||
|
_c.mutation.id = &_node.ID
|
||||||
|
_c.mutation.done = true
|
||||||
return _node, nil
|
return _node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
|
func (_c *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
|
||||||
var (
|
var (
|
||||||
_node = &User{config: uc.config}
|
_node = &User{config: _c.config}
|
||||||
_spec = &sqlgraph.CreateSpec{
|
_spec = sqlgraph.NewCreateSpec(user.Table, sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt))
|
||||||
Table: user.Table,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: user.FieldID,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
if value, ok := uc.mutation.Name(); ok {
|
if value, ok := _c.mutation.Name(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(user.FieldName, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
|
||||||
Value: value,
|
|
||||||
Column: user.FieldName,
|
|
||||||
})
|
|
||||||
_node.Name = value
|
_node.Name = value
|
||||||
}
|
}
|
||||||
if value, ok := uc.mutation.Email(); ok {
|
if value, ok := _c.mutation.Email(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(user.FieldEmail, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
|
||||||
Value: value,
|
|
||||||
Column: user.FieldEmail,
|
|
||||||
})
|
|
||||||
_node.Email = value
|
_node.Email = value
|
||||||
}
|
}
|
||||||
if value, ok := uc.mutation.Password(); ok {
|
if value, ok := _c.mutation.Password(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(user.FieldPassword, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
|
||||||
Value: value,
|
|
||||||
Column: user.FieldPassword,
|
|
||||||
})
|
|
||||||
_node.Password = value
|
_node.Password = value
|
||||||
}
|
}
|
||||||
if value, ok := uc.mutation.CreatedAt(); ok {
|
if value, ok := _c.mutation.Verified(); ok {
|
||||||
_spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{
|
_spec.SetField(user.FieldVerified, field.TypeBool, value)
|
||||||
Type: field.TypeTime,
|
_node.Verified = value
|
||||||
Value: value,
|
}
|
||||||
Column: user.FieldCreatedAt,
|
if value, ok := _c.mutation.Admin(); ok {
|
||||||
})
|
_spec.SetField(user.FieldAdmin, field.TypeBool, value)
|
||||||
|
_node.Admin = value
|
||||||
|
}
|
||||||
|
if value, ok := _c.mutation.CreatedAt(); ok {
|
||||||
|
_spec.SetField(user.FieldCreatedAt, field.TypeTime, value)
|
||||||
_node.CreatedAt = value
|
_node.CreatedAt = value
|
||||||
}
|
}
|
||||||
if nodes := uc.mutation.OwnerIDs(); len(nodes) > 0 {
|
if nodes := _c.mutation.OwnerIDs(); len(nodes) > 0 {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.O2M,
|
||||||
Inverse: true,
|
Inverse: true,
|
||||||
|
|
@ -247,10 +244,7 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
|
||||||
Columns: []string{user.OwnerColumn},
|
Columns: []string{user.OwnerColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(passwordtoken.FieldID, field.TypeInt),
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: passwordtoken.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
|
|
@ -264,17 +258,21 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
|
||||||
// UserCreateBulk is the builder for creating many User entities in bulk.
|
// UserCreateBulk is the builder for creating many User entities in bulk.
|
||||||
type UserCreateBulk struct {
|
type UserCreateBulk struct {
|
||||||
config
|
config
|
||||||
|
err error
|
||||||
builders []*UserCreate
|
builders []*UserCreate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save creates the User entities in the database.
|
// Save creates the User entities in the database.
|
||||||
func (ucb *UserCreateBulk) Save(ctx context.Context) ([]*User, error) {
|
func (_c *UserCreateBulk) Save(ctx context.Context) ([]*User, error) {
|
||||||
specs := make([]*sqlgraph.CreateSpec, len(ucb.builders))
|
if _c.err != nil {
|
||||||
nodes := make([]*User, len(ucb.builders))
|
return nil, _c.err
|
||||||
mutators := make([]Mutator, len(ucb.builders))
|
}
|
||||||
for i := range ucb.builders {
|
specs := make([]*sqlgraph.CreateSpec, len(_c.builders))
|
||||||
|
nodes := make([]*User, len(_c.builders))
|
||||||
|
mutators := make([]Mutator, len(_c.builders))
|
||||||
|
for i := range _c.builders {
|
||||||
func(i int, root context.Context) {
|
func(i int, root context.Context) {
|
||||||
builder := ucb.builders[i]
|
builder := _c.builders[i]
|
||||||
builder.defaults()
|
builder.defaults()
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
||||||
mutation, ok := m.(*UserMutation)
|
mutation, ok := m.(*UserMutation)
|
||||||
|
|
@ -285,16 +283,16 @@ func (ucb *UserCreateBulk) Save(ctx context.Context) ([]*User, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
builder.mutation = mutation
|
builder.mutation = mutation
|
||||||
nodes[i], specs[i] = builder.createSpec()
|
|
||||||
var err error
|
var err error
|
||||||
|
nodes[i], specs[i] = builder.createSpec()
|
||||||
if i < len(mutators)-1 {
|
if i < len(mutators)-1 {
|
||||||
_, err = mutators[i+1].Mutate(root, ucb.builders[i+1].mutation)
|
_, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation)
|
||||||
} else {
|
} else {
|
||||||
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
|
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
|
||||||
// Invoke the actual operation on the latest mutation in the chain.
|
// Invoke the actual operation on the latest mutation in the chain.
|
||||||
if err = sqlgraph.BatchCreate(ctx, ucb.driver, spec); err != nil {
|
if err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil {
|
||||||
if sqlgraph.IsConstraintError(err) {
|
if sqlgraph.IsConstraintError(err) {
|
||||||
err = &ConstraintError{err.Error(), err}
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -302,11 +300,11 @@ func (ucb *UserCreateBulk) Save(ctx context.Context) ([]*User, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
mutation.id = &nodes[i].ID
|
mutation.id = &nodes[i].ID
|
||||||
mutation.done = true
|
|
||||||
if specs[i].ID.Value != nil {
|
if specs[i].ID.Value != nil {
|
||||||
id := specs[i].ID.Value.(int64)
|
id := specs[i].ID.Value.(int64)
|
||||||
nodes[i].ID = int(id)
|
nodes[i].ID = int(id)
|
||||||
}
|
}
|
||||||
|
mutation.done = true
|
||||||
return nodes[i], nil
|
return nodes[i], nil
|
||||||
})
|
})
|
||||||
for i := len(builder.hooks) - 1; i >= 0; i-- {
|
for i := len(builder.hooks) - 1; i >= 0; i-- {
|
||||||
|
|
@ -316,7 +314,7 @@ func (ucb *UserCreateBulk) Save(ctx context.Context) ([]*User, error) {
|
||||||
}(i, ctx)
|
}(i, ctx)
|
||||||
}
|
}
|
||||||
if len(mutators) > 0 {
|
if len(mutators) > 0 {
|
||||||
if _, err := mutators[0].Mutate(ctx, ucb.builders[0].mutation); err != nil {
|
if _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -324,8 +322,8 @@ func (ucb *UserCreateBulk) Save(ctx context.Context) ([]*User, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX is like Save, but panics if an error occurs.
|
// SaveX is like Save, but panics if an error occurs.
|
||||||
func (ucb *UserCreateBulk) SaveX(ctx context.Context) []*User {
|
func (_c *UserCreateBulk) SaveX(ctx context.Context) []*User {
|
||||||
v, err := ucb.Save(ctx)
|
v, err := _c.Save(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -333,14 +331,14 @@ func (ucb *UserCreateBulk) SaveX(ctx context.Context) []*User {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the query.
|
// Exec executes the query.
|
||||||
func (ucb *UserCreateBulk) Exec(ctx context.Context) error {
|
func (_c *UserCreateBulk) Exec(ctx context.Context) error {
|
||||||
_, err := ucb.Save(ctx)
|
_, err := _c.Save(ctx)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (ucb *UserCreateBulk) ExecX(ctx context.Context) {
|
func (_c *UserCreateBulk) ExecX(ctx context.Context) {
|
||||||
if err := ucb.Exec(ctx); err != nil {
|
if err := _c.Exec(ctx); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"goweb/ent/predicate"
|
|
||||||
"goweb/ent/user"
|
|
||||||
|
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
"entgo.io/ent/schema/field"
|
"entgo.io/ent/schema/field"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/predicate"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UserDelete is the builder for deleting a User entity.
|
// UserDelete is the builder for deleting a User entity.
|
||||||
|
|
@ -21,80 +20,56 @@ type UserDelete struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Where appends a list predicates to the UserDelete builder.
|
// Where appends a list predicates to the UserDelete builder.
|
||||||
func (ud *UserDelete) Where(ps ...predicate.User) *UserDelete {
|
func (_d *UserDelete) Where(ps ...predicate.User) *UserDelete {
|
||||||
ud.mutation.Where(ps...)
|
_d.mutation.Where(ps...)
|
||||||
return ud
|
return _d
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the deletion query and returns how many vertices were deleted.
|
// Exec executes the deletion query and returns how many vertices were deleted.
|
||||||
func (ud *UserDelete) Exec(ctx context.Context) (int, error) {
|
func (_d *UserDelete) Exec(ctx context.Context) (int, error) {
|
||||||
var (
|
return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks)
|
||||||
err error
|
|
||||||
affected int
|
|
||||||
)
|
|
||||||
if len(ud.hooks) == 0 {
|
|
||||||
affected, err = ud.sqlExec(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*UserMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
ud.mutation = mutation
|
|
||||||
affected, err = ud.sqlExec(ctx)
|
|
||||||
mutation.done = true
|
|
||||||
return affected, err
|
|
||||||
})
|
|
||||||
for i := len(ud.hooks) - 1; i >= 0; i-- {
|
|
||||||
if ud.hooks[i] == nil {
|
|
||||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = ud.hooks[i](mut)
|
|
||||||
}
|
|
||||||
if _, err := mut.Mutate(ctx, ud.mutation); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return affected, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (ud *UserDelete) ExecX(ctx context.Context) int {
|
func (_d *UserDelete) ExecX(ctx context.Context) int {
|
||||||
n, err := ud.Exec(ctx)
|
n, err := _d.Exec(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ud *UserDelete) sqlExec(ctx context.Context) (int, error) {
|
func (_d *UserDelete) sqlExec(ctx context.Context) (int, error) {
|
||||||
_spec := &sqlgraph.DeleteSpec{
|
_spec := sqlgraph.NewDeleteSpec(user.Table, sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt))
|
||||||
Node: &sqlgraph.NodeSpec{
|
if ps := _d.mutation.predicates; len(ps) > 0 {
|
||||||
Table: user.Table,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: user.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if ps := ud.mutation.predicates; len(ps) > 0 {
|
|
||||||
_spec.Predicate = func(selector *sql.Selector) {
|
_spec.Predicate = func(selector *sql.Selector) {
|
||||||
for i := range ps {
|
for i := range ps {
|
||||||
ps[i](selector)
|
ps[i](selector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sqlgraph.DeleteNodes(ctx, ud.driver, _spec)
|
affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec)
|
||||||
|
if err != nil && sqlgraph.IsConstraintError(err) {
|
||||||
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
|
}
|
||||||
|
_d.mutation.done = true
|
||||||
|
return affected, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserDeleteOne is the builder for deleting a single User entity.
|
// UserDeleteOne is the builder for deleting a single User entity.
|
||||||
type UserDeleteOne struct {
|
type UserDeleteOne struct {
|
||||||
ud *UserDelete
|
_d *UserDelete
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where appends a list predicates to the UserDelete builder.
|
||||||
|
func (_d *UserDeleteOne) Where(ps ...predicate.User) *UserDeleteOne {
|
||||||
|
_d._d.mutation.Where(ps...)
|
||||||
|
return _d
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the deletion query.
|
// Exec executes the deletion query.
|
||||||
func (udo *UserDeleteOne) Exec(ctx context.Context) error {
|
func (_d *UserDeleteOne) Exec(ctx context.Context) error {
|
||||||
n, err := udo.ud.Exec(ctx)
|
n, err := _d._d.Exec(ctx)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return err
|
return err
|
||||||
|
|
@ -106,6 +81,8 @@ func (udo *UserDeleteOne) Exec(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (udo *UserDeleteOne) ExecX(ctx context.Context) {
|
func (_d *UserDeleteOne) ExecX(ctx context.Context) {
|
||||||
udo.ud.ExecX(ctx)
|
if err := _d.Exec(ctx); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,17 +1,18 @@
|
||||||
// Code generated by entc, DO NOT EDIT.
|
// Code generated by ent, DO NOT EDIT.
|
||||||
|
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"goweb/ent/passwordtoken"
|
|
||||||
"goweb/ent/predicate"
|
|
||||||
"goweb/ent/user"
|
|
||||||
|
|
||||||
"entgo.io/ent/dialect/sql"
|
"entgo.io/ent/dialect/sql"
|
||||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||||
"entgo.io/ent/schema/field"
|
"entgo.io/ent/schema/field"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/passwordtoken"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/predicate"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UserUpdate is the builder for updating User entities.
|
// UserUpdate is the builder for updating User entities.
|
||||||
|
|
@ -22,111 +23,130 @@ type UserUpdate struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Where appends a list predicates to the UserUpdate builder.
|
// Where appends a list predicates to the UserUpdate builder.
|
||||||
func (uu *UserUpdate) Where(ps ...predicate.User) *UserUpdate {
|
func (_u *UserUpdate) Where(ps ...predicate.User) *UserUpdate {
|
||||||
uu.mutation.Where(ps...)
|
_u.mutation.Where(ps...)
|
||||||
return uu
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetName sets the "name" field.
|
// SetName sets the "name" field.
|
||||||
func (uu *UserUpdate) SetName(s string) *UserUpdate {
|
func (_u *UserUpdate) SetName(v string) *UserUpdate {
|
||||||
uu.mutation.SetName(s)
|
_u.mutation.SetName(v)
|
||||||
return uu
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableName sets the "name" field if the given value is not nil.
|
||||||
|
func (_u *UserUpdate) SetNillableName(v *string) *UserUpdate {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetName(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetEmail sets the "email" field.
|
// SetEmail sets the "email" field.
|
||||||
func (uu *UserUpdate) SetEmail(s string) *UserUpdate {
|
func (_u *UserUpdate) SetEmail(v string) *UserUpdate {
|
||||||
uu.mutation.SetEmail(s)
|
_u.mutation.SetEmail(v)
|
||||||
return uu
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableEmail sets the "email" field if the given value is not nil.
|
||||||
|
func (_u *UserUpdate) SetNillableEmail(v *string) *UserUpdate {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetEmail(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPassword sets the "password" field.
|
// SetPassword sets the "password" field.
|
||||||
func (uu *UserUpdate) SetPassword(s string) *UserUpdate {
|
func (_u *UserUpdate) SetPassword(v string) *UserUpdate {
|
||||||
uu.mutation.SetPassword(s)
|
_u.mutation.SetPassword(v)
|
||||||
return uu
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillablePassword sets the "password" field if the given value is not nil.
|
||||||
|
func (_u *UserUpdate) SetNillablePassword(v *string) *UserUpdate {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetPassword(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetVerified sets the "verified" field.
|
||||||
|
func (_u *UserUpdate) SetVerified(v bool) *UserUpdate {
|
||||||
|
_u.mutation.SetVerified(v)
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableVerified sets the "verified" field if the given value is not nil.
|
||||||
|
func (_u *UserUpdate) SetNillableVerified(v *bool) *UserUpdate {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetVerified(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAdmin sets the "admin" field.
|
||||||
|
func (_u *UserUpdate) SetAdmin(v bool) *UserUpdate {
|
||||||
|
_u.mutation.SetAdmin(v)
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableAdmin sets the "admin" field if the given value is not nil.
|
||||||
|
func (_u *UserUpdate) SetNillableAdmin(v *bool) *UserUpdate {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetAdmin(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddOwnerIDs adds the "owner" edge to the PasswordToken entity by IDs.
|
// AddOwnerIDs adds the "owner" edge to the PasswordToken entity by IDs.
|
||||||
func (uu *UserUpdate) AddOwnerIDs(ids ...int) *UserUpdate {
|
func (_u *UserUpdate) AddOwnerIDs(ids ...int) *UserUpdate {
|
||||||
uu.mutation.AddOwnerIDs(ids...)
|
_u.mutation.AddOwnerIDs(ids...)
|
||||||
return uu
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddOwner adds the "owner" edges to the PasswordToken entity.
|
// AddOwner adds the "owner" edges to the PasswordToken entity.
|
||||||
func (uu *UserUpdate) AddOwner(p ...*PasswordToken) *UserUpdate {
|
func (_u *UserUpdate) AddOwner(v ...*PasswordToken) *UserUpdate {
|
||||||
ids := make([]int, len(p))
|
ids := make([]int, len(v))
|
||||||
for i := range p {
|
for i := range v {
|
||||||
ids[i] = p[i].ID
|
ids[i] = v[i].ID
|
||||||
}
|
}
|
||||||
return uu.AddOwnerIDs(ids...)
|
return _u.AddOwnerIDs(ids...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutation returns the UserMutation object of the builder.
|
// Mutation returns the UserMutation object of the builder.
|
||||||
func (uu *UserUpdate) Mutation() *UserMutation {
|
func (_u *UserUpdate) Mutation() *UserMutation {
|
||||||
return uu.mutation
|
return _u.mutation
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearOwner clears all "owner" edges to the PasswordToken entity.
|
// ClearOwner clears all "owner" edges to the PasswordToken entity.
|
||||||
func (uu *UserUpdate) ClearOwner() *UserUpdate {
|
func (_u *UserUpdate) ClearOwner() *UserUpdate {
|
||||||
uu.mutation.ClearOwner()
|
_u.mutation.ClearOwner()
|
||||||
return uu
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveOwnerIDs removes the "owner" edge to PasswordToken entities by IDs.
|
// RemoveOwnerIDs removes the "owner" edge to PasswordToken entities by IDs.
|
||||||
func (uu *UserUpdate) RemoveOwnerIDs(ids ...int) *UserUpdate {
|
func (_u *UserUpdate) RemoveOwnerIDs(ids ...int) *UserUpdate {
|
||||||
uu.mutation.RemoveOwnerIDs(ids...)
|
_u.mutation.RemoveOwnerIDs(ids...)
|
||||||
return uu
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveOwner removes "owner" edges to PasswordToken entities.
|
// RemoveOwner removes "owner" edges to PasswordToken entities.
|
||||||
func (uu *UserUpdate) RemoveOwner(p ...*PasswordToken) *UserUpdate {
|
func (_u *UserUpdate) RemoveOwner(v ...*PasswordToken) *UserUpdate {
|
||||||
ids := make([]int, len(p))
|
ids := make([]int, len(v))
|
||||||
for i := range p {
|
for i := range v {
|
||||||
ids[i] = p[i].ID
|
ids[i] = v[i].ID
|
||||||
}
|
}
|
||||||
return uu.RemoveOwnerIDs(ids...)
|
return _u.RemoveOwnerIDs(ids...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save executes the query and returns the number of nodes affected by the update operation.
|
// Save executes the query and returns the number of nodes affected by the update operation.
|
||||||
func (uu *UserUpdate) Save(ctx context.Context) (int, error) {
|
func (_u *UserUpdate) Save(ctx context.Context) (int, error) {
|
||||||
var (
|
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
|
||||||
err error
|
|
||||||
affected int
|
|
||||||
)
|
|
||||||
if len(uu.hooks) == 0 {
|
|
||||||
if err = uu.check(); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
affected, err = uu.sqlSave(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*UserMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
if err = uu.check(); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
uu.mutation = mutation
|
|
||||||
affected, err = uu.sqlSave(ctx)
|
|
||||||
mutation.done = true
|
|
||||||
return affected, err
|
|
||||||
})
|
|
||||||
for i := len(uu.hooks) - 1; i >= 0; i-- {
|
|
||||||
if uu.hooks[i] == nil {
|
|
||||||
return 0, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = uu.hooks[i](mut)
|
|
||||||
}
|
|
||||||
if _, err := mut.Mutate(ctx, uu.mutation); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return affected, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX is like Save, but panics if an error occurs.
|
// SaveX is like Save, but panics if an error occurs.
|
||||||
func (uu *UserUpdate) SaveX(ctx context.Context) int {
|
func (_u *UserUpdate) SaveX(ctx context.Context) int {
|
||||||
affected, err := uu.Save(ctx)
|
affected, err := _u.Save(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -134,78 +154,66 @@ func (uu *UserUpdate) SaveX(ctx context.Context) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the query.
|
// Exec executes the query.
|
||||||
func (uu *UserUpdate) Exec(ctx context.Context) error {
|
func (_u *UserUpdate) Exec(ctx context.Context) error {
|
||||||
_, err := uu.Save(ctx)
|
_, err := _u.Save(ctx)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (uu *UserUpdate) ExecX(ctx context.Context) {
|
func (_u *UserUpdate) ExecX(ctx context.Context) {
|
||||||
if err := uu.Exec(ctx); err != nil {
|
if err := _u.Exec(ctx); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check runs all checks and user-defined validators on the builder.
|
// check runs all checks and user-defined validators on the builder.
|
||||||
func (uu *UserUpdate) check() error {
|
func (_u *UserUpdate) check() error {
|
||||||
if v, ok := uu.mutation.Name(); ok {
|
if v, ok := _u.mutation.Name(); ok {
|
||||||
if err := user.NameValidator(v); err != nil {
|
if err := user.NameValidator(v); err != nil {
|
||||||
return &ValidationError{Name: "name", err: fmt.Errorf("ent: validator failed for field \"name\": %w", err)}
|
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "User.name": %w`, err)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v, ok := uu.mutation.Email(); ok {
|
if v, ok := _u.mutation.Email(); ok {
|
||||||
if err := user.EmailValidator(v); err != nil {
|
if err := user.EmailValidator(v); err != nil {
|
||||||
return &ValidationError{Name: "email", err: fmt.Errorf("ent: validator failed for field \"email\": %w", err)}
|
return &ValidationError{Name: "email", err: fmt.Errorf(`ent: validator failed for field "User.email": %w`, err)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v, ok := uu.mutation.Password(); ok {
|
if v, ok := _u.mutation.Password(); ok {
|
||||||
if err := user.PasswordValidator(v); err != nil {
|
if err := user.PasswordValidator(v); err != nil {
|
||||||
return &ValidationError{Name: "password", err: fmt.Errorf("ent: validator failed for field \"password\": %w", err)}
|
return &ValidationError{Name: "password", err: fmt.Errorf(`ent: validator failed for field "User.password": %w`, err)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
func (_u *UserUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
||||||
_spec := &sqlgraph.UpdateSpec{
|
if err := _u.check(); err != nil {
|
||||||
Node: &sqlgraph.NodeSpec{
|
return _node, err
|
||||||
Table: user.Table,
|
|
||||||
Columns: user.Columns,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: user.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
if ps := uu.mutation.predicates; len(ps) > 0 {
|
_spec := sqlgraph.NewUpdateSpec(user.Table, user.Columns, sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt))
|
||||||
|
if ps := _u.mutation.predicates; len(ps) > 0 {
|
||||||
_spec.Predicate = func(selector *sql.Selector) {
|
_spec.Predicate = func(selector *sql.Selector) {
|
||||||
for i := range ps {
|
for i := range ps {
|
||||||
ps[i](selector)
|
ps[i](selector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if value, ok := uu.mutation.Name(); ok {
|
if value, ok := _u.mutation.Name(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(user.FieldName, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
|
||||||
Value: value,
|
|
||||||
Column: user.FieldName,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if value, ok := uu.mutation.Email(); ok {
|
if value, ok := _u.mutation.Email(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(user.FieldEmail, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
|
||||||
Value: value,
|
|
||||||
Column: user.FieldEmail,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if value, ok := uu.mutation.Password(); ok {
|
if value, ok := _u.mutation.Password(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(user.FieldPassword, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
|
||||||
Value: value,
|
|
||||||
Column: user.FieldPassword,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if uu.mutation.OwnerCleared() {
|
if value, ok := _u.mutation.Verified(); ok {
|
||||||
|
_spec.SetField(user.FieldVerified, field.TypeBool, value)
|
||||||
|
}
|
||||||
|
if value, ok := _u.mutation.Admin(); ok {
|
||||||
|
_spec.SetField(user.FieldAdmin, field.TypeBool, value)
|
||||||
|
}
|
||||||
|
if _u.mutation.OwnerCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.O2M,
|
||||||
Inverse: true,
|
Inverse: true,
|
||||||
|
|
@ -213,15 +221,12 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||||
Columns: []string{user.OwnerColumn},
|
Columns: []string{user.OwnerColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(passwordtoken.FieldID, field.TypeInt),
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: passwordtoken.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
}
|
}
|
||||||
if nodes := uu.mutation.RemovedOwnerIDs(); len(nodes) > 0 && !uu.mutation.OwnerCleared() {
|
if nodes := _u.mutation.RemovedOwnerIDs(); len(nodes) > 0 && !_u.mutation.OwnerCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.O2M,
|
||||||
Inverse: true,
|
Inverse: true,
|
||||||
|
|
@ -229,10 +234,7 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||||
Columns: []string{user.OwnerColumn},
|
Columns: []string{user.OwnerColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(passwordtoken.FieldID, field.TypeInt),
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: passwordtoken.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
|
|
@ -240,7 +242,7 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||||
}
|
}
|
||||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
}
|
}
|
||||||
if nodes := uu.mutation.OwnerIDs(); len(nodes) > 0 {
|
if nodes := _u.mutation.OwnerIDs(); len(nodes) > 0 {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.O2M,
|
||||||
Inverse: true,
|
Inverse: true,
|
||||||
|
|
@ -248,10 +250,7 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||||
Columns: []string{user.OwnerColumn},
|
Columns: []string{user.OwnerColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(passwordtoken.FieldID, field.TypeInt),
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: passwordtoken.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
|
|
@ -259,15 +258,16 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||||
}
|
}
|
||||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||||
}
|
}
|
||||||
if n, err = sqlgraph.UpdateNodes(ctx, uu.driver, _spec); err != nil {
|
if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil {
|
||||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||||
err = &NotFoundError{user.Label}
|
err = &NotFoundError{user.Label}
|
||||||
} else if sqlgraph.IsConstraintError(err) {
|
} else if sqlgraph.IsConstraintError(err) {
|
||||||
err = &ConstraintError{err.Error(), err}
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
}
|
}
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return n, nil
|
_u.mutation.done = true
|
||||||
|
return _node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserUpdateOne is the builder for updating a single User entity.
|
// UserUpdateOne is the builder for updating a single User entity.
|
||||||
|
|
@ -279,112 +279,137 @@ type UserUpdateOne struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetName sets the "name" field.
|
// SetName sets the "name" field.
|
||||||
func (uuo *UserUpdateOne) SetName(s string) *UserUpdateOne {
|
func (_u *UserUpdateOne) SetName(v string) *UserUpdateOne {
|
||||||
uuo.mutation.SetName(s)
|
_u.mutation.SetName(v)
|
||||||
return uuo
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableName sets the "name" field if the given value is not nil.
|
||||||
|
func (_u *UserUpdateOne) SetNillableName(v *string) *UserUpdateOne {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetName(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetEmail sets the "email" field.
|
// SetEmail sets the "email" field.
|
||||||
func (uuo *UserUpdateOne) SetEmail(s string) *UserUpdateOne {
|
func (_u *UserUpdateOne) SetEmail(v string) *UserUpdateOne {
|
||||||
uuo.mutation.SetEmail(s)
|
_u.mutation.SetEmail(v)
|
||||||
return uuo
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableEmail sets the "email" field if the given value is not nil.
|
||||||
|
func (_u *UserUpdateOne) SetNillableEmail(v *string) *UserUpdateOne {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetEmail(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPassword sets the "password" field.
|
// SetPassword sets the "password" field.
|
||||||
func (uuo *UserUpdateOne) SetPassword(s string) *UserUpdateOne {
|
func (_u *UserUpdateOne) SetPassword(v string) *UserUpdateOne {
|
||||||
uuo.mutation.SetPassword(s)
|
_u.mutation.SetPassword(v)
|
||||||
return uuo
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillablePassword sets the "password" field if the given value is not nil.
|
||||||
|
func (_u *UserUpdateOne) SetNillablePassword(v *string) *UserUpdateOne {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetPassword(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetVerified sets the "verified" field.
|
||||||
|
func (_u *UserUpdateOne) SetVerified(v bool) *UserUpdateOne {
|
||||||
|
_u.mutation.SetVerified(v)
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableVerified sets the "verified" field if the given value is not nil.
|
||||||
|
func (_u *UserUpdateOne) SetNillableVerified(v *bool) *UserUpdateOne {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetVerified(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAdmin sets the "admin" field.
|
||||||
|
func (_u *UserUpdateOne) SetAdmin(v bool) *UserUpdateOne {
|
||||||
|
_u.mutation.SetAdmin(v)
|
||||||
|
return _u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableAdmin sets the "admin" field if the given value is not nil.
|
||||||
|
func (_u *UserUpdateOne) SetNillableAdmin(v *bool) *UserUpdateOne {
|
||||||
|
if v != nil {
|
||||||
|
_u.SetAdmin(*v)
|
||||||
|
}
|
||||||
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddOwnerIDs adds the "owner" edge to the PasswordToken entity by IDs.
|
// AddOwnerIDs adds the "owner" edge to the PasswordToken entity by IDs.
|
||||||
func (uuo *UserUpdateOne) AddOwnerIDs(ids ...int) *UserUpdateOne {
|
func (_u *UserUpdateOne) AddOwnerIDs(ids ...int) *UserUpdateOne {
|
||||||
uuo.mutation.AddOwnerIDs(ids...)
|
_u.mutation.AddOwnerIDs(ids...)
|
||||||
return uuo
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddOwner adds the "owner" edges to the PasswordToken entity.
|
// AddOwner adds the "owner" edges to the PasswordToken entity.
|
||||||
func (uuo *UserUpdateOne) AddOwner(p ...*PasswordToken) *UserUpdateOne {
|
func (_u *UserUpdateOne) AddOwner(v ...*PasswordToken) *UserUpdateOne {
|
||||||
ids := make([]int, len(p))
|
ids := make([]int, len(v))
|
||||||
for i := range p {
|
for i := range v {
|
||||||
ids[i] = p[i].ID
|
ids[i] = v[i].ID
|
||||||
}
|
}
|
||||||
return uuo.AddOwnerIDs(ids...)
|
return _u.AddOwnerIDs(ids...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutation returns the UserMutation object of the builder.
|
// Mutation returns the UserMutation object of the builder.
|
||||||
func (uuo *UserUpdateOne) Mutation() *UserMutation {
|
func (_u *UserUpdateOne) Mutation() *UserMutation {
|
||||||
return uuo.mutation
|
return _u.mutation
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearOwner clears all "owner" edges to the PasswordToken entity.
|
// ClearOwner clears all "owner" edges to the PasswordToken entity.
|
||||||
func (uuo *UserUpdateOne) ClearOwner() *UserUpdateOne {
|
func (_u *UserUpdateOne) ClearOwner() *UserUpdateOne {
|
||||||
uuo.mutation.ClearOwner()
|
_u.mutation.ClearOwner()
|
||||||
return uuo
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveOwnerIDs removes the "owner" edge to PasswordToken entities by IDs.
|
// RemoveOwnerIDs removes the "owner" edge to PasswordToken entities by IDs.
|
||||||
func (uuo *UserUpdateOne) RemoveOwnerIDs(ids ...int) *UserUpdateOne {
|
func (_u *UserUpdateOne) RemoveOwnerIDs(ids ...int) *UserUpdateOne {
|
||||||
uuo.mutation.RemoveOwnerIDs(ids...)
|
_u.mutation.RemoveOwnerIDs(ids...)
|
||||||
return uuo
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveOwner removes "owner" edges to PasswordToken entities.
|
// RemoveOwner removes "owner" edges to PasswordToken entities.
|
||||||
func (uuo *UserUpdateOne) RemoveOwner(p ...*PasswordToken) *UserUpdateOne {
|
func (_u *UserUpdateOne) RemoveOwner(v ...*PasswordToken) *UserUpdateOne {
|
||||||
ids := make([]int, len(p))
|
ids := make([]int, len(v))
|
||||||
for i := range p {
|
for i := range v {
|
||||||
ids[i] = p[i].ID
|
ids[i] = v[i].ID
|
||||||
}
|
}
|
||||||
return uuo.RemoveOwnerIDs(ids...)
|
return _u.RemoveOwnerIDs(ids...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where appends a list predicates to the UserUpdate builder.
|
||||||
|
func (_u *UserUpdateOne) Where(ps ...predicate.User) *UserUpdateOne {
|
||||||
|
_u.mutation.Where(ps...)
|
||||||
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select allows selecting one or more fields (columns) of the returned entity.
|
// Select allows selecting one or more fields (columns) of the returned entity.
|
||||||
// The default is selecting all fields defined in the entity schema.
|
// The default is selecting all fields defined in the entity schema.
|
||||||
func (uuo *UserUpdateOne) Select(field string, fields ...string) *UserUpdateOne {
|
func (_u *UserUpdateOne) Select(field string, fields ...string) *UserUpdateOne {
|
||||||
uuo.fields = append([]string{field}, fields...)
|
_u.fields = append([]string{field}, fields...)
|
||||||
return uuo
|
return _u
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save executes the query and returns the updated User entity.
|
// Save executes the query and returns the updated User entity.
|
||||||
func (uuo *UserUpdateOne) Save(ctx context.Context) (*User, error) {
|
func (_u *UserUpdateOne) Save(ctx context.Context) (*User, error) {
|
||||||
var (
|
return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)
|
||||||
err error
|
|
||||||
node *User
|
|
||||||
)
|
|
||||||
if len(uuo.hooks) == 0 {
|
|
||||||
if err = uuo.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
node, err = uuo.sqlSave(ctx)
|
|
||||||
} else {
|
|
||||||
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
|
|
||||||
mutation, ok := m.(*UserMutation)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected mutation type %T", m)
|
|
||||||
}
|
|
||||||
if err = uuo.check(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
uuo.mutation = mutation
|
|
||||||
node, err = uuo.sqlSave(ctx)
|
|
||||||
mutation.done = true
|
|
||||||
return node, err
|
|
||||||
})
|
|
||||||
for i := len(uuo.hooks) - 1; i >= 0; i-- {
|
|
||||||
if uuo.hooks[i] == nil {
|
|
||||||
return nil, fmt.Errorf("ent: uninitialized hook (forgotten import ent/runtime?)")
|
|
||||||
}
|
|
||||||
mut = uuo.hooks[i](mut)
|
|
||||||
}
|
|
||||||
if _, err := mut.Mutate(ctx, uuo.mutation); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return node, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveX is like Save, but panics if an error occurs.
|
// SaveX is like Save, but panics if an error occurs.
|
||||||
func (uuo *UserUpdateOne) SaveX(ctx context.Context) *User {
|
func (_u *UserUpdateOne) SaveX(ctx context.Context) *User {
|
||||||
node, err := uuo.Save(ctx)
|
node, err := _u.Save(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -392,55 +417,49 @@ func (uuo *UserUpdateOne) SaveX(ctx context.Context) *User {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the query on the entity.
|
// Exec executes the query on the entity.
|
||||||
func (uuo *UserUpdateOne) Exec(ctx context.Context) error {
|
func (_u *UserUpdateOne) Exec(ctx context.Context) error {
|
||||||
_, err := uuo.Save(ctx)
|
_, err := _u.Save(ctx)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecX is like Exec, but panics if an error occurs.
|
// ExecX is like Exec, but panics if an error occurs.
|
||||||
func (uuo *UserUpdateOne) ExecX(ctx context.Context) {
|
func (_u *UserUpdateOne) ExecX(ctx context.Context) {
|
||||||
if err := uuo.Exec(ctx); err != nil {
|
if err := _u.Exec(ctx); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check runs all checks and user-defined validators on the builder.
|
// check runs all checks and user-defined validators on the builder.
|
||||||
func (uuo *UserUpdateOne) check() error {
|
func (_u *UserUpdateOne) check() error {
|
||||||
if v, ok := uuo.mutation.Name(); ok {
|
if v, ok := _u.mutation.Name(); ok {
|
||||||
if err := user.NameValidator(v); err != nil {
|
if err := user.NameValidator(v); err != nil {
|
||||||
return &ValidationError{Name: "name", err: fmt.Errorf("ent: validator failed for field \"name\": %w", err)}
|
return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "User.name": %w`, err)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v, ok := uuo.mutation.Email(); ok {
|
if v, ok := _u.mutation.Email(); ok {
|
||||||
if err := user.EmailValidator(v); err != nil {
|
if err := user.EmailValidator(v); err != nil {
|
||||||
return &ValidationError{Name: "email", err: fmt.Errorf("ent: validator failed for field \"email\": %w", err)}
|
return &ValidationError{Name: "email", err: fmt.Errorf(`ent: validator failed for field "User.email": %w`, err)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if v, ok := uuo.mutation.Password(); ok {
|
if v, ok := _u.mutation.Password(); ok {
|
||||||
if err := user.PasswordValidator(v); err != nil {
|
if err := user.PasswordValidator(v); err != nil {
|
||||||
return &ValidationError{Name: "password", err: fmt.Errorf("ent: validator failed for field \"password\": %w", err)}
|
return &ValidationError{Name: "password", err: fmt.Errorf(`ent: validator failed for field "User.password": %w`, err)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) {
|
func (_u *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) {
|
||||||
_spec := &sqlgraph.UpdateSpec{
|
if err := _u.check(); err != nil {
|
||||||
Node: &sqlgraph.NodeSpec{
|
return _node, err
|
||||||
Table: user.Table,
|
|
||||||
Columns: user.Columns,
|
|
||||||
ID: &sqlgraph.FieldSpec{
|
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: user.FieldID,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
id, ok := uuo.mutation.ID()
|
_spec := sqlgraph.NewUpdateSpec(user.Table, user.Columns, sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt))
|
||||||
|
id, ok := _u.mutation.ID()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, &ValidationError{Name: "ID", err: fmt.Errorf("missing User.ID for update")}
|
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "User.id" for update`)}
|
||||||
}
|
}
|
||||||
_spec.Node.ID.Value = id
|
_spec.Node.ID.Value = id
|
||||||
if fields := uuo.fields; len(fields) > 0 {
|
if fields := _u.fields; len(fields) > 0 {
|
||||||
_spec.Node.Columns = make([]string, 0, len(fields))
|
_spec.Node.Columns = make([]string, 0, len(fields))
|
||||||
_spec.Node.Columns = append(_spec.Node.Columns, user.FieldID)
|
_spec.Node.Columns = append(_spec.Node.Columns, user.FieldID)
|
||||||
for _, f := range fields {
|
for _, f := range fields {
|
||||||
|
|
@ -452,35 +471,29 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ps := uuo.mutation.predicates; len(ps) > 0 {
|
if ps := _u.mutation.predicates; len(ps) > 0 {
|
||||||
_spec.Predicate = func(selector *sql.Selector) {
|
_spec.Predicate = func(selector *sql.Selector) {
|
||||||
for i := range ps {
|
for i := range ps {
|
||||||
ps[i](selector)
|
ps[i](selector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if value, ok := uuo.mutation.Name(); ok {
|
if value, ok := _u.mutation.Name(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(user.FieldName, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
|
||||||
Value: value,
|
|
||||||
Column: user.FieldName,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if value, ok := uuo.mutation.Email(); ok {
|
if value, ok := _u.mutation.Email(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(user.FieldEmail, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
|
||||||
Value: value,
|
|
||||||
Column: user.FieldEmail,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if value, ok := uuo.mutation.Password(); ok {
|
if value, ok := _u.mutation.Password(); ok {
|
||||||
_spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{
|
_spec.SetField(user.FieldPassword, field.TypeString, value)
|
||||||
Type: field.TypeString,
|
|
||||||
Value: value,
|
|
||||||
Column: user.FieldPassword,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if uuo.mutation.OwnerCleared() {
|
if value, ok := _u.mutation.Verified(); ok {
|
||||||
|
_spec.SetField(user.FieldVerified, field.TypeBool, value)
|
||||||
|
}
|
||||||
|
if value, ok := _u.mutation.Admin(); ok {
|
||||||
|
_spec.SetField(user.FieldAdmin, field.TypeBool, value)
|
||||||
|
}
|
||||||
|
if _u.mutation.OwnerCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.O2M,
|
||||||
Inverse: true,
|
Inverse: true,
|
||||||
|
|
@ -488,15 +501,12 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error)
|
||||||
Columns: []string{user.OwnerColumn},
|
Columns: []string{user.OwnerColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(passwordtoken.FieldID, field.TypeInt),
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: passwordtoken.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
}
|
}
|
||||||
if nodes := uuo.mutation.RemovedOwnerIDs(); len(nodes) > 0 && !uuo.mutation.OwnerCleared() {
|
if nodes := _u.mutation.RemovedOwnerIDs(); len(nodes) > 0 && !_u.mutation.OwnerCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.O2M,
|
||||||
Inverse: true,
|
Inverse: true,
|
||||||
|
|
@ -504,10 +514,7 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error)
|
||||||
Columns: []string{user.OwnerColumn},
|
Columns: []string{user.OwnerColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(passwordtoken.FieldID, field.TypeInt),
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: passwordtoken.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
|
|
@ -515,7 +522,7 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error)
|
||||||
}
|
}
|
||||||
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
|
||||||
}
|
}
|
||||||
if nodes := uuo.mutation.OwnerIDs(); len(nodes) > 0 {
|
if nodes := _u.mutation.OwnerIDs(); len(nodes) > 0 {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.O2M,
|
Rel: sqlgraph.O2M,
|
||||||
Inverse: true,
|
Inverse: true,
|
||||||
|
|
@ -523,10 +530,7 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error)
|
||||||
Columns: []string{user.OwnerColumn},
|
Columns: []string{user.OwnerColumn},
|
||||||
Bidi: false,
|
Bidi: false,
|
||||||
Target: &sqlgraph.EdgeTarget{
|
Target: &sqlgraph.EdgeTarget{
|
||||||
IDSpec: &sqlgraph.FieldSpec{
|
IDSpec: sqlgraph.NewFieldSpec(passwordtoken.FieldID, field.TypeInt),
|
||||||
Type: field.TypeInt,
|
|
||||||
Column: passwordtoken.FieldID,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, k := range nodes {
|
for _, k := range nodes {
|
||||||
|
|
@ -534,16 +538,17 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error)
|
||||||
}
|
}
|
||||||
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
_spec.Edges.Add = append(_spec.Edges.Add, edge)
|
||||||
}
|
}
|
||||||
_node = &User{config: uuo.config}
|
_node = &User{config: _u.config}
|
||||||
_spec.Assign = _node.assignValues
|
_spec.Assign = _node.assignValues
|
||||||
_spec.ScanValues = _node.scanValues
|
_spec.ScanValues = _node.scanValues
|
||||||
if err = sqlgraph.UpdateNode(ctx, uuo.driver, _spec); err != nil {
|
if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil {
|
||||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||||
err = &NotFoundError{user.Label}
|
err = &NotFoundError{user.Label}
|
||||||
} else if sqlgraph.IsConstraintError(err) {
|
} else if sqlgraph.IsConstraintError(err) {
|
||||||
err = &ConstraintError{err.Error(), err}
|
err = &ConstraintError{msg: err.Error(), wrap: err}
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
_u.mutation.done = true
|
||||||
return _node, nil
|
return _node, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
package funcmap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"html/template"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"goweb/config"
|
|
||||||
|
|
||||||
"github.com/Masterminds/sprig"
|
|
||||||
"github.com/labstack/gommon/random"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// CacheBuster stores a random string used as a cache buster for static files.
|
|
||||||
CacheBuster = random.String(10)
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetFuncMap provides a template function map
|
|
||||||
func GetFuncMap() template.FuncMap {
|
|
||||||
// See http://masterminds.github.io/sprig/ for available funcs
|
|
||||||
funcMap := sprig.FuncMap()
|
|
||||||
|
|
||||||
// Provide a list of custom functions
|
|
||||||
// Expand this as you add more functions to this package
|
|
||||||
// Avoid using a name already in use by sprig
|
|
||||||
f := template.FuncMap{
|
|
||||||
"hasField": HasField,
|
|
||||||
"file": File,
|
|
||||||
"link": Link,
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range f {
|
|
||||||
funcMap[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
return funcMap
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasField checks if an interface contains a given field
|
|
||||||
func HasField(v interface{}, name string) bool {
|
|
||||||
rv := reflect.ValueOf(v)
|
|
||||||
if rv.Kind() == reflect.Ptr {
|
|
||||||
rv = rv.Elem()
|
|
||||||
}
|
|
||||||
if rv.Kind() != reflect.Struct {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return rv.FieldByName(name).IsValid()
|
|
||||||
}
|
|
||||||
|
|
||||||
// File appends a cache buster to a given filepath so it can remain cached until the app is restarted
|
|
||||||
func File(filepath string) string {
|
|
||||||
return fmt.Sprintf("/%s/%s?v=%s", config.StaticPrefix, filepath, CacheBuster)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link outputs HTML for a link element, providing the ability to dynamically set the active class
|
|
||||||
func Link(url, text, currentPath string, classes ...string) template.HTML {
|
|
||||||
if currentPath == url {
|
|
||||||
classes = append(classes, "is-active")
|
|
||||||
}
|
|
||||||
|
|
||||||
html := fmt.Sprintf(`<a class="%s" href="%s">%s</a>`, strings.Join(classes, " "), url, text)
|
|
||||||
return template.HTML(html)
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
package funcmap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"goweb/config"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHasField(t *testing.T) {
|
|
||||||
type example struct {
|
|
||||||
name string
|
|
||||||
}
|
|
||||||
var e example
|
|
||||||
assert.True(t, HasField(e, "name"))
|
|
||||||
assert.False(t, HasField(e, "abcd"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLink(t *testing.T) {
|
|
||||||
link := string(Link("/abc", "Text", "/abc"))
|
|
||||||
expected := `<a class="is-active" href="/abc">Text</a>`
|
|
||||||
assert.Equal(t, expected, link)
|
|
||||||
|
|
||||||
link = string(Link("/abc", "Text", "/abc", "first", "second"))
|
|
||||||
expected = `<a class="first second is-active" href="/abc">Text</a>`
|
|
||||||
assert.Equal(t, expected, link)
|
|
||||||
|
|
||||||
link = string(Link("/abc", "Text", "/def"))
|
|
||||||
expected = `<a class="" href="/abc">Text</a>`
|
|
||||||
assert.Equal(t, expected, link)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetFuncMap(t *testing.T) {
|
|
||||||
file := File("test.png")
|
|
||||||
expected := fmt.Sprintf("/%s/test.png?v=%s", config.StaticPrefix, CacheBuster)
|
|
||||||
assert.Equal(t, expected, file)
|
|
||||||
}
|
|
||||||
130
go.mod
130
go.mod
|
|
@ -1,78 +1,68 @@
|
||||||
module goweb
|
module github.com/mikestefanello/pagoda
|
||||||
|
|
||||||
go 1.17
|
go 1.24.6
|
||||||
|
|
||||||
require (
|
require (
|
||||||
entgo.io/ent v0.9.1
|
entgo.io/ent v0.14.5
|
||||||
github.com/Masterminds/sprig v2.22.0+incompatible
|
github.com/PuerkitoBio/goquery v1.10.3
|
||||||
github.com/PuerkitoBio/goquery v1.8.0
|
github.com/go-playground/validator/v10 v10.29.0
|
||||||
github.com/eko/gocache/v2 v2.1.0
|
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||||
github.com/go-playground/assert/v2 v2.0.1
|
github.com/gorilla/context v1.1.2
|
||||||
github.com/go-playground/validator/v10 v10.9.0
|
github.com/gorilla/sessions v1.4.0
|
||||||
github.com/go-redis/redis/v8 v8.11.4
|
github.com/labstack/echo/v4 v4.14.0
|
||||||
github.com/gorilla/sessions v1.2.1
|
github.com/mattn/go-sqlite3 v1.14.32
|
||||||
github.com/jackc/pgx/v4 v4.14.1
|
github.com/maypok86/otter v1.2.4
|
||||||
github.com/joeshaw/envdecode v0.0.0-20200121155833-099f1fc765bd
|
github.com/mikestefanello/backlite v0.6.0
|
||||||
github.com/labstack/echo-contrib v0.11.0
|
github.com/spf13/afero v1.15.0
|
||||||
github.com/labstack/echo/v4 v4.6.1
|
github.com/spf13/viper v1.21.0
|
||||||
github.com/labstack/gommon v0.3.1
|
github.com/stretchr/testify v1.11.1
|
||||||
github.com/stretchr/testify v1.7.0
|
golang.org/x/crypto v0.46.0
|
||||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
|
maragu.dev/gomponents v1.2.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
ariga.io/atlas v0.38.0 // indirect
|
||||||
github.com/Masterminds/semver v1.5.0 // indirect
|
github.com/agext/levenshtein v1.2.3 // indirect
|
||||||
github.com/XiaoMi/pegasus-go-client v0.0.0-20210427083443-f3b6b08bc4c2 // indirect
|
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||||
github.com/andybalholm/cascadia v1.3.1 // indirect
|
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/bmatcuk/doublestar v1.3.4 // indirect
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.1.0 // indirect
|
github.com/dolthub/maphash v0.1.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/gammazero/deque v1.2.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.0 // indirect
|
github.com/go-openapi/inflect v0.21.5 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
github.com/gorilla/context v1.1.1 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||||
github.com/huandu/xstrings v1.3.2 // indirect
|
github.com/hashicorp/hcl/v2 v2.24.0 // indirect
|
||||||
github.com/imdario/mergo v0.3.12 // indirect
|
github.com/labstack/gommon v0.4.2 // indirect
|
||||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/jackc/pgconn v1.10.1 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/jackc/pgio v1.0.0 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||||
github.com/jackc/pgproto3/v2 v2.2.0 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/jackc/pgtype v1.9.1 // indirect
|
github.com/rogpeppe/go-internal v1.10.0 // indirect
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
|
github.com/sagikazarmark/locafero v0.12.0 // indirect
|
||||||
github.com/leodido/go-urn v1.2.1 // indirect
|
github.com/spf13/cast v1.10.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
|
||||||
github.com/pegasus-kv/thrift v0.13.0 // indirect
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
|
||||||
github.com/prometheus/client_golang v1.10.0 // indirect
|
|
||||||
github.com/prometheus/client_model v0.2.0 // indirect
|
|
||||||
github.com/prometheus/common v0.25.0 // indirect
|
|
||||||
github.com/prometheus/procfs v0.6.0 // indirect
|
|
||||||
github.com/sirupsen/logrus v1.6.0 // indirect
|
|
||||||
github.com/spf13/cast v1.3.1 // indirect
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
github.com/zclconf/go-cty v1.17.0 // indirect
|
||||||
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 // indirect
|
github.com/zclconf/go-cty-yaml v1.1.0 // indirect
|
||||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 // indirect
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/mod v0.31.0 // indirect
|
||||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
|
golang.org/x/net v0.48.0 // indirect
|
||||||
google.golang.org/appengine v1.6.1 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
google.golang.org/protobuf v1.26.0 // indirect
|
golang.org/x/sys v0.39.0 // indirect
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
golang.org/x/text v0.32.0 // indirect
|
||||||
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 // indirect
|
golang.org/x/time v0.14.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
golang.org/x/tools v0.40.0 // indirect
|
||||||
k8s.io/apimachinery v0.0.0-20191123233150-4c4803ed55e3 // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
82
htmx/htmx.go
82
htmx/htmx.go
|
|
@ -1,82 +0,0 @@
|
||||||
package htmx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Headers (https://htmx.org/docs/#requests)
|
|
||||||
const (
|
|
||||||
HeaderRequest = "HX-Request"
|
|
||||||
HeaderBoosted = "HX-Boosted"
|
|
||||||
HeaderTrigger = "HX-Trigger"
|
|
||||||
HeaderTriggerName = "HX-Trigger-Name"
|
|
||||||
HeaderTriggerAfterSwap = "HX-Trigger-After-Swap"
|
|
||||||
HeaderTriggerAfterSettle = "HX-Trigger-After-Settle"
|
|
||||||
HeaderTarget = "HX-Target"
|
|
||||||
HeaderPrompt = "HX-Prompt"
|
|
||||||
HeaderPush = "HX-Push"
|
|
||||||
HeaderRedirect = "HX-Redirect"
|
|
||||||
HeaderRefresh = "HX-Refresh"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// Request contains data that HTMX provides during requests
|
|
||||||
Request struct {
|
|
||||||
Enabled bool
|
|
||||||
Boosted bool
|
|
||||||
Trigger string
|
|
||||||
TriggerName string
|
|
||||||
Target string
|
|
||||||
Prompt string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Response contain data that the server can communicate back to HTMX
|
|
||||||
Response struct {
|
|
||||||
Push string
|
|
||||||
Redirect string
|
|
||||||
Refresh bool
|
|
||||||
Trigger string
|
|
||||||
TriggerAfterSwap string
|
|
||||||
TriggerAfterSettle string
|
|
||||||
NoContent bool
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetRequest extracts HTMX data from the request
|
|
||||||
func GetRequest(ctx echo.Context) Request {
|
|
||||||
return Request{
|
|
||||||
Enabled: ctx.Request().Header.Get(HeaderRequest) == "true",
|
|
||||||
Boosted: ctx.Request().Header.Get(HeaderBoosted) == "true",
|
|
||||||
Trigger: ctx.Request().Header.Get(HeaderTrigger),
|
|
||||||
TriggerName: ctx.Request().Header.Get(HeaderTriggerName),
|
|
||||||
Target: ctx.Request().Header.Get(HeaderTarget),
|
|
||||||
Prompt: ctx.Request().Header.Get(HeaderPrompt),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply applies data from a Response to a server response
|
|
||||||
func (r Response) Apply(ctx echo.Context) {
|
|
||||||
if r.Push != "" {
|
|
||||||
ctx.Response().Header().Set(HeaderPush, r.Push)
|
|
||||||
}
|
|
||||||
if r.Redirect != "" {
|
|
||||||
ctx.Response().Header().Set(HeaderRedirect, r.Redirect)
|
|
||||||
}
|
|
||||||
if r.Refresh {
|
|
||||||
ctx.Response().Header().Set(HeaderRefresh, "true")
|
|
||||||
}
|
|
||||||
if r.Trigger != "" {
|
|
||||||
ctx.Response().Header().Set(HeaderTrigger, r.Trigger)
|
|
||||||
}
|
|
||||||
if r.TriggerAfterSwap != "" {
|
|
||||||
ctx.Response().Header().Set(HeaderTriggerAfterSwap, r.TriggerAfterSwap)
|
|
||||||
}
|
|
||||||
if r.TriggerAfterSettle != "" {
|
|
||||||
ctx.Response().Header().Set(HeaderTriggerAfterSettle, r.TriggerAfterSettle)
|
|
||||||
}
|
|
||||||
if r.NoContent {
|
|
||||||
ctx.Response().Status = http.StatusNoContent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
64
main.go
64
main.go
|
|
@ -1,64 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"goweb/routes"
|
|
||||||
"goweb/services"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Start a new container
|
|
||||||
c := services.NewContainer()
|
|
||||||
defer func() {
|
|
||||||
if err := c.Shutdown(); err != nil {
|
|
||||||
c.Web.Logger.Fatal(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Build the router
|
|
||||||
routes.BuildRouter(c)
|
|
||||||
|
|
||||||
// Start the server
|
|
||||||
go func() {
|
|
||||||
srv := http.Server{
|
|
||||||
Addr: fmt.Sprintf("%s:%d", c.Config.HTTP.Hostname, c.Config.HTTP.Port),
|
|
||||||
Handler: c.Web,
|
|
||||||
ReadTimeout: c.Config.HTTP.ReadTimeout,
|
|
||||||
WriteTimeout: c.Config.HTTP.WriteTimeout,
|
|
||||||
IdleTimeout: c.Config.HTTP.IdleTimeout,
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Config.HTTP.TLS.Enabled {
|
|
||||||
certs, err := tls.LoadX509KeyPair(c.Config.HTTP.TLS.Certificate, c.Config.HTTP.TLS.Key)
|
|
||||||
if err != nil {
|
|
||||||
c.Web.Logger.Fatalf("cannot load TLS certificate: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
srv.TLSConfig = &tls.Config{
|
|
||||||
Certificates: []tls.Certificate{certs},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.Web.StartServer(&srv); err != http.ErrServerClosed {
|
|
||||||
c.Web.Logger.Fatalf("shutting down the server: v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Wait for interrupt signal to gracefully shutdown the server with a timeout of 10 seconds.
|
|
||||||
quit := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(quit, os.Interrupt)
|
|
||||||
signal.Notify(quit, os.Kill)
|
|
||||||
<-quit
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
if err := c.Web.Shutdown(ctx); err != nil {
|
|
||||||
c.Web.Logger.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,89 +0,0 @@
|
||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"goweb/context"
|
|
||||||
"goweb/ent"
|
|
||||||
"goweb/msg"
|
|
||||||
"goweb/services"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LoadAuthenticatedUser loads the authenticated user, if one, and stores in context
|
|
||||||
func LoadAuthenticatedUser(authClient *services.AuthClient) echo.MiddlewareFunc {
|
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
u, err := authClient.GetAuthenticatedUser(c)
|
|
||||||
switch err.(type) {
|
|
||||||
case *ent.NotFoundError:
|
|
||||||
c.Logger().Warn("auth user not found")
|
|
||||||
case services.NotAuthenticatedError:
|
|
||||||
case nil:
|
|
||||||
c.Set(context.AuthenticatedUserKey, u)
|
|
||||||
c.Logger().Infof("auth user loaded in to context: %d", u.ID)
|
|
||||||
default:
|
|
||||||
c.Logger().Errorf("error querying for authenticated user: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return next(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadValidPasswordToken loads a valid password token entity that matches the user and token
|
|
||||||
// provided in path parameters
|
|
||||||
// If the token is invalid, the user will be redirected to the forgot password route
|
|
||||||
// This requires that the user owning the token is loaded in to context
|
|
||||||
func LoadValidPasswordToken(authClient *services.AuthClient) echo.MiddlewareFunc {
|
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
// Extract the user parameter
|
|
||||||
if c.Get(context.UserKey) == nil {
|
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
usr := c.Get(context.UserKey).(*ent.User)
|
|
||||||
|
|
||||||
token, err := authClient.GetValidPasswordToken(c, c.Param("password_token"), usr.ID)
|
|
||||||
|
|
||||||
switch err.(type) {
|
|
||||||
case nil:
|
|
||||||
c.Set(context.PasswordTokenKey, token)
|
|
||||||
return next(c)
|
|
||||||
case services.InvalidPasswordTokenError:
|
|
||||||
msg.Warning(c, "The link is either invalid or has expired. Please request a new one.")
|
|
||||||
return c.Redirect(http.StatusFound, c.Echo().Reverse("forgot_password"))
|
|
||||||
default:
|
|
||||||
c.Logger().Error(err)
|
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequireAuthentication requires that the user be authenticated in order to proceed
|
|
||||||
func RequireAuthentication() echo.MiddlewareFunc {
|
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
if u := c.Get(context.AuthenticatedUserKey); u == nil {
|
|
||||||
return echo.NewHTTPError(http.StatusUnauthorized)
|
|
||||||
}
|
|
||||||
|
|
||||||
return next(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequireNoAuthentication requires that the user not be authenticated in order to proceed
|
|
||||||
func RequireNoAuthentication() echo.MiddlewareFunc {
|
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
if u := c.Get(context.AuthenticatedUserKey); u != nil {
|
|
||||||
return echo.NewHTTPError(http.StatusForbidden)
|
|
||||||
}
|
|
||||||
|
|
||||||
return next(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"goweb/context"
|
|
||||||
|
|
||||||
"github.com/eko/gocache/v2/cache"
|
|
||||||
"github.com/eko/gocache/v2/marshaler"
|
|
||||||
"github.com/go-redis/redis/v8"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CachedPage is what is used to store a rendered Page in the cache
|
|
||||||
type CachedPage struct {
|
|
||||||
// URL stores the URL of the requested page
|
|
||||||
URL string
|
|
||||||
|
|
||||||
// HTML stores the complete HTML of the rendered Page
|
|
||||||
HTML []byte
|
|
||||||
|
|
||||||
// StatusCode stores the HTTP status code
|
|
||||||
StatusCode int
|
|
||||||
|
|
||||||
// Headers stores the HTTP headers
|
|
||||||
Headers map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServeCachedPage attempts to load a page from the cache by matching on the complete request URL
|
|
||||||
// If a page is cached for the requested URL, it will be served here and the request terminated.
|
|
||||||
// Any request made by an authenticated user or that is not a GET will be skipped.
|
|
||||||
func ServeCachedPage(ch *cache.Cache) echo.MiddlewareFunc {
|
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
// Skip non GET requests
|
|
||||||
if c.Request().Method != http.MethodGet {
|
|
||||||
return next(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip if the user is authenticated
|
|
||||||
if c.Get(context.AuthenticatedUserKey) != nil {
|
|
||||||
return next(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to load from cache
|
|
||||||
res, err := marshaler.New(ch).Get(
|
|
||||||
c.Request().Context(),
|
|
||||||
c.Request().URL.String(),
|
|
||||||
new(CachedPage),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
if err == redis.Nil {
|
|
||||||
c.Logger().Info("no cached page found")
|
|
||||||
} else {
|
|
||||||
c.Logger().Errorf("failed getting cached page: %v", err)
|
|
||||||
}
|
|
||||||
return next(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
page, ok := res.(*CachedPage)
|
|
||||||
if !ok {
|
|
||||||
c.Logger().Errorf("failed casting cached page")
|
|
||||||
return next(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set any headers
|
|
||||||
if page.Headers != nil {
|
|
||||||
for k, v := range page.Headers {
|
|
||||||
c.Response().Header().Set(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Logger().Info("serving cached page")
|
|
||||||
|
|
||||||
return c.HTMLBlob(page.StatusCode, page.HTML)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CacheControl sets a Cache-Control header with a given max age
|
|
||||||
func CacheControl(maxAge time.Duration) echo.MiddlewareFunc {
|
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
v := "no-cache, no-store"
|
|
||||||
if maxAge > 0 {
|
|
||||||
v = fmt.Sprintf("public, max-age=%.0f", maxAge.Seconds())
|
|
||||||
}
|
|
||||||
c.Response().Header().Set("Cache-Control", v)
|
|
||||||
return next(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"goweb/tests"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/eko/gocache/v2/marshaler"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestServeCachedPage(t *testing.T) {
|
|
||||||
// Cache a page
|
|
||||||
cp := CachedPage{
|
|
||||||
URL: "/cache",
|
|
||||||
HTML: []byte("html"),
|
|
||||||
Headers: make(map[string]string),
|
|
||||||
StatusCode: http.StatusCreated,
|
|
||||||
}
|
|
||||||
cp.Headers["a"] = "b"
|
|
||||||
cp.Headers["c"] = "d"
|
|
||||||
err := marshaler.New(c.Cache).Set(context.Background(), cp.URL, cp, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Request the URL of the cached page
|
|
||||||
ctx, rec := tests.NewContext(c.Web, cp.URL)
|
|
||||||
err = tests.ExecuteMiddleware(ctx, ServeCachedPage(c.Cache))
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, cp.StatusCode, ctx.Response().Status)
|
|
||||||
assert.Equal(t, cp.Headers["a"], ctx.Response().Header().Get("a"))
|
|
||||||
assert.Equal(t, cp.Headers["c"], ctx.Response().Header().Get("c"))
|
|
||||||
assert.Equal(t, cp.HTML, rec.Body.Bytes())
|
|
||||||
|
|
||||||
// Login and try again
|
|
||||||
tests.InitSession(ctx)
|
|
||||||
err = c.Auth.Login(ctx, usr.ID)
|
|
||||||
require.NoError(t, err)
|
|
||||||
_ = tests.ExecuteMiddleware(ctx, LoadAuthenticatedUser(c.Auth))
|
|
||||||
err = tests.ExecuteMiddleware(ctx, ServeCachedPage(c.Cache))
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCacheControl(t *testing.T) {
|
|
||||||
ctx, _ := tests.NewContext(c.Web, "/")
|
|
||||||
_ = tests.ExecuteMiddleware(ctx, CacheControl(time.Second*5))
|
|
||||||
assert.Equal(t, "public, max-age=5", ctx.Response().Header().Get("Cache-Control"))
|
|
||||||
_ = tests.ExecuteMiddleware(ctx, CacheControl(0))
|
|
||||||
assert.Equal(t, "no-cache, no-store", ctx.Response().Header().Get("Cache-Control"))
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LogRequestID includes the request ID in all logs for the given request
|
|
||||||
// This requires that middleware that includes the request ID first execute
|
|
||||||
func LogRequestID() echo.MiddlewareFunc {
|
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
|
||||||
return func(c echo.Context) error {
|
|
||||||
rID := c.Response().Header().Get(echo.HeaderXRequestID)
|
|
||||||
format := `{"time":"${time_rfc3339_nano}","id":"%s","level":"${level}","prefix":"${prefix}","file":"${short_file}","line":"${line}"}`
|
|
||||||
c.Logger().SetHeader(fmt.Sprintf(format, rID))
|
|
||||||
return next(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"goweb/tests"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
echomw "github.com/labstack/echo/v4/middleware"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLogRequestID(t *testing.T) {
|
|
||||||
ctx, _ := tests.NewContext(c.Web, "/")
|
|
||||||
_ = tests.ExecuteMiddleware(ctx, echomw.RequestID())
|
|
||||||
_ = tests.ExecuteMiddleware(ctx, LogRequestID())
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
ctx.Logger().SetOutput(&buf)
|
|
||||||
ctx.Logger().Info("test")
|
|
||||||
rID := ctx.Response().Header().Get(echo.HeaderXRequestID)
|
|
||||||
assert.Contains(t, buf.String(), fmt.Sprintf(`id":"%s"`, rID))
|
|
||||||
}
|
|
||||||
62
pkg/context/context.go
Normal file
62
pkg/context/context.go
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AuthenticatedUserKey is the key used to store the authenticated user in context.
|
||||||
|
AuthenticatedUserKey = "auth_user"
|
||||||
|
|
||||||
|
// UserKey is the key used to store a user in context.
|
||||||
|
UserKey = "user"
|
||||||
|
|
||||||
|
// FormKey is the key used to store a form in context.
|
||||||
|
FormKey = "form"
|
||||||
|
|
||||||
|
// PasswordTokenKey is the key used to store a password token in context.
|
||||||
|
PasswordTokenKey = "password_token"
|
||||||
|
|
||||||
|
// LoggerKey is the key used to store a structured logger in context.
|
||||||
|
LoggerKey = "logger"
|
||||||
|
|
||||||
|
// SessionKey is the key used to store the session data in context.
|
||||||
|
SessionKey = "session"
|
||||||
|
|
||||||
|
// HTMXRequestKey is the key used to store the HTMX request data in context.
|
||||||
|
HTMXRequestKey = "htmx"
|
||||||
|
|
||||||
|
// CSRFKey is the key used to store the CSRF token in context.
|
||||||
|
CSRFKey = "csrf"
|
||||||
|
|
||||||
|
// ConfigKey is the key used to store the configuration in context.
|
||||||
|
ConfigKey = "config"
|
||||||
|
|
||||||
|
// AdminEntityKey is the key used to store the entity being operated on in the admin panel.
|
||||||
|
AdminEntityKey = "admin:entity"
|
||||||
|
|
||||||
|
// AdminEntityIDKey is the key used to store the ID of the entity being operated on in the admin panel.
|
||||||
|
AdminEntityIDKey = "admin:entity_id"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsCanceledError determines if an error is due to a context cancellation.
|
||||||
|
func IsCanceledError(err error) bool {
|
||||||
|
return errors.Is(err, context.Canceled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache checks if a value of a given type exists in the Echo context for a given key and returns that, otherwise
|
||||||
|
// it will use a callback to generate a value, which is stored in the context then returned. This allows you to
|
||||||
|
// only generate items only once for a given request.
|
||||||
|
func Cache[T any](ctx echo.Context, key string, gen func(echo.Context) T) T {
|
||||||
|
if val := ctx.Get(key); val != nil {
|
||||||
|
if v, ok := val.(T); ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val := gen(ctx)
|
||||||
|
ctx.Set(key, val)
|
||||||
|
return val
|
||||||
|
}
|
||||||
47
pkg/context/context_test.go
Normal file
47
pkg/context/context_test.go
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsCanceled(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
assert.False(t, IsCanceledError(ctx.Err()))
|
||||||
|
cancel()
|
||||||
|
assert.True(t, IsCanceledError(ctx.Err()))
|
||||||
|
|
||||||
|
ctx, cancel = context.WithTimeout(context.Background(), time.Microsecond*5)
|
||||||
|
<-ctx.Done()
|
||||||
|
cancel()
|
||||||
|
assert.False(t, IsCanceledError(ctx.Err()))
|
||||||
|
|
||||||
|
assert.False(t, IsCanceledError(errors.New("test error")))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCache(t *testing.T) {
|
||||||
|
ctx := echo.New().NewContext(nil, nil)
|
||||||
|
|
||||||
|
key := "testing"
|
||||||
|
value := "hello"
|
||||||
|
called := 0
|
||||||
|
callback := func(ctx echo.Context) string {
|
||||||
|
called++
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Nil(t, ctx.Get(key))
|
||||||
|
|
||||||
|
got := Cache(ctx, key, callback)
|
||||||
|
assert.Equal(t, value, got)
|
||||||
|
assert.Equal(t, 1, called)
|
||||||
|
|
||||||
|
got = Cache(ctx, key, callback)
|
||||||
|
assert.Equal(t, value, got)
|
||||||
|
assert.Equal(t, 1, called)
|
||||||
|
}
|
||||||
55
pkg/form/form.go
Normal file
55
pkg/form/form.go
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
package form
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Form represents a form that can be submitted and validated.
|
||||||
|
type Form interface {
|
||||||
|
// Submit marks the form as submitted, stores a pointer to it in the context, binds the request
|
||||||
|
// values to the struct fields, and validates the input based on the struct tags.
|
||||||
|
// Returns a validator.ValidationErrors, if the form values were not valid, or an echo.HTTPError,
|
||||||
|
// if the request failed to process.
|
||||||
|
Submit(c echo.Context, form any) error
|
||||||
|
|
||||||
|
// IsSubmitted returns true if the form was submitted.
|
||||||
|
IsSubmitted() bool
|
||||||
|
|
||||||
|
// IsValid returns true if the form has no validation errors.
|
||||||
|
IsValid() bool
|
||||||
|
|
||||||
|
// IsDone returns true if the form was submitted and has no validation errors.
|
||||||
|
IsDone() bool
|
||||||
|
|
||||||
|
// FieldHasErrors returns true if a given struct field has validation errors.
|
||||||
|
FieldHasErrors(fieldName string) bool
|
||||||
|
|
||||||
|
// SetFieldError sets a validation error message for a given struct field.
|
||||||
|
SetFieldError(fieldName string, message string)
|
||||||
|
|
||||||
|
// GetFieldErrors returns the validation errors for a given struct field.
|
||||||
|
GetFieldErrors(fieldName string) []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets a form from the context or initializes a new copy if one is not set.
|
||||||
|
func Get[T any](ctx echo.Context) *T {
|
||||||
|
if v := ctx.Get(context.FormKey); v != nil {
|
||||||
|
if form, ok := v.(*T); ok {
|
||||||
|
return form
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var v T
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear removes the form set in the context.
|
||||||
|
func Clear(ctx echo.Context) {
|
||||||
|
ctx.Set(context.FormKey, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Submit submits a form.
|
||||||
|
// See Form.Submit().
|
||||||
|
func Submit(ctx echo.Context, form Form) error {
|
||||||
|
return form.Submit(ctx, form)
|
||||||
|
}
|
||||||
67
pkg/form/form_test.go
Normal file
67
pkg/form/form_test.go
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
package form
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/tests"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mockForm struct {
|
||||||
|
called bool
|
||||||
|
Submission
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockForm) Submit(_ echo.Context, _ any) error {
|
||||||
|
m.called = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubmit(t *testing.T) {
|
||||||
|
m := mockForm{}
|
||||||
|
ctx, _ := tests.NewContext(echo.New(), "/")
|
||||||
|
err := Submit(ctx, &m)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, m.called)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetClear(t *testing.T) {
|
||||||
|
e := echo.New()
|
||||||
|
|
||||||
|
type example struct {
|
||||||
|
Name string `form:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("get empty context", func(t *testing.T) {
|
||||||
|
// Empty context, still return a form.
|
||||||
|
ctx, _ := tests.NewContext(e, "/")
|
||||||
|
form := Get[example](ctx)
|
||||||
|
assert.NotNil(t, form)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("get non-empty context", func(t *testing.T) {
|
||||||
|
form := example{
|
||||||
|
Name: "test",
|
||||||
|
}
|
||||||
|
ctx, _ := tests.NewContext(e, "/")
|
||||||
|
ctx.Set(context.FormKey, &form)
|
||||||
|
|
||||||
|
// Get again and expect the values were stored.
|
||||||
|
got := Get[example](ctx)
|
||||||
|
require.NotNil(t, got)
|
||||||
|
assert.Equal(t, "test", got.Name)
|
||||||
|
|
||||||
|
// Attempt getting a different type to ensure there's no panic.
|
||||||
|
ret := Get[int](ctx)
|
||||||
|
require.NotNil(t, ret)
|
||||||
|
|
||||||
|
// Clear.
|
||||||
|
Clear(ctx)
|
||||||
|
got = Get[example](ctx)
|
||||||
|
require.NotNil(t, got)
|
||||||
|
assert.Empty(t, got.Name)
|
||||||
|
})
|
||||||
|
}
|
||||||
105
pkg/form/submission.go
Normal file
105
pkg/form/submission.go
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
package form
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Submission represents the state of the submission of a form, not including the form itself.
|
||||||
|
// This satisfies the Form interface.
|
||||||
|
type Submission struct {
|
||||||
|
// isSubmitted indicates if the form has been submitted.
|
||||||
|
isSubmitted bool
|
||||||
|
|
||||||
|
// errors stores a slice of error message strings keyed by form struct field name.
|
||||||
|
errors map[string][]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Submission) Submit(ctx echo.Context, form any) error {
|
||||||
|
f.isSubmitted = true
|
||||||
|
|
||||||
|
// Set in context so the form can later be retrieved.
|
||||||
|
ctx.Set(context.FormKey, form)
|
||||||
|
|
||||||
|
// Bind the values from the incoming request to the form struct.
|
||||||
|
if err := ctx.Bind(form); err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("unable to bind form: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the form.
|
||||||
|
if err := ctx.Validate(form); err != nil {
|
||||||
|
f.setErrorMessages(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Submission) IsSubmitted() bool {
|
||||||
|
return f.isSubmitted
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Submission) IsValid() bool {
|
||||||
|
if f.errors == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return len(f.errors) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Submission) IsDone() bool {
|
||||||
|
return f.IsSubmitted() && f.IsValid()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Submission) FieldHasErrors(fieldName string) bool {
|
||||||
|
return len(f.GetFieldErrors(fieldName)) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Submission) SetFieldError(fieldName string, message string) {
|
||||||
|
if f.errors == nil {
|
||||||
|
f.errors = make(map[string][]string)
|
||||||
|
}
|
||||||
|
f.errors[fieldName] = append(f.errors[fieldName], message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Submission) GetFieldErrors(fieldName string) []string {
|
||||||
|
if f.errors == nil {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
return f.errors[fieldName]
|
||||||
|
}
|
||||||
|
|
||||||
|
// setErrorMessages sets errors messages on the submission for all fields that failed validation.
|
||||||
|
func (f *Submission) setErrorMessages(err error) {
|
||||||
|
// Only this is supported right now
|
||||||
|
ves, ok := err.(validator.ValidationErrors)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ve := range ves {
|
||||||
|
var message string
|
||||||
|
|
||||||
|
// Provide better error messages depending on the failed validation tag.
|
||||||
|
// This should be expanded as you use additional tags in your validation.
|
||||||
|
switch ve.Tag() {
|
||||||
|
case "required":
|
||||||
|
message = "This field is required."
|
||||||
|
case "email":
|
||||||
|
message = "Enter a valid email address."
|
||||||
|
case "eqfield":
|
||||||
|
message = "Does not match."
|
||||||
|
case "gte":
|
||||||
|
message = fmt.Sprintf("Must be greater than or equal to %v.", ve.Param())
|
||||||
|
default:
|
||||||
|
message = "Invalid value."
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the error.
|
||||||
|
f.SetFieldError(ve.Field(), message)
|
||||||
|
}
|
||||||
|
}
|
||||||
57
pkg/form/submission_test.go
Normal file
57
pkg/form/submission_test.go
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
package form
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFormSubmission(t *testing.T) {
|
||||||
|
type formTest struct {
|
||||||
|
Name string `form:"name" validate:"required"`
|
||||||
|
Email string `form:"email" validate:"required,email"`
|
||||||
|
Submission
|
||||||
|
}
|
||||||
|
|
||||||
|
e := echo.New()
|
||||||
|
e.Validator = services.NewValidator()
|
||||||
|
|
||||||
|
t.Run("valid request", func(t *testing.T) {
|
||||||
|
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader("email=a@a.com"))
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
ctx := e.NewContext(req, httptest.NewRecorder())
|
||||||
|
|
||||||
|
var form formTest
|
||||||
|
err := form.Submit(ctx, &form)
|
||||||
|
assert.IsType(t, validator.ValidationErrors{}, err)
|
||||||
|
|
||||||
|
assert.Empty(t, form.Name)
|
||||||
|
assert.Equal(t, "a@a.com", form.Email)
|
||||||
|
assert.False(t, form.IsValid())
|
||||||
|
assert.True(t, form.FieldHasErrors("Name"))
|
||||||
|
assert.False(t, form.FieldHasErrors("Email"))
|
||||||
|
require.Len(t, form.GetFieldErrors("Name"), 1)
|
||||||
|
assert.Len(t, form.GetFieldErrors("Email"), 0)
|
||||||
|
assert.Equal(t, "This field is required.", form.GetFieldErrors("Name")[0])
|
||||||
|
assert.False(t, form.IsDone())
|
||||||
|
|
||||||
|
formInCtx := Get[formTest](ctx)
|
||||||
|
require.NotNil(t, formInCtx)
|
||||||
|
assert.Equal(t, form.Email, formInCtx.Email)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid request", func(t *testing.T) {
|
||||||
|
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader("abc=abc"))
|
||||||
|
ctx := e.NewContext(req, httptest.NewRecorder())
|
||||||
|
var form formTest
|
||||||
|
err := form.Submit(ctx, &form)
|
||||||
|
assert.IsType(t, new(echo.HTTPError), err)
|
||||||
|
})
|
||||||
|
}
|
||||||
198
pkg/handlers/admin.go
Normal file
198
pkg/handlers/admin.go
Normal file
|
|
@ -0,0 +1,198 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/backlite/ui"
|
||||||
|
"github.com/mikestefanello/pagoda/ent"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/admin"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/middleware"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/msg"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/pager"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/redirect"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/routenames"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/pages"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Admin struct {
|
||||||
|
orm *ent.Client
|
||||||
|
admin *admin.Handler
|
||||||
|
backlite *ui.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register(new(Admin))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Admin) Init(c *services.Container) error {
|
||||||
|
var err error
|
||||||
|
h.orm = c.ORM
|
||||||
|
h.admin = admin.NewHandler(h.orm, admin.HandlerConfig{
|
||||||
|
ItemsPerPage: 25,
|
||||||
|
PageQueryKey: pager.QueryKey,
|
||||||
|
TimeFormat: time.DateTime,
|
||||||
|
})
|
||||||
|
h.backlite, err = ui.NewHandler(ui.Config{
|
||||||
|
DB: c.Database,
|
||||||
|
BasePath: "/admin/tasks",
|
||||||
|
ItemsPerPage: 25,
|
||||||
|
ReleaseAfter: c.Config.Tasks.ReleaseAfter,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Admin) Routes(g *echo.Group) {
|
||||||
|
ag := g.Group("/admin", middleware.RequireAdmin)
|
||||||
|
|
||||||
|
entities := ag.Group("/entity")
|
||||||
|
for _, n := range admin.GetEntityTypes() {
|
||||||
|
ng := entities.Group(fmt.Sprintf("/%s", strings.ToLower(n.GetName())))
|
||||||
|
ng.GET("", h.EntityList(n)).
|
||||||
|
Name = routenames.AdminEntityList(n.GetName())
|
||||||
|
ng.GET("/add", h.EntityAdd(n)).
|
||||||
|
Name = routenames.AdminEntityAdd(n.GetName())
|
||||||
|
ng.POST("/add", h.EntityAddSubmit(n)).
|
||||||
|
Name = routenames.AdminEntityAddSubmit(n.GetName())
|
||||||
|
ng.GET("/:id/edit", h.EntityEdit(n), h.middlewareEntityLoad(n)).
|
||||||
|
Name = routenames.AdminEntityEdit(n.GetName())
|
||||||
|
ng.POST("/:id/edit", h.EntityEditSubmit(n), h.middlewareEntityLoad(n)).
|
||||||
|
Name = routenames.AdminEntityEditSubmit(n.GetName())
|
||||||
|
ng.GET("/:id/delete", h.EntityDelete(n), h.middlewareEntityLoad(n)).
|
||||||
|
Name = routenames.AdminEntityDelete(n.GetName())
|
||||||
|
ng.POST("/:id/delete", h.EntityDeleteSubmit(n), h.middlewareEntityLoad(n)).
|
||||||
|
Name = routenames.AdminEntityDeleteSubmit(n.GetName())
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks := ag.Group("/tasks")
|
||||||
|
tasks.GET("", h.Backlite(h.backlite.Running)).Name = routenames.AdminTasks
|
||||||
|
tasks.GET("/succeeded", h.Backlite(h.backlite.Succeeded))
|
||||||
|
tasks.GET("/failed", h.Backlite(h.backlite.Failed))
|
||||||
|
tasks.GET("/upcoming", h.Backlite(h.backlite.Upcoming))
|
||||||
|
tasks.GET("/task/:id", h.Backlite(h.backlite.Task))
|
||||||
|
tasks.GET("/completed/:id", h.Backlite(h.backlite.TaskCompleted))
|
||||||
|
}
|
||||||
|
|
||||||
|
// middlewareEntityLoad is middleware to extract the entity ID and attempt to load the given entity.
|
||||||
|
func (h *Admin) middlewareEntityLoad(n admin.EntityType) echo.MiddlewareFunc {
|
||||||
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
return func(ctx echo.Context) error {
|
||||||
|
id, err := strconv.Atoi(ctx.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest, "invalid entity ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
entity, err := h.admin.Get(ctx, n, id)
|
||||||
|
switch {
|
||||||
|
case err == nil:
|
||||||
|
ctx.Set(context.AdminEntityIDKey, id)
|
||||||
|
ctx.Set(context.AdminEntityKey, map[string][]string(entity))
|
||||||
|
return next(ctx)
|
||||||
|
case ent.IsNotFound(err):
|
||||||
|
return echo.NewHTTPError(http.StatusNotFound, "entity not found")
|
||||||
|
default:
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Admin) EntityList(n admin.EntityType) echo.HandlerFunc {
|
||||||
|
return func(ctx echo.Context) error {
|
||||||
|
list, err := h.admin.List(ctx, n)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pages.AdminEntityList(ctx, n, list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Admin) EntityAdd(n admin.EntityType) echo.HandlerFunc {
|
||||||
|
return func(ctx echo.Context) error {
|
||||||
|
return pages.AdminEntityInput(ctx, n, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Admin) EntityAddSubmit(n admin.EntityType) echo.HandlerFunc {
|
||||||
|
return func(ctx echo.Context) error {
|
||||||
|
err := h.admin.Create(ctx, n)
|
||||||
|
if err != nil {
|
||||||
|
msg.Error(ctx, err.Error())
|
||||||
|
return h.EntityAdd(n)(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Success(ctx, fmt.Sprintf("Successfully added %s.", n.GetName()))
|
||||||
|
|
||||||
|
return redirect.
|
||||||
|
New(ctx).
|
||||||
|
Route(routenames.AdminEntityList(n.GetName())).
|
||||||
|
StatusCode(http.StatusFound).
|
||||||
|
Go()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Admin) EntityEdit(n admin.EntityType) echo.HandlerFunc {
|
||||||
|
return func(ctx echo.Context) error {
|
||||||
|
v := ctx.Get(context.AdminEntityKey).(map[string][]string)
|
||||||
|
return pages.AdminEntityInput(ctx, n, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Admin) EntityEditSubmit(n admin.EntityType) echo.HandlerFunc {
|
||||||
|
return func(ctx echo.Context) error {
|
||||||
|
id := ctx.Get(context.AdminEntityIDKey).(int)
|
||||||
|
err := h.admin.Update(ctx, n, id)
|
||||||
|
if err != nil {
|
||||||
|
msg.Error(ctx, err.Error())
|
||||||
|
return h.EntityEdit(n)(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Success(ctx, fmt.Sprintf("Updated %s.", n.GetName()))
|
||||||
|
|
||||||
|
return redirect.
|
||||||
|
New(ctx).
|
||||||
|
Route(routenames.AdminEntityList(n.GetName())).
|
||||||
|
StatusCode(http.StatusFound).
|
||||||
|
Go()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Admin) EntityDelete(n admin.EntityType) echo.HandlerFunc {
|
||||||
|
return func(ctx echo.Context) error {
|
||||||
|
return pages.AdminEntityDelete(ctx, n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Admin) EntityDeleteSubmit(n admin.EntityType) echo.HandlerFunc {
|
||||||
|
return func(ctx echo.Context) error {
|
||||||
|
id := ctx.Get(context.AdminEntityIDKey).(int)
|
||||||
|
if err := h.admin.Delete(ctx, n, id); err != nil {
|
||||||
|
msg.Error(ctx, err.Error())
|
||||||
|
return h.EntityDelete(n)(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Success(ctx, fmt.Sprintf("Successfully deleted %s (ID %d).", n.GetName(), id))
|
||||||
|
|
||||||
|
return redirect.
|
||||||
|
New(ctx).
|
||||||
|
Route(routenames.AdminEntityList(n.GetName())).
|
||||||
|
StatusCode(http.StatusFound).
|
||||||
|
Go()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Admin) Backlite(handler func(http.ResponseWriter, *http.Request) error) echo.HandlerFunc {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
if id := c.Param("id"); id != "" {
|
||||||
|
c.Request().SetPathValue("task", id)
|
||||||
|
}
|
||||||
|
return handler(c.Response().Writer, c.Request())
|
||||||
|
}
|
||||||
|
}
|
||||||
380
pkg/handlers/auth.go
Normal file
380
pkg/handlers/auth.go
Normal file
|
|
@ -0,0 +1,380 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/config"
|
||||||
|
"github.com/mikestefanello/pagoda/ent"
|
||||||
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/form"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/log"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/middleware"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/msg"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/redirect"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/routenames"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/emails"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/forms"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/pages"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Auth struct {
|
||||||
|
config *config.Config
|
||||||
|
auth *services.AuthClient
|
||||||
|
mail *services.MailClient
|
||||||
|
orm *ent.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register(new(Auth))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Auth) Init(c *services.Container) error {
|
||||||
|
h.config = c.Config
|
||||||
|
h.orm = c.ORM
|
||||||
|
h.auth = c.Auth
|
||||||
|
h.mail = c.Mail
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Auth) Routes(g *echo.Group) {
|
||||||
|
g.GET("/logout", h.Logout, middleware.RequireAuthentication).Name = routenames.Logout
|
||||||
|
g.GET("/email/verify/:token", h.VerifyEmail).Name = routenames.VerifyEmail
|
||||||
|
|
||||||
|
noAuth := g.Group("/user", middleware.RequireNoAuthentication)
|
||||||
|
noAuth.GET("/login", h.LoginPage).Name = routenames.Login
|
||||||
|
noAuth.POST("/login", h.LoginSubmit).Name = routenames.LoginSubmit
|
||||||
|
noAuth.GET("/register", h.RegisterPage).Name = routenames.Register
|
||||||
|
noAuth.POST("/register", h.RegisterSubmit).Name = routenames.RegisterSubmit
|
||||||
|
noAuth.GET("/password", h.ForgotPasswordPage).Name = routenames.ForgotPassword
|
||||||
|
noAuth.POST("/password", h.ForgotPasswordSubmit).Name = routenames.ForgotPasswordSubmit
|
||||||
|
|
||||||
|
resetGroup := noAuth.Group("/password/reset",
|
||||||
|
middleware.LoadUser(h.orm),
|
||||||
|
middleware.LoadValidPasswordToken(h.auth),
|
||||||
|
)
|
||||||
|
resetGroup.GET("/token/:user/:password_token/:token", h.ResetPasswordPage).Name = routenames.ResetPassword
|
||||||
|
resetGroup.POST("/token/:user/:password_token/:token", h.ResetPasswordSubmit).Name = routenames.ResetPasswordSubmit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Auth) ForgotPasswordPage(ctx echo.Context) error {
|
||||||
|
return pages.ForgotPassword(ctx, form.Get[forms.ForgotPassword](ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Auth) ForgotPasswordSubmit(ctx echo.Context) error {
|
||||||
|
var input forms.ForgotPassword
|
||||||
|
|
||||||
|
succeed := func() error {
|
||||||
|
form.Clear(ctx)
|
||||||
|
msg.Success(ctx, "An email containing a link to reset your password will be sent to this address if it exists in our system.")
|
||||||
|
return h.ForgotPasswordPage(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := form.Submit(ctx, &input)
|
||||||
|
|
||||||
|
switch err.(type) {
|
||||||
|
case nil:
|
||||||
|
case validator.ValidationErrors:
|
||||||
|
return h.ForgotPasswordPage(ctx)
|
||||||
|
default:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to load the user.
|
||||||
|
u, err := h.orm.User.
|
||||||
|
Query().
|
||||||
|
Where(user.Email(strings.ToLower(input.Email))).
|
||||||
|
Only(ctx.Request().Context())
|
||||||
|
|
||||||
|
switch err.(type) {
|
||||||
|
case *ent.NotFoundError:
|
||||||
|
return succeed()
|
||||||
|
case nil:
|
||||||
|
default:
|
||||||
|
return fail(err, "error querying user during forgot password")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the token.
|
||||||
|
token, pt, err := h.auth.GeneratePasswordResetToken(ctx, u.ID)
|
||||||
|
if err != nil {
|
||||||
|
return fail(err, "error generating password reset token")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Ctx(ctx).Info("generated password reset token",
|
||||||
|
"user_id", u.ID,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Email the user.
|
||||||
|
url := ctx.Echo().Reverse(routenames.ResetPassword, u.ID, pt.ID, token)
|
||||||
|
err = h.mail.
|
||||||
|
Compose().
|
||||||
|
To(u.Email).
|
||||||
|
Subject("Reset your password").
|
||||||
|
Body(fmt.Sprintf("Go here to reset your password: %s", h.config.App.Host+url)).
|
||||||
|
Send(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fail(err, "error sending password reset email")
|
||||||
|
}
|
||||||
|
|
||||||
|
return succeed()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Auth) LoginPage(ctx echo.Context) error {
|
||||||
|
return pages.Login(ctx, form.Get[forms.Login](ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Auth) LoginSubmit(ctx echo.Context) error {
|
||||||
|
var input forms.Login
|
||||||
|
|
||||||
|
authFailed := func() error {
|
||||||
|
input.SetFieldError("Email", "")
|
||||||
|
input.SetFieldError("Password", "")
|
||||||
|
msg.Error(ctx, "Invalid credentials. Please try again.")
|
||||||
|
return h.LoginPage(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := form.Submit(ctx, &input)
|
||||||
|
|
||||||
|
switch err.(type) {
|
||||||
|
case nil:
|
||||||
|
case validator.ValidationErrors:
|
||||||
|
return h.LoginPage(ctx)
|
||||||
|
default:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to load the user.
|
||||||
|
u, err := h.orm.User.
|
||||||
|
Query().
|
||||||
|
Where(user.Email(strings.ToLower(input.Email))).
|
||||||
|
Only(ctx.Request().Context())
|
||||||
|
|
||||||
|
switch err.(type) {
|
||||||
|
case *ent.NotFoundError:
|
||||||
|
return authFailed()
|
||||||
|
case nil:
|
||||||
|
default:
|
||||||
|
return fail(err, "error querying user during login")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the password is correct.
|
||||||
|
err = h.auth.CheckPassword(input.Password, u.Password)
|
||||||
|
if err != nil {
|
||||||
|
return authFailed()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the user in.
|
||||||
|
err = h.auth.Login(ctx, u.ID)
|
||||||
|
if err != nil {
|
||||||
|
return fail(err, "unable to log in user")
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Success(ctx, fmt.Sprintf("Welcome back, %s. You are now logged in.", u.Name))
|
||||||
|
|
||||||
|
return redirect.New(ctx).
|
||||||
|
Route(routenames.Home).
|
||||||
|
Go()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Auth) Logout(ctx echo.Context) error {
|
||||||
|
if err := h.auth.Logout(ctx); err == nil {
|
||||||
|
msg.Success(ctx, "You have been logged out successfully.")
|
||||||
|
} else {
|
||||||
|
msg.Error(ctx, "An error occurred. Please try again.")
|
||||||
|
}
|
||||||
|
return redirect.New(ctx).
|
||||||
|
Route(routenames.Home).
|
||||||
|
Go()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Auth) RegisterPage(ctx echo.Context) error {
|
||||||
|
return pages.Register(ctx, form.Get[forms.Register](ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Auth) RegisterSubmit(ctx echo.Context) error {
|
||||||
|
var input forms.Register
|
||||||
|
|
||||||
|
err := form.Submit(ctx, &input)
|
||||||
|
|
||||||
|
switch err.(type) {
|
||||||
|
case nil:
|
||||||
|
case validator.ValidationErrors:
|
||||||
|
return h.RegisterPage(ctx)
|
||||||
|
default:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt creating the user.
|
||||||
|
u, err := h.orm.User.
|
||||||
|
Create().
|
||||||
|
SetName(input.Name).
|
||||||
|
SetEmail(input.Email).
|
||||||
|
SetPassword(input.Password).
|
||||||
|
Save(ctx.Request().Context())
|
||||||
|
|
||||||
|
switch err.(type) {
|
||||||
|
case nil:
|
||||||
|
log.Ctx(ctx).Info("user created",
|
||||||
|
"user_name", u.Name,
|
||||||
|
"user_id", u.ID,
|
||||||
|
)
|
||||||
|
case *ent.ConstraintError:
|
||||||
|
msg.Warning(ctx, "A user with this email address already exists. Please log in.")
|
||||||
|
return redirect.New(ctx).
|
||||||
|
Route(routenames.Login).
|
||||||
|
Go()
|
||||||
|
default:
|
||||||
|
return fail(err, "unable to create user")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the user in.
|
||||||
|
err = h.auth.Login(ctx, u.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Ctx(ctx).Error("unable to log user in",
|
||||||
|
"error", err,
|
||||||
|
"user_id", u.ID,
|
||||||
|
)
|
||||||
|
msg.Info(ctx, "Your account has been created.")
|
||||||
|
return redirect.New(ctx).
|
||||||
|
Route(routenames.Login).
|
||||||
|
Go()
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Success(ctx, "Your account has been created. You are now logged in.")
|
||||||
|
|
||||||
|
// Send the verification email.
|
||||||
|
h.sendVerificationEmail(ctx, u)
|
||||||
|
|
||||||
|
return redirect.New(ctx).
|
||||||
|
Route(routenames.Home).
|
||||||
|
Go()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Auth) sendVerificationEmail(ctx echo.Context, usr *ent.User) {
|
||||||
|
// Generate a token.
|
||||||
|
token, err := h.auth.GenerateEmailVerificationToken(usr.Email)
|
||||||
|
if err != nil {
|
||||||
|
log.Ctx(ctx).Error("unable to generate email verification token",
|
||||||
|
"user_id", usr.ID,
|
||||||
|
"error", err,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the email.
|
||||||
|
err = h.mail.
|
||||||
|
Compose().
|
||||||
|
To(usr.Email).
|
||||||
|
Subject("Confirm your email address").
|
||||||
|
Component(emails.ConfirmEmailAddress(ctx, usr.Name, token)).
|
||||||
|
Send(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Ctx(ctx).Error("unable to send email verification link",
|
||||||
|
"user_id", usr.ID,
|
||||||
|
"error", err,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Info(ctx, "An email was sent to you to verify your email address.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Auth) ResetPasswordPage(ctx echo.Context) error {
|
||||||
|
return pages.ResetPassword(ctx, form.Get[forms.ResetPassword](ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Auth) ResetPasswordSubmit(ctx echo.Context) error {
|
||||||
|
var input forms.ResetPassword
|
||||||
|
|
||||||
|
err := form.Submit(ctx, &input)
|
||||||
|
|
||||||
|
switch err.(type) {
|
||||||
|
case nil:
|
||||||
|
case validator.ValidationErrors:
|
||||||
|
return h.ResetPasswordPage(ctx)
|
||||||
|
default:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the requesting user.
|
||||||
|
usr := ctx.Get(context.UserKey).(*ent.User)
|
||||||
|
|
||||||
|
// Update the user.
|
||||||
|
_, err = usr.
|
||||||
|
Update().
|
||||||
|
SetPassword(input.Password).
|
||||||
|
Save(ctx.Request().Context())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fail(err, "unable to update password")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all password tokens for this user.
|
||||||
|
err = h.auth.DeletePasswordTokens(ctx, usr.ID)
|
||||||
|
if err != nil {
|
||||||
|
return fail(err, "unable to delete password tokens")
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Success(ctx, "Your password has been updated.")
|
||||||
|
return redirect.New(ctx).
|
||||||
|
Route(routenames.Login).
|
||||||
|
Go()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Auth) VerifyEmail(ctx echo.Context) error {
|
||||||
|
var usr *ent.User
|
||||||
|
|
||||||
|
// Validate the token.
|
||||||
|
token := ctx.Param("token")
|
||||||
|
email, err := h.auth.ValidateEmailVerificationToken(token)
|
||||||
|
if err != nil {
|
||||||
|
msg.Warning(ctx, "The link is either invalid or has expired.")
|
||||||
|
return redirect.New(ctx).
|
||||||
|
Route(routenames.Home).
|
||||||
|
Go()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it matches the authenticated user.
|
||||||
|
if u := ctx.Get(context.AuthenticatedUserKey); u != nil {
|
||||||
|
authUser := u.(*ent.User)
|
||||||
|
|
||||||
|
if authUser.Email == email {
|
||||||
|
usr = authUser
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query to find a matching user, if needed.
|
||||||
|
if usr == nil {
|
||||||
|
usr, err = h.orm.User.
|
||||||
|
Query().
|
||||||
|
Where(user.Email(email)).
|
||||||
|
Only(ctx.Request().Context())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fail(err, "query failed loading email verification token user")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the user, if needed.
|
||||||
|
if !usr.Verified {
|
||||||
|
usr, err = usr.
|
||||||
|
Update().
|
||||||
|
SetVerified(true).
|
||||||
|
Save(ctx.Request().Context())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fail(err, "failed to set user as verified")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Success(ctx, "Your email has been successfully verified.")
|
||||||
|
return redirect.New(ctx).
|
||||||
|
Route(routenames.Home).
|
||||||
|
Go()
|
||||||
|
}
|
||||||
76
pkg/handlers/cache.go
Normal file
76
pkg/handlers/cache.go
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/form"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/routenames"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/forms"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/pages"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Cache struct {
|
||||||
|
cache *services.CacheClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register(new(Cache))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Cache) Init(c *services.Container) error {
|
||||||
|
h.cache = c.Cache
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Cache) Routes(g *echo.Group) {
|
||||||
|
g.GET("/cache", h.Page).Name = routenames.Cache
|
||||||
|
g.POST("/cache", h.Submit).Name = routenames.CacheSubmit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Cache) Page(ctx echo.Context) error {
|
||||||
|
f := form.Get[forms.Cache](ctx)
|
||||||
|
|
||||||
|
// Fetch the value from the cache.
|
||||||
|
value, err := h.cache.
|
||||||
|
Get().
|
||||||
|
Key("page_cache_example").
|
||||||
|
Fetch(ctx.Request().Context())
|
||||||
|
|
||||||
|
// Store the value in the form, so it can be rendered, if found.
|
||||||
|
switch {
|
||||||
|
case err == nil:
|
||||||
|
f.CurrentValue = value.(string)
|
||||||
|
case errors.Is(err, services.ErrCacheMiss):
|
||||||
|
default:
|
||||||
|
return fail(err, "failed to fetch from cache")
|
||||||
|
}
|
||||||
|
|
||||||
|
return pages.UpdateCache(ctx, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Cache) Submit(ctx echo.Context) error {
|
||||||
|
var input forms.Cache
|
||||||
|
|
||||||
|
if err := form.Submit(ctx, &input); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the cache.
|
||||||
|
err := h.cache.
|
||||||
|
Set().
|
||||||
|
Key("page_cache_example").
|
||||||
|
Data(input.Value).
|
||||||
|
Expiration(30 * time.Minute).
|
||||||
|
Save(ctx.Request().Context())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fail(err, "unable to set cache")
|
||||||
|
}
|
||||||
|
|
||||||
|
form.Clear(ctx)
|
||||||
|
|
||||||
|
return h.Page(ctx)
|
||||||
|
}
|
||||||
62
pkg/handlers/contact.go
Normal file
62
pkg/handlers/contact.go
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/form"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/routenames"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/forms"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/pages"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Contact struct {
|
||||||
|
mail *services.MailClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register(new(Contact))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Contact) Init(c *services.Container) error {
|
||||||
|
h.mail = c.Mail
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Contact) Routes(g *echo.Group) {
|
||||||
|
g.GET("/contact", h.Page).Name = routenames.Contact
|
||||||
|
g.POST("/contact", h.Submit).Name = routenames.ContactSubmit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Contact) Page(ctx echo.Context) error {
|
||||||
|
return pages.ContactUs(ctx, form.Get[forms.Contact](ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Contact) Submit(ctx echo.Context) error {
|
||||||
|
var input forms.Contact
|
||||||
|
|
||||||
|
err := form.Submit(ctx, &input)
|
||||||
|
|
||||||
|
switch err.(type) {
|
||||||
|
case nil:
|
||||||
|
case validator.ValidationErrors:
|
||||||
|
return h.Page(ctx)
|
||||||
|
default:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.mail.
|
||||||
|
Compose().
|
||||||
|
To(input.Email).
|
||||||
|
Subject("Contact form submitted").
|
||||||
|
Body(fmt.Sprintf("The message is: %s", input.Message)).
|
||||||
|
Send(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fail(err, "unable to send email")
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.Page(ctx)
|
||||||
|
}
|
||||||
43
pkg/handlers/error.go
Normal file
43
pkg/handlers/error.go
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/log"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/pages"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Error struct{}
|
||||||
|
|
||||||
|
func (e *Error) Page(err error, ctx echo.Context) {
|
||||||
|
if ctx.Response().Committed || context.IsCanceledError(err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the error status code.
|
||||||
|
code := http.StatusInternalServerError
|
||||||
|
if he, ok := err.(*echo.HTTPError); ok {
|
||||||
|
code = he.Code
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the error.
|
||||||
|
logger := log.Ctx(ctx)
|
||||||
|
switch {
|
||||||
|
case code >= 500:
|
||||||
|
logger.Error(err.Error())
|
||||||
|
case code >= 400:
|
||||||
|
logger.Warn(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the status code.
|
||||||
|
ctx.Response().WriteHeader(code)
|
||||||
|
|
||||||
|
// Render the error page.
|
||||||
|
if err = pages.Error(ctx, code); err != nil {
|
||||||
|
log.Ctx(ctx).Error("failed to render error page",
|
||||||
|
"error", err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
80
pkg/handlers/files.go
Normal file
80
pkg/handlers/files.go
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/msg"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/routenames"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/models"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/pages"
|
||||||
|
"github.com/spf13/afero"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Files struct {
|
||||||
|
files afero.Fs
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register(new(Files))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Files) Init(c *services.Container) error {
|
||||||
|
h.files = c.Files
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Files) Routes(g *echo.Group) {
|
||||||
|
g.GET("/files", h.Page).Name = routenames.Files
|
||||||
|
g.POST("/files", h.Submit).Name = routenames.FilesSubmit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Files) Page(ctx echo.Context) error {
|
||||||
|
// Compile a list of all uploaded files to be rendered.
|
||||||
|
info, err := afero.ReadDir(h.files, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
files := make([]*models.File, 0)
|
||||||
|
for _, file := range info {
|
||||||
|
files = append(files, &models.File{
|
||||||
|
Name: file.Name(),
|
||||||
|
Size: file.Size(),
|
||||||
|
Modified: file.ModTime().Format(time.DateTime),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return pages.UploadFile(ctx, files)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Files) Submit(ctx echo.Context) error {
|
||||||
|
file, err := ctx.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
msg.Error(ctx, "A file is required.")
|
||||||
|
return h.Page(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
src, err := file.Open()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer src.Close()
|
||||||
|
|
||||||
|
dst, err := h.files.Create(file.Filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer dst.Close()
|
||||||
|
|
||||||
|
if _, err = io.Copy(dst, src); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Success(ctx, fmt.Sprintf("%s was uploaded successfully.", file.Filename))
|
||||||
|
|
||||||
|
return h.Page(ctx)
|
||||||
|
}
|
||||||
36
pkg/handlers/handlers.go
Normal file
36
pkg/handlers/handlers.go
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
var handlers []Handler
|
||||||
|
|
||||||
|
// Handler handles one or more HTTP routes
|
||||||
|
type Handler interface {
|
||||||
|
// Routes allows for self-registration of HTTP routes on the router
|
||||||
|
Routes(g *echo.Group)
|
||||||
|
|
||||||
|
// Init provides the service container to initialize
|
||||||
|
Init(*services.Container) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register registers a handler
|
||||||
|
func Register(h Handler) {
|
||||||
|
handlers = append(handlers, h)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHandlers returns all handlers
|
||||||
|
func GetHandlers() []Handler {
|
||||||
|
return handlers
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail is a helper to fail a request by returning a 500 error and logging the error
|
||||||
|
func fail(err error, log string) error {
|
||||||
|
// The error handler will handle logging
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("%s: %v", log, err))
|
||||||
|
}
|
||||||
29
pkg/handlers/handlers_test.go
Normal file
29
pkg/handlers/handlers_test.go
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetSetHandlers(t *testing.T) {
|
||||||
|
handlers = []Handler{}
|
||||||
|
assert.Empty(t, GetHandlers())
|
||||||
|
h := new(Pages)
|
||||||
|
Register(h)
|
||||||
|
got := GetHandlers()
|
||||||
|
require.Len(t, got, 1)
|
||||||
|
assert.Equal(t, h, got[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFail(t *testing.T) {
|
||||||
|
err := fail(errors.New("err message"), "log message")
|
||||||
|
require.IsType(t, new(echo.HTTPError), err)
|
||||||
|
he := err.(*echo.HTTPError)
|
||||||
|
assert.Equal(t, http.StatusInternalServerError, he.Code)
|
||||||
|
assert.Equal(t, "log message: err message", he.Message)
|
||||||
|
}
|
||||||
55
pkg/handlers/pages.go
Normal file
55
pkg/handlers/pages.go
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/pager"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/routenames"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/models"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/pages"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Pages struct{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register(new(Pages))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Pages) Init(c *services.Container) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Pages) Routes(g *echo.Group) {
|
||||||
|
g.GET("/", h.Home).Name = routenames.Home
|
||||||
|
g.GET("/about", h.About).Name = routenames.About
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Pages) Home(ctx echo.Context) error {
|
||||||
|
pgr := pager.NewPager(ctx, 4)
|
||||||
|
|
||||||
|
return pages.Home(ctx, &models.Posts{
|
||||||
|
Posts: h.fetchPosts(&pgr),
|
||||||
|
Pager: pgr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetchPosts is a mock example of fetching posts to illustrate how paging works.
|
||||||
|
func (h *Pages) fetchPosts(pager *pager.Pager) []models.Post {
|
||||||
|
pager.SetItems(20)
|
||||||
|
posts := make([]models.Post, 20)
|
||||||
|
|
||||||
|
for k := range posts {
|
||||||
|
posts[k] = models.Post{
|
||||||
|
ID: k + 1,
|
||||||
|
Title: fmt.Sprintf("Post example #%d", k+1),
|
||||||
|
Body: fmt.Sprintf("Lorem ipsum example #%d ddolor sit amet, consectetur adipiscing elit. Nam elementum vulputate tristique.", k+1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return posts[pager.GetOffset() : pager.GetOffset()+pager.ItemsPerPage]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Pages) About(ctx echo.Context) error {
|
||||||
|
return pages.About(ctx)
|
||||||
|
}
|
||||||
|
|
@ -1,23 +1,24 @@
|
||||||
package routes
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/routenames"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Simple example of how to test routes and their markup using the test HTTP server spun up within
|
// Simple example of how to test routes and their markup using the test HTTP server spun up within
|
||||||
// this test package
|
// this test package
|
||||||
func TestAbout_Get(t *testing.T) {
|
func TestPages__About(t *testing.T) {
|
||||||
doc := request(t).
|
doc := request(t).
|
||||||
setRoute("about").
|
setRoute(routenames.About).
|
||||||
get().
|
get().
|
||||||
assertStatusCode(http.StatusOK).
|
assertStatusCode(http.StatusOK).
|
||||||
toDoc()
|
toDoc()
|
||||||
|
|
||||||
// Goquery is an excellent package to use for testing HTML markup
|
// Goquery is an excellent package to use for testing HTML markup
|
||||||
h1 := doc.Find("h1.title")
|
h1 := doc.Find("h1")
|
||||||
assert.Len(t, h1.Nodes, 1)
|
assert.Len(t, h1.Nodes, 1)
|
||||||
assert.Equal(t, "About", h1.Text())
|
assert.Equal(t, "About", h1.Text())
|
||||||
}
|
}
|
||||||
93
pkg/handlers/router.go
Normal file
93
pkg/handlers/router.go
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gorilla/sessions"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
echomw "github.com/labstack/echo/v4/middleware"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/middleware"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
files "github.com/mikestefanello/pagoda/public"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BuildRouter builds the router.
|
||||||
|
func BuildRouter(c *services.Container) error {
|
||||||
|
// Force HTTPS, if enabled.
|
||||||
|
if c.Config.HTTP.TLS.Enabled {
|
||||||
|
c.Web.Use(echomw.HTTPSRedirect())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve public files with cache control.
|
||||||
|
c.Web.Group("", middleware.CacheControl(c.Config.Cache.Expiration.PublicFile)).
|
||||||
|
Static("files", "public/files")
|
||||||
|
|
||||||
|
// Serve static files.
|
||||||
|
// ui.StaticFile() should be used in ui components to append a cache key to the URL to break cache
|
||||||
|
// after each server reboot.
|
||||||
|
c.Web.Group(
|
||||||
|
"",
|
||||||
|
echomw.GzipWithConfig(echomw.GzipConfig{
|
||||||
|
Skipper: func(c echo.Context) bool {
|
||||||
|
for _, ext := range []string{
|
||||||
|
".js",
|
||||||
|
".css",
|
||||||
|
} {
|
||||||
|
if strings.HasSuffix(c.Request().URL.Path, ext) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
middleware.CacheControl(c.Config.Cache.Expiration.PublicFile),
|
||||||
|
).StaticFS("static", echo.MustSubFS(files.Static, "static"))
|
||||||
|
|
||||||
|
// Non-static file route group.
|
||||||
|
g := c.Web.Group("")
|
||||||
|
|
||||||
|
// Create a cookie store for session data.
|
||||||
|
cookieStore := sessions.NewCookieStore([]byte(c.Config.App.EncryptionKey))
|
||||||
|
cookieStore.Options.HttpOnly = true
|
||||||
|
cookieStore.Options.SameSite = http.SameSiteStrictMode
|
||||||
|
|
||||||
|
g.Use(
|
||||||
|
echomw.RemoveTrailingSlashWithConfig(echomw.TrailingSlashConfig{
|
||||||
|
RedirectCode: http.StatusMovedPermanently,
|
||||||
|
}),
|
||||||
|
echomw.Recover(),
|
||||||
|
echomw.Secure(),
|
||||||
|
echomw.RequestID(),
|
||||||
|
middleware.SetLogger(),
|
||||||
|
middleware.LogRequest(),
|
||||||
|
echomw.Gzip(),
|
||||||
|
echomw.TimeoutWithConfig(echomw.TimeoutConfig{
|
||||||
|
Timeout: c.Config.App.Timeout,
|
||||||
|
}),
|
||||||
|
middleware.Config(c.Config),
|
||||||
|
middleware.Session(cookieStore),
|
||||||
|
middleware.LoadAuthenticatedUser(c.Auth),
|
||||||
|
echomw.CSRFWithConfig(echomw.CSRFConfig{
|
||||||
|
TokenLookup: "form:csrf",
|
||||||
|
CookieHTTPOnly: true,
|
||||||
|
CookieSameSite: http.SameSiteStrictMode,
|
||||||
|
ContextKey: context.CSRFKey,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error handler.
|
||||||
|
c.Web.HTTPErrorHandler = new(Error).Page
|
||||||
|
|
||||||
|
// Initialize and register all handlers.
|
||||||
|
for _, h := range GetHandlers() {
|
||||||
|
if err := h.Init(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Routes(g)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
package routes
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/cookiejar"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"goweb/config"
|
"github.com/mikestefanello/pagoda/config"
|
||||||
"goweb/services"
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
@ -27,19 +28,22 @@ func TestMain(m *testing.M) {
|
||||||
|
|
||||||
// Start a new container
|
// Start a new container
|
||||||
c = services.NewContainer()
|
c = services.NewContainer()
|
||||||
defer func() {
|
|
||||||
if err := c.Shutdown(); err != nil {
|
|
||||||
c.Web.Logger.Fatal(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Start a test HTTP server
|
// Start a test HTTP server
|
||||||
BuildRouter(c)
|
if err := BuildRouter(c); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
srv = httptest.NewServer(c.Web)
|
srv = httptest.NewServer(c.Web)
|
||||||
|
|
||||||
// Run tests
|
// Run tests
|
||||||
exitVal := m.Run()
|
exitVal := m.Run()
|
||||||
|
|
||||||
|
// Shutdown the container and test server
|
||||||
|
if err := c.Shutdown(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
srv.Close()
|
srv.Close()
|
||||||
|
|
||||||
os.Exit(exitVal)
|
os.Exit(exitVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,8 +55,14 @@ type httpRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func request(t *testing.T) *httpRequest {
|
func request(t *testing.T) *httpRequest {
|
||||||
|
jar, err := cookiejar.New(nil)
|
||||||
|
require.NoError(t, err)
|
||||||
r := httpRequest{
|
r := httpRequest{
|
||||||
t: t,
|
t: t,
|
||||||
|
body: url.Values{},
|
||||||
|
client: http.Client{
|
||||||
|
Jar: jar,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return &r
|
return &r
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +72,7 @@ func (h *httpRequest) setClient(client http.Client) *httpRequest {
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpRequest) setRoute(route string, params ...interface{}) *httpRequest {
|
func (h *httpRequest) setRoute(route string, params ...any) *httpRequest {
|
||||||
h.route = srv.URL + c.Web.Reverse(route, params)
|
h.route = srv.URL + c.Web.Reverse(route, params)
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
@ -83,6 +93,18 @@ func (h *httpRequest) get() *httpResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpRequest) post() *httpResponse {
|
func (h *httpRequest) post() *httpResponse {
|
||||||
|
// Make a get request to get the CSRF token
|
||||||
|
doc := h.get().
|
||||||
|
assertStatusCode(http.StatusOK).
|
||||||
|
toDoc()
|
||||||
|
|
||||||
|
// Extract the CSRF and include it in the POST request body
|
||||||
|
csrf := doc.Find(`input[name="csrf"]`).First()
|
||||||
|
token, exists := csrf.Attr("value")
|
||||||
|
assert.True(h.t, exists)
|
||||||
|
h.body["csrf"] = []string{token}
|
||||||
|
|
||||||
|
// Make the POST requests
|
||||||
resp, err := h.client.PostForm(h.route, h.body)
|
resp, err := h.client.PostForm(h.route, h.body)
|
||||||
require.NoError(h.t, err)
|
require.NoError(h.t, err)
|
||||||
r := httpResponse{
|
r := httpResponse{
|
||||||
|
|
@ -102,7 +124,7 @@ func (h *httpResponse) assertStatusCode(code int) *httpResponse {
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *httpResponse) assertRedirect(t *testing.T, route string, params ...interface{}) *httpResponse {
|
func (h *httpResponse) assertRedirect(t *testing.T, route string, params ...any) *httpResponse {
|
||||||
assert.Equal(t, c.Web.Reverse(route, params), h.Header.Get("Location"))
|
assert.Equal(t, c.Web.Reverse(route, params), h.Header.Get("Location"))
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
44
pkg/handlers/search.go
Normal file
44
pkg/handlers/search.go
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/routenames"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/models"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/pages"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Search struct{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register(new(Search))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Search) Init(c *services.Container) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Search) Routes(g *echo.Group) {
|
||||||
|
g.GET("/search", h.Page).Name = routenames.Search
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Search) Page(ctx echo.Context) error {
|
||||||
|
// Fake search results.
|
||||||
|
results := make([]*models.SearchResult, 0, 5)
|
||||||
|
if search := ctx.QueryParam("query"); search != "" {
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
title := "Lorem ipsum example ddolor sit amet"
|
||||||
|
index := rand.Intn(len(title))
|
||||||
|
title = title[:index] + search + title[index:]
|
||||||
|
results = append(results, &models.SearchResult{
|
||||||
|
Title: title,
|
||||||
|
URL: fmt.Sprintf("https://www.%s.com", search),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pages.SearchResults(ctx, results)
|
||||||
|
}
|
||||||
71
pkg/handlers/task.go
Normal file
71
pkg/handlers/task.go
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/mikestefanello/backlite"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/msg"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/routenames"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/forms"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/ui/pages"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/form"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/tasks"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Task struct {
|
||||||
|
tasks *backlite.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Register(new(Task))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Task) Init(c *services.Container) error {
|
||||||
|
h.tasks = c.Tasks
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Task) Routes(g *echo.Group) {
|
||||||
|
g.GET("/task", h.Page).Name = routenames.Task
|
||||||
|
g.POST("/task", h.Submit).Name = routenames.TaskSubmit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Task) Page(ctx echo.Context) error {
|
||||||
|
return pages.AddTask(ctx, form.Get[forms.Task](ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Task) Submit(ctx echo.Context) error {
|
||||||
|
var input forms.Task
|
||||||
|
|
||||||
|
err := form.Submit(ctx, &input)
|
||||||
|
|
||||||
|
switch err.(type) {
|
||||||
|
case nil:
|
||||||
|
case validator.ValidationErrors:
|
||||||
|
return h.Page(ctx)
|
||||||
|
default:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the task
|
||||||
|
_, err = h.tasks.
|
||||||
|
Add(tasks.ExampleTask{
|
||||||
|
Message: input.Message,
|
||||||
|
}).
|
||||||
|
Wait(time.Duration(input.Delay) * time.Second).
|
||||||
|
Save()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fail(err, "unable to create a task")
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Success(ctx, fmt.Sprintf("The task has been created. Check the logs in %d seconds.", input.Delay))
|
||||||
|
form.Clear(ctx)
|
||||||
|
|
||||||
|
return h.Page(ctx)
|
||||||
|
}
|
||||||
97
pkg/htmx/htmx.go
Normal file
97
pkg/htmx/htmx.go
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
package htmx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Request headers: https://htmx.org/docs/#request-headers
|
||||||
|
const (
|
||||||
|
HeaderBoosted = "HX-Boosted"
|
||||||
|
HeaderHistoryRestoreRequest = "HX-History-Restore-Request"
|
||||||
|
HeaderPrompt = "HX-Prompt"
|
||||||
|
HeaderRequest = "HX-Request"
|
||||||
|
HeaderTarget = "HX-Target"
|
||||||
|
HeaderTrigger = "HX-Trigger"
|
||||||
|
HeaderTriggerName = "HX-Trigger-Name"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Response headers: https://htmx.org/docs/#response-headers
|
||||||
|
const (
|
||||||
|
HeaderPushURL = "HX-Push-Url"
|
||||||
|
HeaderRedirect = "HX-Redirect"
|
||||||
|
HeaderReplaceURL = "HX-Replace-Url"
|
||||||
|
HeaderRefresh = "HX-Refresh"
|
||||||
|
HeaderTriggerAfterSettle = "HX-Trigger-After-Settle"
|
||||||
|
HeaderTriggerAfterSwap = "HX-Trigger-After-Swap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Request contains data that HTMX provides during requests.
|
||||||
|
Request struct {
|
||||||
|
Enabled bool
|
||||||
|
Boosted bool
|
||||||
|
HistoryRestore bool
|
||||||
|
Trigger string
|
||||||
|
TriggerName string
|
||||||
|
Target string
|
||||||
|
Prompt string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response contain data that the server can communicate back to HTMX.
|
||||||
|
Response struct {
|
||||||
|
PushURL string
|
||||||
|
Redirect string
|
||||||
|
Refresh bool
|
||||||
|
ReplaceURL string
|
||||||
|
Trigger string
|
||||||
|
TriggerAfterSwap string
|
||||||
|
TriggerAfterSettle string
|
||||||
|
NoContent bool
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetRequest extracts HTMX data from the request,
|
||||||
|
func GetRequest(ctx echo.Context) *Request {
|
||||||
|
return context.Cache(ctx, context.HTMXRequestKey, func(ctx echo.Context) *Request {
|
||||||
|
return &Request{
|
||||||
|
Enabled: ctx.Request().Header.Get(HeaderRequest) == "true",
|
||||||
|
Boosted: ctx.Request().Header.Get(HeaderBoosted) == "true",
|
||||||
|
Trigger: ctx.Request().Header.Get(HeaderTrigger),
|
||||||
|
TriggerName: ctx.Request().Header.Get(HeaderTriggerName),
|
||||||
|
Target: ctx.Request().Header.Get(HeaderTarget),
|
||||||
|
Prompt: ctx.Request().Header.Get(HeaderPrompt),
|
||||||
|
HistoryRestore: ctx.Request().Header.Get(HeaderHistoryRestoreRequest) == "true",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply applies data from a Response to a server response.
|
||||||
|
func (r Response) Apply(ctx echo.Context) {
|
||||||
|
if r.PushURL != "" {
|
||||||
|
ctx.Response().Header().Set(HeaderPushURL, r.PushURL)
|
||||||
|
}
|
||||||
|
if r.Redirect != "" {
|
||||||
|
ctx.Response().Header().Set(HeaderRedirect, r.Redirect)
|
||||||
|
}
|
||||||
|
if r.Refresh {
|
||||||
|
ctx.Response().Header().Set(HeaderRefresh, "true")
|
||||||
|
}
|
||||||
|
if r.Trigger != "" {
|
||||||
|
ctx.Response().Header().Set(HeaderTrigger, r.Trigger)
|
||||||
|
}
|
||||||
|
if r.TriggerAfterSwap != "" {
|
||||||
|
ctx.Response().Header().Set(HeaderTriggerAfterSwap, r.TriggerAfterSwap)
|
||||||
|
}
|
||||||
|
if r.TriggerAfterSettle != "" {
|
||||||
|
ctx.Response().Header().Set(HeaderTriggerAfterSettle, r.TriggerAfterSettle)
|
||||||
|
}
|
||||||
|
if r.ReplaceURL != "" {
|
||||||
|
ctx.Response().Header().Set(HeaderReplaceURL, r.ReplaceURL)
|
||||||
|
}
|
||||||
|
if r.NoContent {
|
||||||
|
ctx.Response().Status = http.StatusNoContent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"goweb/tests"
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/tests"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
|
@ -19,21 +20,29 @@ func TestSetRequest(t *testing.T) {
|
||||||
ctx.Request().Header.Set(HeaderTriggerName, "b")
|
ctx.Request().Header.Set(HeaderTriggerName, "b")
|
||||||
ctx.Request().Header.Set(HeaderTarget, "c")
|
ctx.Request().Header.Set(HeaderTarget, "c")
|
||||||
ctx.Request().Header.Set(HeaderPrompt, "d")
|
ctx.Request().Header.Set(HeaderPrompt, "d")
|
||||||
|
ctx.Request().Header.Set(HeaderHistoryRestoreRequest, "true")
|
||||||
|
|
||||||
r := GetRequest(ctx)
|
r := GetRequest(ctx)
|
||||||
assert.Equal(t, true, r.Enabled)
|
assert.Equal(t, true, r.Enabled)
|
||||||
assert.Equal(t, true, r.Boosted)
|
assert.Equal(t, true, r.Boosted)
|
||||||
|
assert.Equal(t, true, r.HistoryRestore)
|
||||||
assert.Equal(t, "a", r.Trigger)
|
assert.Equal(t, "a", r.Trigger)
|
||||||
assert.Equal(t, "b", r.TriggerName)
|
assert.Equal(t, "b", r.TriggerName)
|
||||||
assert.Equal(t, "c", r.Target)
|
assert.Equal(t, "c", r.Target)
|
||||||
assert.Equal(t, "d", r.Prompt)
|
assert.Equal(t, "d", r.Prompt)
|
||||||
|
|
||||||
|
cached := context.Cache(ctx, context.HTMXRequestKey, func(ctx echo.Context) *Request {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
assert.Equal(t, r, cached)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResponse_Apply(t *testing.T) {
|
func TestResponse_Apply(t *testing.T) {
|
||||||
ctx, _ := tests.NewContext(echo.New(), "/")
|
ctx, _ := tests.NewContext(echo.New(), "/")
|
||||||
r := Response{
|
r := Response{
|
||||||
Push: "a",
|
PushURL: "a",
|
||||||
Redirect: "b",
|
Redirect: "b",
|
||||||
|
ReplaceURL: "f",
|
||||||
Refresh: true,
|
Refresh: true,
|
||||||
Trigger: "c",
|
Trigger: "c",
|
||||||
TriggerAfterSwap: "d",
|
TriggerAfterSwap: "d",
|
||||||
|
|
@ -42,11 +51,12 @@ func TestResponse_Apply(t *testing.T) {
|
||||||
}
|
}
|
||||||
r.Apply(ctx)
|
r.Apply(ctx)
|
||||||
|
|
||||||
assert.Equal(t, "a", ctx.Response().Header().Get(HeaderPush))
|
assert.Equal(t, "a", ctx.Response().Header().Get(HeaderPushURL))
|
||||||
assert.Equal(t, "b", ctx.Response().Header().Get(HeaderRedirect))
|
assert.Equal(t, "b", ctx.Response().Header().Get(HeaderRedirect))
|
||||||
assert.Equal(t, "true", ctx.Response().Header().Get(HeaderRefresh))
|
assert.Equal(t, "true", ctx.Response().Header().Get(HeaderRefresh))
|
||||||
assert.Equal(t, "c", ctx.Response().Header().Get(HeaderTrigger))
|
assert.Equal(t, "c", ctx.Response().Header().Get(HeaderTrigger))
|
||||||
assert.Equal(t, "d", ctx.Response().Header().Get(HeaderTriggerAfterSwap))
|
assert.Equal(t, "d", ctx.Response().Header().Get(HeaderTriggerAfterSwap))
|
||||||
assert.Equal(t, "e", ctx.Response().Header().Get(HeaderTriggerAfterSettle))
|
assert.Equal(t, "e", ctx.Response().Header().Get(HeaderTriggerAfterSettle))
|
||||||
|
assert.Equal(t, "f", ctx.Response().Header().Get(HeaderReplaceURL))
|
||||||
assert.Equal(t, http.StatusNoContent, ctx.Response().Status)
|
assert.Equal(t, http.StatusNoContent, ctx.Response().Status)
|
||||||
}
|
}
|
||||||
27
pkg/log/log.go
Normal file
27
pkg/log/log.go
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set sets a logger in the context.
|
||||||
|
func Set(ctx echo.Context, logger *slog.Logger) {
|
||||||
|
ctx.Set(context.LoggerKey, logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ctx returns the logger stored in context, or provides the default logger if one is not present.
|
||||||
|
func Ctx(ctx echo.Context) *slog.Logger {
|
||||||
|
if l, ok := ctx.Get(context.LoggerKey).(*slog.Logger); ok {
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
return Default()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default returns the default logger.
|
||||||
|
func Default() *slog.Logger {
|
||||||
|
return slog.Default()
|
||||||
|
}
|
||||||
21
pkg/log/log_test.go
Normal file
21
pkg/log/log_test.go
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/tests"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCtxSet(t *testing.T) {
|
||||||
|
ctx, _ := tests.NewContext(echo.New(), "/")
|
||||||
|
logger := Ctx(ctx)
|
||||||
|
assert.NotNil(t, logger)
|
||||||
|
|
||||||
|
logger = logger.With("a", "b")
|
||||||
|
Set(ctx, logger)
|
||||||
|
|
||||||
|
got := Ctx(ctx)
|
||||||
|
assert.Equal(t, got, logger)
|
||||||
|
}
|
||||||
120
pkg/middleware/auth.go
Normal file
120
pkg/middleware/auth.go
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/mikestefanello/pagoda/ent"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/log"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/msg"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/routenames"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/services"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LoadAuthenticatedUser loads the authenticated user, if one, and stores in context.
|
||||||
|
func LoadAuthenticatedUser(authClient *services.AuthClient) echo.MiddlewareFunc {
|
||||||
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
u, err := authClient.GetAuthenticatedUser(c)
|
||||||
|
switch err.(type) {
|
||||||
|
case *ent.NotFoundError:
|
||||||
|
log.Ctx(c).Warn("auth user not found")
|
||||||
|
case services.NotAuthenticatedError:
|
||||||
|
case nil:
|
||||||
|
c.Set(context.AuthenticatedUserKey, u)
|
||||||
|
default:
|
||||||
|
return echo.NewHTTPError(
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
fmt.Sprintf("error querying for authenticated user: %v", err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return next(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadValidPasswordToken loads a valid password token entity that matches the user and token
|
||||||
|
// provided in path parameters
|
||||||
|
// If the token is invalid, the user will be redirected to the forgot password route
|
||||||
|
// This requires that the user owning the token is loaded in to context.
|
||||||
|
func LoadValidPasswordToken(authClient *services.AuthClient) echo.MiddlewareFunc {
|
||||||
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
// Extract the user parameter
|
||||||
|
if c.Get(context.UserKey) == nil {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
usr := c.Get(context.UserKey).(*ent.User)
|
||||||
|
|
||||||
|
// Extract the token ID.
|
||||||
|
tokenID, err := strconv.Atoi(c.Param("password_token"))
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to load a valid password token.
|
||||||
|
token, err := authClient.GetValidPasswordToken(
|
||||||
|
c,
|
||||||
|
usr.ID,
|
||||||
|
tokenID,
|
||||||
|
c.Param("token"),
|
||||||
|
)
|
||||||
|
|
||||||
|
switch err.(type) {
|
||||||
|
case nil:
|
||||||
|
c.Set(context.PasswordTokenKey, token)
|
||||||
|
return next(c)
|
||||||
|
case services.InvalidPasswordTokenError:
|
||||||
|
msg.Warning(c, "The link is either invalid or has expired. Please request a new one.")
|
||||||
|
return c.Redirect(http.StatusFound, c.Echo().Reverse(routenames.ForgotPassword))
|
||||||
|
default:
|
||||||
|
return echo.NewHTTPError(
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
fmt.Sprintf("error loading password token: %v", err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequireAuthentication requires that the user be authenticated in order to proceed.
|
||||||
|
func RequireAuthentication(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
if u := c.Get(context.AuthenticatedUserKey); u == nil {
|
||||||
|
return echo.NewHTTPError(http.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
|
||||||
|
return next(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequireNoAuthentication requires that the user not be authenticated in order to proceed.
|
||||||
|
func RequireNoAuthentication(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
if u := c.Get(context.AuthenticatedUserKey); u != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusForbidden)
|
||||||
|
}
|
||||||
|
|
||||||
|
return next(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequireAdmin requires that the authenticated user be an admin in order to proceed.
|
||||||
|
func RequireAdmin(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
return func(c echo.Context) error {
|
||||||
|
if u := c.Get(context.AuthenticatedUserKey); u != nil {
|
||||||
|
if user, ok := u.(*ent.User); ok {
|
||||||
|
if user.Admin {
|
||||||
|
return next(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return echo.NewHTTPError(http.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
goctx "context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"goweb/context"
|
"github.com/mikestefanello/pagoda/ent"
|
||||||
"goweb/ent"
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
"goweb/tests"
|
"github.com/mikestefanello/pagoda/pkg/tests"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
|
@ -40,7 +41,7 @@ func TestRequireAuthentication(t *testing.T) {
|
||||||
tests.InitSession(ctx)
|
tests.InitSession(ctx)
|
||||||
|
|
||||||
// Not logged in
|
// Not logged in
|
||||||
err := tests.ExecuteMiddleware(ctx, RequireAuthentication())
|
err := tests.ExecuteMiddleware(ctx, RequireAuthentication)
|
||||||
tests.AssertHTTPErrorCode(t, err, http.StatusUnauthorized)
|
tests.AssertHTTPErrorCode(t, err, http.StatusUnauthorized)
|
||||||
|
|
||||||
// Login
|
// Login
|
||||||
|
|
@ -49,7 +50,7 @@ func TestRequireAuthentication(t *testing.T) {
|
||||||
_ = tests.ExecuteMiddleware(ctx, LoadAuthenticatedUser(c.Auth))
|
_ = tests.ExecuteMiddleware(ctx, LoadAuthenticatedUser(c.Auth))
|
||||||
|
|
||||||
// Logged in
|
// Logged in
|
||||||
err = tests.ExecuteMiddleware(ctx, RequireAuthentication())
|
err = tests.ExecuteMiddleware(ctx, RequireAuthentication)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,7 +59,7 @@ func TestRequireNoAuthentication(t *testing.T) {
|
||||||
tests.InitSession(ctx)
|
tests.InitSession(ctx)
|
||||||
|
|
||||||
// Not logged in
|
// Not logged in
|
||||||
err := tests.ExecuteMiddleware(ctx, RequireNoAuthentication())
|
err := tests.ExecuteMiddleware(ctx, RequireNoAuthentication)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
// Login
|
// Login
|
||||||
|
|
@ -67,7 +68,7 @@ func TestRequireNoAuthentication(t *testing.T) {
|
||||||
_ = tests.ExecuteMiddleware(ctx, LoadAuthenticatedUser(c.Auth))
|
_ = tests.ExecuteMiddleware(ctx, LoadAuthenticatedUser(c.Auth))
|
||||||
|
|
||||||
// Logged in
|
// Logged in
|
||||||
err = tests.ExecuteMiddleware(ctx, RequireNoAuthentication())
|
err = tests.ExecuteMiddleware(ctx, RequireNoAuthentication)
|
||||||
tests.AssertHTTPErrorCode(t, err, http.StatusForbidden)
|
tests.AssertHTTPErrorCode(t, err, http.StatusForbidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,17 +80,17 @@ func TestLoadValidPasswordToken(t *testing.T) {
|
||||||
err := tests.ExecuteMiddleware(ctx, LoadValidPasswordToken(c.Auth))
|
err := tests.ExecuteMiddleware(ctx, LoadValidPasswordToken(c.Auth))
|
||||||
tests.AssertHTTPErrorCode(t, err, http.StatusInternalServerError)
|
tests.AssertHTTPErrorCode(t, err, http.StatusInternalServerError)
|
||||||
|
|
||||||
// Add user context but no password token and expect a redirect
|
// Add user and password token context but no token and expect a redirect
|
||||||
ctx.SetParamNames("user")
|
ctx.SetParamNames("user", "password_token")
|
||||||
ctx.SetParamValues(fmt.Sprintf("%d", usr.ID))
|
ctx.SetParamValues(fmt.Sprintf("%d", usr.ID), "1")
|
||||||
_ = tests.ExecuteMiddleware(ctx, LoadUser(c.ORM))
|
_ = tests.ExecuteMiddleware(ctx, LoadUser(c.ORM))
|
||||||
err = tests.ExecuteMiddleware(ctx, LoadValidPasswordToken(c.Auth))
|
err = tests.ExecuteMiddleware(ctx, LoadValidPasswordToken(c.Auth))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, http.StatusFound, ctx.Response().Status)
|
assert.Equal(t, http.StatusFound, ctx.Response().Status)
|
||||||
|
|
||||||
// Add user context and invalid password token and expect a redirect
|
// Add user context and invalid password token and expect a redirect
|
||||||
ctx.SetParamNames("user", "password_token")
|
ctx.SetParamNames("user", "password_token", "token")
|
||||||
ctx.SetParamValues(fmt.Sprintf("%d", usr.ID), "faketoken")
|
ctx.SetParamValues(fmt.Sprintf("%d", usr.ID), "1", "faketoken")
|
||||||
_ = tests.ExecuteMiddleware(ctx, LoadUser(c.ORM))
|
_ = tests.ExecuteMiddleware(ctx, LoadUser(c.ORM))
|
||||||
err = tests.ExecuteMiddleware(ctx, LoadValidPasswordToken(c.Auth))
|
err = tests.ExecuteMiddleware(ctx, LoadValidPasswordToken(c.Auth))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
@ -100,8 +101,8 @@ func TestLoadValidPasswordToken(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Add user and valid password token
|
// Add user and valid password token
|
||||||
ctx.SetParamNames("user", "password_token")
|
ctx.SetParamNames("user", "password_token", "token")
|
||||||
ctx.SetParamValues(fmt.Sprintf("%d", usr.ID), token)
|
ctx.SetParamValues(fmt.Sprintf("%d", usr.ID), fmt.Sprintf("%d", pt.ID), token)
|
||||||
_ = tests.ExecuteMiddleware(ctx, LoadUser(c.ORM))
|
_ = tests.ExecuteMiddleware(ctx, LoadUser(c.ORM))
|
||||||
err = tests.ExecuteMiddleware(ctx, LoadValidPasswordToken(c.Auth))
|
err = tests.ExecuteMiddleware(ctx, LoadValidPasswordToken(c.Auth))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
@ -109,3 +110,36 @@ func TestLoadValidPasswordToken(t *testing.T) {
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
assert.Equal(t, pt.ID, ctxPt.ID)
|
assert.Equal(t, pt.ID, ctxPt.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRequireAdmin(t *testing.T) {
|
||||||
|
ctx, _ := tests.NewContext(c.Web, "/")
|
||||||
|
tests.InitSession(ctx)
|
||||||
|
|
||||||
|
// Not logged in
|
||||||
|
err := tests.ExecuteMiddleware(ctx, RequireAdmin)
|
||||||
|
tests.AssertHTTPErrorCode(t, err, http.StatusUnauthorized)
|
||||||
|
|
||||||
|
// Login as a non-admin
|
||||||
|
err = c.Auth.Login(ctx, usr.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_ = tests.ExecuteMiddleware(ctx, LoadAuthenticatedUser(c.Auth))
|
||||||
|
|
||||||
|
// Logged in as a non-admin
|
||||||
|
err = tests.ExecuteMiddleware(ctx, RequireAdmin)
|
||||||
|
tests.AssertHTTPErrorCode(t, err, http.StatusUnauthorized)
|
||||||
|
|
||||||
|
// Create an admin and login
|
||||||
|
adm, err := tests.CreateUser(c.ORM)
|
||||||
|
require.NoError(t, err)
|
||||||
|
err = c.ORM.User.Update().
|
||||||
|
SetAdmin(true).
|
||||||
|
Exec(goctx.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
err = c.Auth.Login(ctx, adm.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_ = tests.ExecuteMiddleware(ctx, LoadAuthenticatedUser(c.Auth))
|
||||||
|
|
||||||
|
// Logged in as an admin
|
||||||
|
err = tests.ExecuteMiddleware(ctx, RequireAdmin)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
22
pkg/middleware/cache.go
Normal file
22
pkg/middleware/cache.go
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CacheControl sets a Cache-Control header with a given max age.
|
||||||
|
func CacheControl(maxAge time.Duration) echo.MiddlewareFunc {
|
||||||
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
return func(ctx echo.Context) error {
|
||||||
|
v := "no-cache, no-store"
|
||||||
|
if maxAge > 0 {
|
||||||
|
v = fmt.Sprintf("public, max-age=%.0f", maxAge.Seconds())
|
||||||
|
}
|
||||||
|
ctx.Response().Header().Set("Cache-Control", v)
|
||||||
|
return next(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
pkg/middleware/cache_test.go
Normal file
18
pkg/middleware/cache_test.go
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/tests"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCacheControl(t *testing.T) {
|
||||||
|
ctx, _ := tests.NewContext(c.Web, "/")
|
||||||
|
_ = tests.ExecuteMiddleware(ctx, CacheControl(time.Second*5))
|
||||||
|
assert.Equal(t, "public, max-age=5", ctx.Response().Header().Get("Cache-Control"))
|
||||||
|
_ = tests.ExecuteMiddleware(ctx, CacheControl(0))
|
||||||
|
assert.Equal(t, "no-cache, no-store", ctx.Response().Header().Get("Cache-Control"))
|
||||||
|
}
|
||||||
17
pkg/middleware/config.go
Normal file
17
pkg/middleware/config.go
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/config"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config stores the configuration in the request so it can be accessed by the ui.
|
||||||
|
func Config(cfg *config.Config) echo.MiddlewareFunc {
|
||||||
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
return func(ctx echo.Context) error {
|
||||||
|
ctx.Set(context.ConfigKey, cfg)
|
||||||
|
return next(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
pkg/middleware/config_test.go
Normal file
22
pkg/middleware/config_test.go
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mikestefanello/pagoda/config"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/tests"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConfig(t *testing.T) {
|
||||||
|
ctx, _ := tests.NewContext(c.Web, "/")
|
||||||
|
cfg := &config.Config{}
|
||||||
|
err := tests.ExecuteMiddleware(ctx, Config(cfg))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
got, ok := ctx.Get(context.ConfigKey).(*config.Config)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.Same(t, got, cfg)
|
||||||
|
}
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"goweb/context"
|
"github.com/mikestefanello/pagoda/ent"
|
||||||
"goweb/ent"
|
"github.com/mikestefanello/pagoda/ent/user"
|
||||||
"goweb/ent/user"
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LoadUser loads the user based on the ID provided as a path parameter
|
// LoadUser loads the user based on the ID provided as a path parameter.
|
||||||
func LoadUser(orm *ent.Client) echo.MiddlewareFunc {
|
func LoadUser(orm *ent.Client) echo.MiddlewareFunc {
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
|
|
@ -32,8 +33,10 @@ func LoadUser(orm *ent.Client) echo.MiddlewareFunc {
|
||||||
case *ent.NotFoundError:
|
case *ent.NotFoundError:
|
||||||
return echo.NewHTTPError(http.StatusNotFound)
|
return echo.NewHTTPError(http.StatusNotFound)
|
||||||
default:
|
default:
|
||||||
c.Logger().Error(err)
|
return echo.NewHTTPError(
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError)
|
http.StatusInternalServerError,
|
||||||
|
fmt.Sprintf("error querying user: %v", err),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,9 +4,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"goweb/context"
|
"github.com/mikestefanello/pagoda/ent"
|
||||||
"goweb/ent"
|
"github.com/mikestefanello/pagoda/pkg/context"
|
||||||
"goweb/tests"
|
"github.com/mikestefanello/pagoda/pkg/tests"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
73
pkg/middleware/log.go
Normal file
73
pkg/middleware/log.go
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/mikestefanello/pagoda/pkg/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetLogger initializes a logger for the current request and stores it in the context.
|
||||||
|
// It's recommended to have this executed after Echo's RequestID() middleware because it will add
|
||||||
|
// the request ID to the logger so that all log messages produced from this request have the
|
||||||
|
// request ID in it. You can modify this code to include any other fields that you want to always
|
||||||
|
// appear.
|
||||||
|
func SetLogger() echo.MiddlewareFunc {
|
||||||
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
return func(ctx echo.Context) error {
|
||||||
|
// Include the request ID in the logger
|
||||||
|
rID := ctx.Response().Header().Get(echo.HeaderXRequestID)
|
||||||
|
logger := log.Ctx(ctx).With("request_id", rID)
|
||||||
|
|
||||||
|
// TODO include other fields you may want in all logs for this request
|
||||||
|
log.Set(ctx, logger)
|
||||||
|
return next(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogRequest logs the current request
|
||||||
|
// Echo provides middleware similar to this, but we want to use our own logger
|
||||||
|
func LogRequest() echo.MiddlewareFunc {
|
||||||
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
return func(ctx echo.Context) (err error) {
|
||||||
|
req := ctx.Request()
|
||||||
|
res := ctx.Response()
|
||||||
|
|
||||||
|
// Track how long the request takes to complete
|
||||||
|
start := time.Now()
|
||||||
|
if err = next(ctx); err != nil {
|
||||||
|
ctx.Error(err)
|
||||||
|
}
|
||||||
|
stop := time.Now()
|
||||||
|
|
||||||
|
sub := log.Ctx(ctx).With(
|
||||||
|
"ip", ctx.RealIP(),
|
||||||
|
"host", req.Host,
|
||||||
|
"referer", req.Referer(),
|
||||||
|
"status", res.Status,
|
||||||
|
"bytes_in", func() string {
|
||||||
|
cl := req.Header.Get(echo.HeaderContentLength)
|
||||||
|
if cl == "" {
|
||||||
|
cl = "0"
|
||||||
|
}
|
||||||
|
return cl
|
||||||
|
}(),
|
||||||
|
"bytes_out", strconv.FormatInt(res.Size, 10),
|
||||||
|
"latency", stop.Sub(start).String(),
|
||||||
|
)
|
||||||
|
|
||||||
|
msg := fmt.Sprintf("%s %s", req.Method, req.URL.RequestURI())
|
||||||
|
|
||||||
|
if res.Status >= 500 {
|
||||||
|
sub.Error(msg)
|
||||||
|
} else {
|
||||||
|
sub.Info(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue