mirror of
https://github.com/Floriansylvain/RenewCMS.git
synced 2026-08-19 11:43:22 +02:00
Merge pull request #30 from Floriansylvain/feature/authMailing
Feature/auth mailing
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
ENVIRONMENT=development
|
ENVIRONMENT=development
|
||||||
|
HOST=example.com
|
||||||
PORT=8080
|
PORT=8080
|
||||||
|
JWT_SECRET=abc123
|
||||||
CORS_ALLOWED_ORIGINS=*
|
CORS_ALLOWED_ORIGINS=*
|
||||||
DB_FILE=./gohcms.db
|
DB_FILE=./gohcms.db
|
||||||
DOCKER_DB_FOLDER=./data
|
DOCKER_DB_FOLDER=./data
|
||||||
|
SMTP_EMAIL=a@b.c
|
||||||
|
SMTP_PASSWORD=12341234
|
||||||
|
SMTP_HOST=mail.service.abc
|
||||||
|
SMTP_PORT=465
|
||||||
|
|||||||
@@ -13,11 +13,19 @@ jobs:
|
|||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
environment: test
|
||||||
env:
|
env:
|
||||||
ENVIRONMENT: "development"
|
ENVIRONMENT: ${{ secrets.ENVIRONMENT }}
|
||||||
PORT: "42069"
|
HOST: ${{ secrets.HOST }}
|
||||||
CORS_ALLOWED_ORIGINS: "*"
|
PORT: ${{ secrets.PORT }}
|
||||||
DB_FILE: "./gohcms.db"
|
JWT_SECRET: ${{ secrets.JWT_SECRET }}
|
||||||
|
CORS_ALLOWED_ORIGINS: ${{ secrets.CORS_ALLOWED_ORIGINS }}
|
||||||
|
DB_FILE: ${{ secrets.DB_FILE }}
|
||||||
|
DOCKER_DB_FOLDER: ${{ secrets.DOCKER_DB_FOLDER }}
|
||||||
|
SMTP_EMAIL: ${{ secrets.SMTP_EMAIL }}
|
||||||
|
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
|
||||||
|
SMTP_HOST: ${{ secrets.SMTP_HOST }}
|
||||||
|
SMTP_PORT: ${{ secrets.SMTP_PORT }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
|||||||
@@ -40,12 +40,18 @@ of course required, but not necessarily via the `.env` file.
|
|||||||
### Environment variables
|
### Environment variables
|
||||||
|
|
||||||
| Name | Type | Description | Comment |
|
| Name | Type | Description | Comment |
|
||||||
|----------------------|--------|-----------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
|
|----------------------|--------|:----------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
|
||||||
| ENVIRONMENT | string | The environment the API is running in | required, `development` or `production` |
|
| ENVIRONMENT | string | environment the API is running in | required, `development` or `production` |
|
||||||
| PORT | int | The port the API will use | required |
|
| HOST | string | the host domain name for emails and callbacks | required |
|
||||||
| CORS_ALLOWED_ORIGINS | string | The allowed origins for CORS | required, semicolon separated list |
|
| PORT | int | port the API will use | required |
|
||||||
| DB_FILE | string | The path to the sqlite db file | required, can be at the root but name still required (e.g. `./gohcms.db`) ; have to end up with `.db` |
|
| JWT_SECRET | string | secret for the jwt auth | required |
|
||||||
| DOCKER_DB_FOLDER | string | The path to the sqlite db file's folder | required with docker, this will basically be the host machine folder (e.g. `./data`) that contains the sqlite db file |
|
| CORS_ALLOWED_ORIGINS | string | allowed origins for CORS | required, semicolon separated list |
|
||||||
|
| DB_FILE | string | path to the sqlite db file | required, can be at the root but name still required (e.g. `./gohcms.db`) ; have to end up with `.db` |
|
||||||
|
| DOCKER_DB_FOLDER | string | path to the sqlite db file's folder | required with docker, this will basically be the host machine folder (e.g. `./data`) that contains the sqlite db file |
|
||||||
|
| SMTP_EMAIL | string | sender email | required |
|
||||||
|
| SMTP_PASSWORD | string | smtp account password | required |
|
||||||
|
| SMTP_HOST | string | smtp server address | required |
|
||||||
|
| SMTP_PORT | int | smtp server port | required |
|
||||||
|
|
||||||
## API Usage
|
## API Usage
|
||||||
|
|
||||||
@@ -54,3 +60,7 @@ TODO
|
|||||||
## Demo
|
## Demo
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
|
## TODOs
|
||||||
|
|
||||||
|
- Cancel button when email validation pending or expired
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<body>
|
||||||
|
<h1>
|
||||||
|
<img src="{{.Host}}/static/gohcms-favicon-128.png" alt="G" style="width: 2.5rem"/>
|
||||||
|
GohCMS
|
||||||
|
</h1>
|
||||||
|
<main>
|
||||||
|
<p>You or someone tried to create a GohCMS admin account with this e-mail address. If you are not responsible for
|
||||||
|
this, please do not validate the account creation.</p>
|
||||||
|
<p><b>If you want to validate the account creation, please <a href="{{.Host}}/register/validate?c={{.VerificationCode}}" target="_blank">click HERE</a>.</b>
|
||||||
|
</p>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package gateways
|
||||||
|
|
||||||
|
import (
|
||||||
|
"GohCMS2/domain/gateways"
|
||||||
|
"bytes"
|
||||||
|
"embed"
|
||||||
|
"gopkg.in/gomail.v2"
|
||||||
|
"html/template"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MailRepository struct{}
|
||||||
|
|
||||||
|
//go:embed mail/templates/*
|
||||||
|
var mailTemplateFiles embed.FS
|
||||||
|
|
||||||
|
func (m MailRepository) Send(receiverAddress string, templateName string, data interface{}) error {
|
||||||
|
from := os.Getenv("SMTP_EMAIL")
|
||||||
|
password := os.Getenv("SMTP_PASSWORD")
|
||||||
|
smtpHost := os.Getenv("SMTP_HOST")
|
||||||
|
smtpPort, _ := strconv.Atoi(os.Getenv("SMTP_PORT"))
|
||||||
|
|
||||||
|
d := gomail.NewDialer(smtpHost, smtpPort, from, password)
|
||||||
|
|
||||||
|
tmpl, err := template.ParseFS(mailTemplateFiles, "mail/templates/"+templateName+".html")
|
||||||
|
if err != nil {
|
||||||
|
log.Println("error when template.ParseFS:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var body bytes.Buffer
|
||||||
|
err = tmpl.Execute(&body, data)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("error when tmpl.Execute:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := gomail.NewMessage()
|
||||||
|
msg.SetHeaders(map[string][]string{
|
||||||
|
"From": {"GohCMS <" + from + ">"},
|
||||||
|
"To": {receiverAddress},
|
||||||
|
"MIME-version": {"1.0"},
|
||||||
|
"Content-Type": {"text/html"},
|
||||||
|
"charset": {"UTF-8"},
|
||||||
|
"Subject": {"GohCMS | Action required"},
|
||||||
|
})
|
||||||
|
msg.SetBody("text/html", body.String())
|
||||||
|
|
||||||
|
if err := d.DialAndSend(msg); err != nil {
|
||||||
|
log.Println("error when sending email:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ gateways.IMailRepository = &MailRepository{}
|
||||||
@@ -11,6 +11,9 @@ type User struct {
|
|||||||
Username string `gorm:"unique;not null"`
|
Username string `gorm:"unique;not null"`
|
||||||
Password string `gorm:"not null"`
|
Password string `gorm:"not null"`
|
||||||
Email string `gorm:"unique;not null"`
|
Email string `gorm:"unique;not null"`
|
||||||
|
IsVerified bool `gorm:"default=false;not null"`
|
||||||
|
VerificationCode string `gorm:"unique;not null"`
|
||||||
|
VerificationExpiration time.Time `gorm:"not null"`
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
type PageRepository struct{}
|
type PageRepository struct{}
|
||||||
|
|
||||||
//go:embed web/templates/*
|
//go:embed web/templates/*
|
||||||
var templateFiles embed.FS
|
var webTemplateFiles embed.FS
|
||||||
|
|
||||||
func NewPageRepository() *PageRepository {
|
func NewPageRepository() *PageRepository {
|
||||||
return &PageRepository{}
|
return &PageRepository{}
|
||||||
@@ -18,7 +18,7 @@ func NewPageRepository() *PageRepository {
|
|||||||
|
|
||||||
func (p *PageRepository) Get(name string, data interface{}) ([]byte, error) {
|
func (p *PageRepository) Get(name string, data interface{}) ([]byte, error) {
|
||||||
var processedHTML bytes.Buffer
|
var processedHTML bytes.Buffer
|
||||||
tmpl, err := template.ParseFS(templateFiles, "web/templates/"+name+".html")
|
tmpl, err := template.ParseFS(webTemplateFiles, "web/templates/"+name+".html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,16 @@ func NewUserRepository(db *gorm.DB) *UserRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mapUserToDomain(user entity.User) domain.User {
|
func mapUserToDomain(user entity.User) domain.User {
|
||||||
return domain.FromDb(user.ID, user.Username, user.Password, user.Email, user.CreatedAt, user.UpdatedAt)
|
return domain.FromDb(
|
||||||
|
user.ID,
|
||||||
|
user.Username,
|
||||||
|
user.Password,
|
||||||
|
user.Email,
|
||||||
|
user.IsVerified,
|
||||||
|
user.VerificationCode,
|
||||||
|
user.VerificationExpiration,
|
||||||
|
user.CreatedAt, user.UpdatedAt,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserRepository) Get(id uint32) (domain.User, error) {
|
func (u *UserRepository) Get(id uint32) (domain.User, error) {
|
||||||
@@ -31,12 +40,15 @@ func (u *UserRepository) Get(id uint32) (domain.User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserRepository) Create(user domain.User) (domain.User, error) {
|
func (u *UserRepository) Create(user domain.User) (domain.User, error) {
|
||||||
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(user.Password), 14)
|
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(user.Password), 12)
|
||||||
|
hashedVerificationCode, _ := bcrypt.GenerateFromPassword([]byte(user.VerificationCode), 12)
|
||||||
|
|
||||||
creationResult := u.db.Create(&entity.User{
|
creationResult := u.db.Create(&entity.User{
|
||||||
Username: user.Username,
|
Username: user.Username,
|
||||||
Password: string(hashedPassword),
|
Password: string(hashedPassword),
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
|
VerificationCode: string(hashedVerificationCode),
|
||||||
|
VerificationExpiration: user.VerificationExpiration,
|
||||||
})
|
})
|
||||||
if creationResult.Error != nil {
|
if creationResult.Error != nil {
|
||||||
return domain.User{}, creationResult.Error
|
return domain.User{}, creationResult.Error
|
||||||
@@ -71,4 +83,20 @@ func (u *UserRepository) GetByUsername(username string) (domain.User, error) {
|
|||||||
return mapUserToDomain(user), nil
|
return mapUserToDomain(user), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UserRepository) UpdateVerificationStatus(userId uint32, isVerified bool) (domain.User, error) {
|
||||||
|
var user entity.User
|
||||||
|
err := u.db.Model(&entity.User{}).First(&user, userId).Error
|
||||||
|
if err != nil {
|
||||||
|
return domain.User{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
user.IsVerified = isVerified
|
||||||
|
err = u.db.Save(&user).Error
|
||||||
|
if err != nil {
|
||||||
|
return domain.User{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapUserToDomain(user), nil
|
||||||
|
}
|
||||||
|
|
||||||
var _ gateways.IUserRepository = &UserRepository{}
|
var _ gateways.IUserRepository = &UserRepository{}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<h1>GohCMS</h1>
|
<h1>GohCMS</h1>
|
||||||
<h2>Login</h2>
|
<h2>Login</h2>
|
||||||
</div>
|
</div>
|
||||||
<form action="login" class="" method="POST">
|
<form action="login" method="POST">
|
||||||
<div class="d-flex flex-column gap-4">
|
<div class="d-flex flex-column gap-4">
|
||||||
<div class="form-floating">
|
<div class="form-floating">
|
||||||
<input class="form-control {{ if .PageError.IsError }} is-invalid {{ end }}"
|
<input class="form-control {{ if .PageError.IsError }} is-invalid {{ end }}"
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>GohCMS | Setup</title>
|
||||||
|
{{.Head}}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.form-container {
|
||||||
|
max-width: 24rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="d-flex min-vh-100 vw-100 justify-content-center align-items-center text-dark">
|
||||||
|
<div class="container">
|
||||||
|
<div class="d-flex flex-column gap-5 m-auto form-container">
|
||||||
|
<div>
|
||||||
|
<h1>GohCMS</h1>
|
||||||
|
<h2>Verify your email</h2>
|
||||||
|
</div>
|
||||||
|
<p>An e-mail with the validation link was sent to the address you just registered.</p>
|
||||||
|
<button id="finalSetupFormButton" class="btn btn-outline-primary" type="button">
|
||||||
|
<span class="finalSetupFormButtonLoading visually-hidden spinner-border spinner-border-sm"
|
||||||
|
role="status"></span>
|
||||||
|
<span class="finalSetupFormButtonDefault">Cancel</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>GohCMS | Setup</title>
|
||||||
|
{{.Head}}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.form-container {
|
||||||
|
max-width: 24rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="d-flex min-vh-100 vw-100 justify-content-center align-items-center text-dark">
|
||||||
|
<div class="container">
|
||||||
|
<div class="d-flex flex-column gap-5 m-auto form-container">
|
||||||
|
<div>
|
||||||
|
<h1>GohCMS</h1>
|
||||||
|
<h2>E-mail verification</h2>
|
||||||
|
</div>
|
||||||
|
{{ if .PageError.IsError }}
|
||||||
|
<p>{{.PageError.Message}}</p>
|
||||||
|
{{ else }}
|
||||||
|
<p>Your e-mail was successfully validated!</p>
|
||||||
|
<form action="../home" method="get" class="d-flex">
|
||||||
|
<button class="btn btn-primary w-100" type="submit">
|
||||||
|
<span class="visually-hidden spinner-border spinner-border-sm"
|
||||||
|
role="status"></span>
|
||||||
|
<span>Continue</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const button = document.querySelector("button")
|
||||||
|
|
||||||
|
function setButtonLoading() {
|
||||||
|
button.classList.add("disabled")
|
||||||
|
button.querySelector("button > span + span").classList.add("visually-hidden")
|
||||||
|
button.querySelector("button > span:first-child").classList.remove("visually-hidden")
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubmit(event) {
|
||||||
|
setButtonLoading()
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('submit', onSubmit)
|
||||||
|
button.addEventListener('click', onSubmit)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>GohCMS | Setup</title>
|
|
||||||
{{.Head}}
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.form-container {
|
|
||||||
max-width: 24rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body class="d-flex min-vh-100 vw-100 justify-content-center align-items-center text-dark">
|
|
||||||
<div class="container">
|
|
||||||
<div class="d-flex flex-column gap-5 m-auto form-container">
|
|
||||||
<div>
|
|
||||||
<h1>GohCMS</h1>
|
|
||||||
<h2>Setup done!</h2>
|
|
||||||
</div>
|
|
||||||
<p>GohCMS is now ready.</p>
|
|
||||||
<button id="finalSetupFormButton" class="btn btn-primary" type="button">
|
|
||||||
<span class="finalSetupFormButtonLoading visually-hidden spinner-border spinner-border-sm"
|
|
||||||
role="status"></span>
|
|
||||||
<span class="finalSetupFormButtonDefault">Finish</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
const button = document.querySelector("#finalSetupFormButton")
|
|
||||||
|
|
||||||
function setButtonLoading() {
|
|
||||||
button.classList.add("disabled")
|
|
||||||
button.querySelector(".finalSetupFormButtonDefault").classList.add("visually-hidden")
|
|
||||||
button.querySelector(".finalSetupFormButtonLoading").classList.remove("visually-hidden")
|
|
||||||
}
|
|
||||||
|
|
||||||
function onFinalSetupFormSubmit() {
|
|
||||||
setButtonLoading()
|
|
||||||
window.location.replace("/home")
|
|
||||||
}
|
|
||||||
|
|
||||||
button.addEventListener('click', onFinalSetupFormSubmit)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
+31
-5
@@ -6,6 +6,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/jwtauth/v5"
|
"github.com/go-chi/jwtauth/v5"
|
||||||
|
"github.com/google/uuid"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -61,6 +62,21 @@ func IsLoggedIn(r *http.Request) bool {
|
|||||||
return token != nil && err == nil
|
return token != nil && err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsVerified(r *http.Request) bool {
|
||||||
|
token, err := jwtauth.VerifyRequest(
|
||||||
|
TokenAuth,
|
||||||
|
r,
|
||||||
|
jwtauth.TokenFromCookie,
|
||||||
|
jwtauth.TokenFromHeader,
|
||||||
|
jwtauth.TokenFromQuery)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
userId := token.PrivateClaims()["user_id"].(float64)
|
||||||
|
currentUser, _ := Container.GetUserUseCase.GetUser(uint32(userId))
|
||||||
|
return currentUser.IsVerified
|
||||||
|
}
|
||||||
|
|
||||||
func getUserFromCredentials(credentials LoginCredentials) (user.User, error) {
|
func getUserFromCredentials(credentials LoginCredentials) (user.User, error) {
|
||||||
dbUser, err := Container.GetUserUseCase.GetUserByUsername(credentials.Username)
|
dbUser, err := Container.GetUserUseCase.GetUserByUsername(credentials.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -75,6 +91,19 @@ func getUserFromCredentials(credentials LoginCredentials) (user.User, error) {
|
|||||||
return dbUser, nil
|
return dbUser, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getNewUser(newUserCredentials RegisterCredentials, verificationCode string) (user.User, error) {
|
||||||
|
createdUser, err := Container.CreateUserUseCase.CreateUser(useCases.CreateUserCommand{
|
||||||
|
Username: newUserCredentials.Username,
|
||||||
|
Password: newUserCredentials.Password,
|
||||||
|
Email: newUserCredentials.Email,
|
||||||
|
VerificationCode: verificationCode,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return user.User{}, err
|
||||||
|
}
|
||||||
|
return createdUser, nil
|
||||||
|
}
|
||||||
|
|
||||||
func login(w http.ResponseWriter, r *http.Request) {
|
func login(w http.ResponseWriter, r *http.Request) {
|
||||||
var credentials LoginCredentials
|
var credentials LoginCredentials
|
||||||
|
|
||||||
@@ -120,11 +149,8 @@ func register(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
createdUser, err := Container.CreateUserUseCase.CreateUser(useCases.CreateUserCommand{
|
verificationCode := uuid.NewString()
|
||||||
Username: credentials.Username,
|
createdUser, err := getNewUser(credentials, verificationCode)
|
||||||
Password: credentials.Password,
|
|
||||||
Email: credentials.Email,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -16,8 +16,10 @@ type UseCases struct {
|
|||||||
ListPostsUseCase *useCases.ListPostsUseCase
|
ListPostsUseCase *useCases.ListPostsUseCase
|
||||||
GetUserUseCase *useCases.GetUserUseCase
|
GetUserUseCase *useCases.GetUserUseCase
|
||||||
CreateUserUseCase *useCases.CreateUserUseCase
|
CreateUserUseCase *useCases.CreateUserUseCase
|
||||||
|
UpdateUserUseCase *useCases.UpdateUserUseCase
|
||||||
ListUsersUseCase *useCases.ListUsersUseCase
|
ListUsersUseCase *useCases.ListUsersUseCase
|
||||||
GetPageUseCase *useCases.GetPageUseCase
|
GetPageUseCase *useCases.GetPageUseCase
|
||||||
|
SendMailUseCase *useCases.SendMailUseCase
|
||||||
}
|
}
|
||||||
|
|
||||||
var Container *UseCases
|
var Container *UseCases
|
||||||
@@ -48,8 +50,10 @@ func InitContainer() {
|
|||||||
ListPostsUseCase: useCases.NewListPostsUseCase(db),
|
ListPostsUseCase: useCases.NewListPostsUseCase(db),
|
||||||
GetUserUseCase: useCases.NewGetUserUseCase(db),
|
GetUserUseCase: useCases.NewGetUserUseCase(db),
|
||||||
CreateUserUseCase: useCases.NewCreateUserUseCase(db),
|
CreateUserUseCase: useCases.NewCreateUserUseCase(db),
|
||||||
|
UpdateUserUseCase: useCases.NewUpdateUserUseCase(db),
|
||||||
ListUsersUseCase: useCases.NewListUsersUseCase(db),
|
ListUsersUseCase: useCases.NewListUsersUseCase(db),
|
||||||
GetPageUseCase: useCases.NewGetPageUseCase(),
|
GetPageUseCase: useCases.NewGetPageUseCase(),
|
||||||
|
SendMailUseCase: useCases.NewSendMailUseCase(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
err := digContainer.Invoke(func(useCases *UseCases) { Container = useCases })
|
err := digContainer.Invoke(func(useCases *UseCases) { Container = useCases })
|
||||||
|
|||||||
+28
-1
@@ -47,6 +47,26 @@ func IsLoggedInMiddleware(next http.Handler) http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsVerifiedMiddleware(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !IsVerified(r) {
|
||||||
|
http.Redirect(w, r, "/register/pending", http.StatusSeeOther)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsNotVerifiedMiddleware(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if IsVerified(r) {
|
||||||
|
http.Redirect(w, r, "/register/pending", http.StatusSeeOther)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func GetLogin(w http.ResponseWriter, r *http.Request) {
|
func GetLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, LoginRoute, http.StatusPermanentRedirect)
|
http.Redirect(w, r, LoginRoute, http.StatusPermanentRedirect)
|
||||||
}
|
}
|
||||||
@@ -91,7 +111,14 @@ func NewPageRouter() http.Handler {
|
|||||||
|
|
||||||
r.Group(func(r chi.Router) {
|
r.Group(func(r chi.Router) {
|
||||||
r.Use(IsLoggedInMiddleware)
|
r.Use(IsLoggedInMiddleware)
|
||||||
r.Get("/register-confirm", GetRegisterConfirmPage)
|
r.Use(IsNotVerifiedMiddleware)
|
||||||
|
r.Get("/register/pending", GetRegisterPendingPage)
|
||||||
|
r.Get("/register/validate", GetRegisterValidatePage)
|
||||||
|
})
|
||||||
|
|
||||||
|
r.Group(func(r chi.Router) {
|
||||||
|
r.Use(IsLoggedInMiddleware)
|
||||||
|
r.Use(IsVerifiedMiddleware)
|
||||||
r.Get("/home", GetHomePage)
|
r.Get("/home", GetHomePage)
|
||||||
r.Get("/post", GetPostsPage)
|
r.Get("/post", GetPostsPage)
|
||||||
r.Get("/post/edit", GetPostEditPage)
|
r.Get("/post/edit", GetPostEditPage)
|
||||||
|
|||||||
+19
-19
@@ -1,8 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"github.com/google/uuid"
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
@@ -29,7 +28,7 @@ func GetRegisterPageHandler(registerPage *RegisterPage) http.HandlerFunc {
|
|||||||
PostRegisterPage(w, r)
|
PostRegisterPage(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bs, err := Container.GetPageUseCase.GetPage("setup1", map[string]interface{}{
|
bs, err := Container.GetPageUseCase.GetPage("register", map[string]interface{}{
|
||||||
"PageError": registerPage.PageError,
|
"PageError": registerPage.PageError,
|
||||||
"Username": registerPage.Username,
|
"Username": registerPage.Username,
|
||||||
"Email": registerPage.Email,
|
"Email": registerPage.Email,
|
||||||
@@ -45,11 +44,12 @@ func GetRegisterPageHandler(registerPage *RegisterPage) http.HandlerFunc {
|
|||||||
func PostRegisterPage(w http.ResponseWriter, r *http.Request) {
|
func PostRegisterPage(w http.ResponseWriter, r *http.Request) {
|
||||||
_ = r.ParseForm()
|
_ = r.ParseForm()
|
||||||
|
|
||||||
credentials, err := json.Marshal(&RegisterCredentials{
|
credentials := RegisterCredentials{
|
||||||
Username: r.FormValue("username"),
|
Username: r.FormValue("username"),
|
||||||
Password: r.FormValue("password"),
|
Password: r.FormValue("password"),
|
||||||
Email: r.FormValue("email"),
|
Email: r.FormValue("email"),
|
||||||
})
|
}
|
||||||
|
err := validate.Struct(credentials)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.Method = http.MethodGet
|
r.Method = http.MethodGet
|
||||||
GetRegisterPageHandler(&RegisterPage{
|
GetRegisterPageHandler(&RegisterPage{
|
||||||
@@ -60,22 +60,22 @@ func PostRegisterPage(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := http.Post(
|
verificationCode := uuid.NewString()
|
||||||
"http://localhost:"+os.Getenv("PORT")+"/v1/auth/register",
|
createdUser, err := getNewUser(credentials, verificationCode)
|
||||||
"application/json",
|
if err != nil {
|
||||||
bytes.NewBuffer(credentials))
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
|
||||||
if err != nil || response.StatusCode != http.StatusOK {
|
|
||||||
r.Method = http.MethodGet
|
|
||||||
GetRegisterPageHandler(&RegisterPage{
|
|
||||||
PageError: NewPageError("Username should be between 3 and 20 characters long, password should be between 8 and 20 characters long, and email should be a valid email address."),
|
|
||||||
Username: r.FormValue("username"),
|
|
||||||
Email: r.FormValue("email"),
|
|
||||||
})(w, r)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Set-Cookie", response.Header.Get("Set-Cookie"))
|
err = Container.SendMailUseCase.SendMail(createdUser.Email, "mailValidation", map[string]string{
|
||||||
|
"Host": os.Getenv("HOST"),
|
||||||
|
"VerificationCode": verificationCode,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
http.Redirect(w, r, "/register-confirm", http.StatusSeeOther)
|
_ = SetJwtCookie(&w, createdUser.ID)
|
||||||
|
|
||||||
|
http.Redirect(w, r, "/register/pending", http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetRegisterConfirmPage(w http.ResponseWriter, _ *http.Request) {
|
|
||||||
registerConfirmTmpl, _ := Container.GetPageUseCase.GetPage("setup2", map[string]interface{}{
|
|
||||||
"Head": headTmpl,
|
|
||||||
})
|
|
||||||
_, _ = w.Write(registerConfirmTmpl)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
func GetRegisterPendingPage(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
registerPendingTmpl, _ := Container.GetPageUseCase.GetPage("registerPending", map[string]interface{}{
|
||||||
|
"Head": headTmpl,
|
||||||
|
})
|
||||||
|
_, _ = w.Write(registerPendingTmpl)
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-chi/jwtauth/v5"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetRegisterValidatePage(w http.ResponseWriter, r *http.Request) {
|
||||||
|
queryVerificationCode := r.URL.Query().Get("c")
|
||||||
|
if queryVerificationCode == "" {
|
||||||
|
http.Redirect(w, r, "/register/pending", http.StatusSeeOther)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token, _ := jwtauth.VerifyRequest(
|
||||||
|
TokenAuth,
|
||||||
|
r,
|
||||||
|
jwtauth.TokenFromCookie,
|
||||||
|
jwtauth.TokenFromHeader,
|
||||||
|
jwtauth.TokenFromQuery)
|
||||||
|
|
||||||
|
userId := token.PrivateClaims()["user_id"].(float64)
|
||||||
|
user, _ := Container.GetUserUseCase.GetUser(uint32(userId))
|
||||||
|
errorMessage := ""
|
||||||
|
|
||||||
|
err := bcrypt.CompareHashAndPassword([]byte(user.VerificationCode), []byte(queryVerificationCode))
|
||||||
|
if err != nil || user.VerificationExpiration.Before(time.Now()) {
|
||||||
|
errorMessage = "Verification link is incorrect or has expired."
|
||||||
|
} else {
|
||||||
|
_, err := Container.UpdateUserUseCase.UpdateVerificationStatus(user.ID, true)
|
||||||
|
if err != nil {
|
||||||
|
errorMessage = "Something went wrong server-side. User account may not exist."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerValidateTmpl, _ := Container.GetPageUseCase.GetPage("registerValidate", map[string]interface{}{
|
||||||
|
"Head": headTmpl,
|
||||||
|
"PageError": NewPageError(errorMessage),
|
||||||
|
})
|
||||||
|
_, _ = w.Write(registerValidateTmpl)
|
||||||
|
}
|
||||||
+2
-2
@@ -6,7 +6,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ${DOCKER_DB_FOLDER}:/app/db/
|
- ${DOCKER_DB_FOLDER}:/app/db/
|
||||||
environment:
|
environment:
|
||||||
- ENVIRONMENT=${ENVIRONMENT}
|
|
||||||
- PORT=8080
|
- PORT=8080
|
||||||
- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS}
|
|
||||||
- DB_FILE=/app/db/gohcms.db
|
- DB_FILE=/app/db/gohcms.db
|
||||||
|
env_file:
|
||||||
|
- ./.env
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package gateways
|
||||||
|
|
||||||
|
type IMailRepository interface {
|
||||||
|
Send(receiverAddress string, templateName string, data interface{}) error
|
||||||
|
}
|
||||||
@@ -7,4 +7,5 @@ type IUserRepository interface {
|
|||||||
GetByUsername(username string) (user.User, error)
|
GetByUsername(username string) (user.User, error)
|
||||||
GetAll() []user.User
|
GetAll() []user.User
|
||||||
Create(user user.User) (user.User, error)
|
Create(user user.User) (user.User, error)
|
||||||
|
UpdateVerificationStatus(userId uint32, isVerified bool) (user.User, error)
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-1
@@ -1,12 +1,17 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ID uint32 `json:"id"`
|
ID uint32 `json:"id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
|
IsVerified bool `gorm:"default=false;not null"`
|
||||||
|
VerificationCode string `gorm:"unique;not null"`
|
||||||
|
VerificationExpiration time.Time `gorm:"not null"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
}
|
}
|
||||||
@@ -15,11 +20,16 @@ func FromApi(
|
|||||||
username string,
|
username string,
|
||||||
password string,
|
password string,
|
||||||
email string,
|
email string,
|
||||||
|
verificationCode string,
|
||||||
) User {
|
) User {
|
||||||
|
expiration := time.Now().Add(2 * time.Hour)
|
||||||
return User{
|
return User{
|
||||||
Username: username,
|
Username: username,
|
||||||
Password: password,
|
Password: password,
|
||||||
Email: email,
|
Email: email,
|
||||||
|
IsVerified: false,
|
||||||
|
VerificationCode: verificationCode,
|
||||||
|
VerificationExpiration: expiration,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +38,9 @@ func FromDb(
|
|||||||
username string,
|
username string,
|
||||||
password string,
|
password string,
|
||||||
email string,
|
email string,
|
||||||
|
isVerified bool,
|
||||||
|
verificationCode string,
|
||||||
|
verificationExpiration time.Time,
|
||||||
createdAt time.Time,
|
createdAt time.Time,
|
||||||
updatedAt time.Time,
|
updatedAt time.Time,
|
||||||
) User {
|
) User {
|
||||||
@@ -36,6 +49,9 @@ func FromDb(
|
|||||||
Username: username,
|
Username: username,
|
||||||
Password: password,
|
Password: password,
|
||||||
Email: email,
|
Email: email,
|
||||||
|
IsVerified: isVerified,
|
||||||
|
VerificationCode: verificationCode,
|
||||||
|
VerificationExpiration: verificationExpiration,
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
UpdatedAt: updatedAt,
|
UpdatedAt: updatedAt,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,16 @@ require (
|
|||||||
github.com/go-chi/jwtauth/v5 v5.3.1
|
github.com/go-chi/jwtauth/v5 v5.3.1
|
||||||
github.com/go-playground/validator/v10 v10.20.0
|
github.com/go-playground/validator/v10 v10.20.0
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
|
github.com/stretchr/testify v1.8.4
|
||||||
go.uber.org/dig v1.17.1
|
go.uber.org/dig v1.17.1
|
||||||
golang.org/x/crypto v0.23.0
|
golang.org/x/crypto v0.23.0
|
||||||
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||||
gorm.io/gorm v1.25.10
|
gorm.io/gorm v1.25.10
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 // indirect
|
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 // indirect
|
||||||
|
github.com/beevik/guid v1.0.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
@@ -25,9 +28,10 @@ require (
|
|||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
|
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
|
||||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||||
@@ -38,10 +42,9 @@ require (
|
|||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/segmentio/asm v1.2.0 // indirect
|
github.com/segmentio/asm v1.2.0 // indirect
|
||||||
github.com/stretchr/objx v0.5.0 // indirect
|
|
||||||
github.com/stretchr/testify v1.8.4 // indirect
|
|
||||||
golang.org/x/net v0.21.0 // indirect
|
golang.org/x/net v0.21.0 // indirect
|
||||||
golang.org/x/text v0.15.0 // indirect
|
golang.org/x/text v0.15.0 // indirect
|
||||||
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
modernc.org/libc v1.24.1 // indirect
|
modernc.org/libc v1.24.1 // indirect
|
||||||
modernc.org/mathutil v1.5.0 // indirect
|
modernc.org/mathutil v1.5.0 // indirect
|
||||||
|
|||||||
@@ -2,69 +2,56 @@ github.com/MadAppGang/httplog v1.3.0 h1:1XU54TO8kiqTeO+7oZLKAM3RP/cJ7SadzslRcKsp
|
|||||||
github.com/MadAppGang/httplog v1.3.0/go.mod h1:gpYEdkjh/Cda6YxtDy4AB7KY+fR7mb3SqBZw74A5hJ4=
|
github.com/MadAppGang/httplog v1.3.0/go.mod h1:gpYEdkjh/Cda6YxtDy4AB7KY+fR7mb3SqBZw74A5hJ4=
|
||||||
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4=
|
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4=
|
||||||
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w=
|
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w=
|
||||||
|
github.com/beevik/guid v1.0.0 h1:XhTlrl9h5+TlkB7MB3SBwAm2+ZdFE62O0D+g7LDFqqI=
|
||||||
|
github.com/beevik/guid v1.0.0/go.mod h1:FyB4y08P/8c0J0xhRHR6xVjdXIpGDwpMXzmGV6vWDj4=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
|
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
|
||||||
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
||||||
github.com/glebarez/sqlite v1.9.0 h1:Aj6bPA12ZEx5GbSF6XADmCkYXlljPNUY+Zf1EQxynXs=
|
|
||||||
github.com/glebarez/sqlite v1.9.0/go.mod h1:YBYCoyupOao60lzp1MVBLEjZfgkq0tdB1voAQ09K9zw=
|
|
||||||
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
||||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||||
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
|
|
||||||
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
|
||||||
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||||
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||||
github.com/go-chi/jwtauth/v5 v5.1.1 h1:Pjixqu5YkjE9sCLpzE01L0Q4sQzJIPdo7uz9r8ftp/c=
|
|
||||||
github.com/go-chi/jwtauth/v5 v5.1.1/go.mod h1:CYP1WSbzD4MPuKCr537EM3kfFhSQgpUEtMJFuYJjqWU=
|
|
||||||
github.com/go-chi/jwtauth/v5 v5.3.1 h1:1ePWrjVctvp1tyBq5b/2ER8Th/+RbYc7x4qNsc5rh5A=
|
github.com/go-chi/jwtauth/v5 v5.3.1 h1:1ePWrjVctvp1tyBq5b/2ER8Th/+RbYc7x4qNsc5rh5A=
|
||||||
github.com/go-chi/jwtauth/v5 v5.3.1/go.mod h1:6Fl2RRmWXs3tJYE1IQGX81FsPoGqDwq9c15j52R5q80=
|
github.com/go-chi/jwtauth/v5 v5.3.1/go.mod h1:6Fl2RRmWXs3tJYE1IQGX81FsPoGqDwq9c15j52R5q80=
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
|
||||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.15.0 h1:nDU5XeOKtB3GEa+uB7GNYwhVKsgjAR7VgKoNB6ryXfw=
|
|
||||||
github.com/go-playground/validator/v10 v10.15.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
|
||||||
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8=
|
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8=
|
||||||
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI=
|
|
||||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
|
||||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
|
||||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80=
|
|
||||||
github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
|
|
||||||
github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
|
github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
|
||||||
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
|
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
|
||||||
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
|
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
|
||||||
@@ -73,11 +60,8 @@ github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJG
|
|||||||
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
|
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
|
||||||
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
|
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
|
||||||
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
|
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
|
||||||
github.com/lestrrat-go/jwx/v2 v2.0.11 h1:ViHMnaMeaO0qV16RZWBHM7GTrAnX2aFLVKofc7FuKLQ=
|
|
||||||
github.com/lestrrat-go/jwx/v2 v2.0.11/go.mod h1:ZtPtMFlrfDrH2Y0iwfa3dRFn8VzwBrB+cyrm3IBWdDg=
|
|
||||||
github.com/lestrrat-go/jwx/v2 v2.0.20 h1:sAgXuWS/t8ykxS9Bi2Qtn5Qhpakw1wrcjxChudjolCc=
|
github.com/lestrrat-go/jwx/v2 v2.0.20 h1:sAgXuWS/t8ykxS9Bi2Qtn5Qhpakw1wrcjxChudjolCc=
|
||||||
github.com/lestrrat-go/jwx/v2 v2.0.20/go.mod h1:UlCSmKqw+agm5BsOBfEAbTvKsEApaGNqHAEUTv5PJC4=
|
github.com/lestrrat-go/jwx/v2 v2.0.20/go.mod h1:UlCSmKqw+agm5BsOBfEAbTvKsEApaGNqHAEUTv5PJC4=
|
||||||
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
|
||||||
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
||||||
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
@@ -88,7 +72,6 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
|
|||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
@@ -97,110 +80,41 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq
|
|||||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
|
||||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
|
||||||
go.uber.org/dig v1.17.0 h1:5Chju+tUvcC+N7N6EV08BJz41UZuO3BmHcN4A287ZLI=
|
|
||||||
go.uber.org/dig v1.17.0/go.mod h1:rTxpf7l5I0eBTlE6/9RL+lDybC7WFwY2QH55ZSjy1mU=
|
|
||||||
go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc=
|
go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc=
|
||||||
go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
|
go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
|
||||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
|
||||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
|
||||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|
||||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
|
||||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
|
||||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
|
||||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
|
||||||
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|
||||||
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
|
||||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|
||||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||||
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho=
|
|
||||||
gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
|
||||||
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
|
|
||||||
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
|
||||||
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
|
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
|
||||||
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
|
||||||
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
|
|
||||||
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
|
|
||||||
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
|
||||||
modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM=
|
modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM=
|
||||||
modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak=
|
modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak=
|
||||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||||
modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o=
|
modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o=
|
||||||
modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
|
||||||
modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA=
|
modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA=
|
||||||
modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU=
|
modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU=
|
||||||
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
|
||||||
modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c=
|
|
||||||
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
|
||||||
modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE=
|
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ func HtmlContentTypeMiddleware(next http.Handler) http.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func InitJwt() {
|
func InitJwt() {
|
||||||
api.TokenAuth = jwtauth.New("HS256", []byte("secret"), nil)
|
api.TokenAuth = jwtauth.New("HS256", []byte(os.Getenv("JWT_SECRET")), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetHelloWorld(w http.ResponseWriter, _ *http.Request) {
|
func GetHelloWorld(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
|||||||
+12
-1
@@ -11,7 +11,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var possibleEnvFileLocations = []string{".env", "../.env"}
|
var possibleEnvFileLocations = []string{".env", "../.env"}
|
||||||
var envVarsToLoad = []string{"PORT", "ENVIRONMENT", "CORS_ALLOWED_ORIGINS", "DB_FILE"}
|
var envVarsToLoad = []string{
|
||||||
|
"HOST",
|
||||||
|
"PORT",
|
||||||
|
"JWT_SECRET",
|
||||||
|
"ENVIRONMENT",
|
||||||
|
"CORS_ALLOWED_ORIGINS",
|
||||||
|
"DB_FILE",
|
||||||
|
"SMTP_EMAIL",
|
||||||
|
"SMTP_PASSWORD",
|
||||||
|
"SMTP_HOST",
|
||||||
|
"SMTP_PORT",
|
||||||
|
}
|
||||||
|
|
||||||
func initEnvVariables() {
|
func initEnvVariables() {
|
||||||
var err error
|
var err error
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ type CreateUserCommand struct {
|
|||||||
Username string
|
Username string
|
||||||
Password string
|
Password string
|
||||||
Email string
|
Email string
|
||||||
|
VerificationCode string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCreateUserUseCase(db *gorm.DB) *CreateUserUseCase {
|
func NewCreateUserUseCase(db *gorm.DB) *CreateUserUseCase {
|
||||||
@@ -27,5 +28,6 @@ func (g *CreateUserUseCase) CreateUser(createUser CreateUserCommand) (user.User,
|
|||||||
createUser.Username,
|
createUser.Username,
|
||||||
createUser.Password,
|
createUser.Password,
|
||||||
createUser.Email,
|
createUser.Email,
|
||||||
|
createUser.VerificationCode,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package useCases
|
||||||
|
|
||||||
|
import (
|
||||||
|
"GohCMS2/adapters/secondary/gateways"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SendMailUseCase struct {
|
||||||
|
mailRepository gateways.MailRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSendMailUseCase() *SendMailUseCase {
|
||||||
|
return &SendMailUseCase{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *SendMailUseCase) SendMail(receiverAddress string, templateName string, data interface{}) error {
|
||||||
|
return g.mailRepository.Send(receiverAddress, templateName, data)
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package useCases
|
||||||
|
|
||||||
|
import (
|
||||||
|
"GohCMS2/adapters/secondary/gateways"
|
||||||
|
"GohCMS2/domain/user"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateUserUseCase struct {
|
||||||
|
userRepository gateways.UserRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateVerificationStatusCommand struct {
|
||||||
|
isVerified bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUpdateUserUseCase(db *gorm.DB) *UpdateUserUseCase {
|
||||||
|
return &UpdateUserUseCase{
|
||||||
|
userRepository: *gateways.NewUserRepository(db),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *UpdateUserUseCase) UpdateVerificationStatus(userId uint32, isVerified bool) (user.User, error) {
|
||||||
|
return g.userRepository.UpdateVerificationStatus(userId, isVerified)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user