Skip to content

Commit

Permalink
create employee
Browse files Browse the repository at this point in the history
  • Loading branch information
henriquepw committed Sep 6, 2024
1 parent 528327f commit 8db397d
Show file tree
Hide file tree
Showing 24 changed files with 311 additions and 189 deletions.
4 changes: 3 additions & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/henriquepw/imperium-tattoo/database"
"github.com/henriquepw/imperium-tattoo/web/handler"
"github.com/henriquepw/imperium-tattoo/web/service"

_ "github.com/joho/godotenv/autoload"
_ "github.com/tursodatabase/libsql-client-go/libsql"
Expand All @@ -31,7 +32,8 @@ func main() {
clientHandler := handler.NewClientHandler()
server.HandleFunc("GET /clients", clientHandler.ClientsPage)

employeeHandler := handler.NewEmployeeHandler(database.NewEmployeeRepo(db))
employeeSvc := service.NewEmployeeService(database.NewEmployeeRepo(db))
employeeHandler := handler.NewEmployeeHandler(employeeSvc)
server.HandleFunc("GET /employees", employeeHandler.EmployeesPage)
server.HandleFunc("GET /employees/create", employeeHandler.EmployeeCreatePage)
server.HandleFunc("POST /employees/create", employeeHandler.EmployeeCreateAction)
Expand Down
20 changes: 13 additions & 7 deletions database/employee_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,21 @@ import (
"github.com/henriquepw/imperium-tattoo/web/types"
)

type EmployeeRepository interface {
type EmployeeRepo interface {
Insert(ctx context.Context, payload types.EmployeeCreateDTO) (*string, error)
List(ctx context.Context) ([]types.Employee, error)
CheckEmail(ctx context.Context, email string) bool
}

type EmployeeRepo struct {
type repo struct {
db *sql.DB
}

func NewEmployeeRepo(db *sql.DB) *EmployeeRepo {
return &EmployeeRepo{db}
func NewEmployeeRepo(db *sql.DB) *repo {
return &repo{db}
}

func (r EmployeeRepo) Insert(ctx context.Context, payload types.EmployeeCreateDTO) (*string, error) {
func (r repo) Insert(ctx context.Context, payload types.EmployeeCreateDTO) (*string, error) {
id, err := web.NewID()
if err != nil {
return nil, err
Expand Down Expand Up @@ -49,7 +50,7 @@ func (r EmployeeRepo) Insert(ctx context.Context, payload types.EmployeeCreateDT
ctx,
"INSERT INTO credential (id, secret) VALUES ($1, $2)",
payload.Email,
payload.PasswordHash,
payload.Password,
)
if err != nil {
return nil, err
Expand All @@ -62,7 +63,7 @@ func (r EmployeeRepo) Insert(ctx context.Context, payload types.EmployeeCreateDT
return &id, nil
}

func (r EmployeeRepo) List(ctx context.Context) ([]types.Employee, error) {
func (r repo) List(ctx context.Context) ([]types.Employee, error) {
rows, err := r.db.QueryContext(ctx, "SELECT id, name, email, roles FROM employee")
if err != nil {
return nil, err
Expand All @@ -81,3 +82,8 @@ func (r EmployeeRepo) List(ctx context.Context) ([]types.Employee, error) {

return items, nil
}

func (r repo) CheckEmail(ctx context.Context, email string) bool {
row := r.db.QueryRowContext(ctx, "SELECT COUNT(1) FROM employee WHERE email = ?", email)
return row.Err() == nil
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
module github.com/henriquepw/imperium-tattoo

go 1.22.4
go 1.23.1

require (
github.com/a-h/templ v0.2.747
github.com/go-playground/validator/v10 v10.22.0
github.com/joho/godotenv v1.5.1
github.com/matoous/go-nanoid/v2 v2.1.0
github.com/tursodatabase/libsql-client-go v0.0.0-20240812094001-348a4e45b535
golang.org/x/crypto v0.22.0
)

require (
Expand All @@ -17,7 +18,6 @@ require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.21.0 // indirect
Expand Down
16 changes: 16 additions & 0 deletions static/css/input.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@
@tailwind components;
@tailwind utilities;

@layer components {
.htmx-request .hx-indicator {
display: block;
}

.htmx-request .default-indicator {
display: none;
}

.btn-primary {
@apply flex items-center justify-center gap-1.5 h-9 px-3 rounded bg-accent-9;
@apply font-bold text-gray-12 text-center;
@apply transition-all hover:bg-accent-10 active:bg-accent-11 active:scale-95;
}
}

@layer base {
@font-face {
font-family: raleway;
Expand Down
50 changes: 50 additions & 0 deletions web/handler/employee.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package handler

import (
"net/http"

"github.com/a-h/templ"
"github.com/henriquepw/imperium-tattoo/web"
"github.com/henriquepw/imperium-tattoo/web/service"
"github.com/henriquepw/imperium-tattoo/web/types"
"github.com/henriquepw/imperium-tattoo/web/view/employee"
)

type EmployeeHandler struct {
svc service.EmployeeService
}

func NewEmployeeHandler(svc service.EmployeeService) *EmployeeHandler {
return &EmployeeHandler{svc}
}

func (h EmployeeHandler) EmployeesPage(w http.ResponseWriter, r *http.Request) {
web.RenderPage(w, r, employee.EmployeesPage)
}

func (h EmployeeHandler) EmployeeCreatePage(w http.ResponseWriter, r *http.Request) {
web.RenderPage(w, r, employee.EmployeeCreatePage)
}

func (h EmployeeHandler) EmployeeCreateAction(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
payload := types.EmployeeCreateDTO{
Name: r.Form.Get("name"),
Email: r.Form.Get("email"),
Roles: r.Form.Get("roles"),
Password: r.Form.Get("email"),
}

_, err := h.svc.CreateEmployee(r.Context(), payload)
if err != nil {
web.RenderError(w, r, err, func(e web.ServerError) templ.Component {
return employee.EmployeeCreateForm(employee.EmployeeCreateFormProps{
Values: payload,
Errors: e.Errors,
})
})
return
}

http.Redirect(w, r, "/employees", http.StatusSeeOther)
}
62 changes: 0 additions & 62 deletions web/handler/employee_handler.go

This file was deleted.

15 changes: 15 additions & 0 deletions web/hash.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package web

import (
"golang.org/x/crypto/bcrypt"
)

func HashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
return string(bytes), err
}

func VerifyPassword(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
10 changes: 0 additions & 10 deletions web/parsers.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
package web

import (
"net/http"
"net/url"
"strconv"

"github.com/a-h/templ"
)

func Render(w http.ResponseWriter, r *http.Request, statusCode int, t templ.Component) error {
w.WriteHeader(statusCode)
w.Header().Set("Content-Type", "text/html")

return t.Render(r.Context(), w)
}

func GetQueryInt(q url.Values, name string, defaultVal int64) int64 {
val, err := strconv.ParseInt(q.Get(name), 10, 64)
if err != nil {
Expand Down
37 changes: 37 additions & 0 deletions web/renders.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package web

import (
"net/http"

"github.com/a-h/templ"
)

func RenderPage(w http.ResponseWriter, r *http.Request, comp func(boosted bool) templ.Component) error {
t := comp(r.Header.Get("HX-Boosted") == "true")
return Render(w, r, http.StatusOK, t)
}

func Render(w http.ResponseWriter, r *http.Request, statusCode int, t templ.Component) error {
w.WriteHeader(statusCode)
w.Header().Set("Content-Type", "text/html")

return t.Render(r.Context(), w)
}

func RenderError(w http.ResponseWriter, r *http.Request, err error, t func(e ServerError) templ.Component) error {
if e, ok := err.(ServerError); ok {
if e.Errors != nil {
return Render(w, r, e.StatusCode, t(e))
}

w.WriteHeader(e.StatusCode)
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte(e.Message))
return nil
}

w.WriteHeader(http.StatusInternalServerError)
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte("Houve um erro inesperado"))
return nil
}
48 changes: 48 additions & 0 deletions web/service/employee.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package service

import (
"context"

"github.com/henriquepw/imperium-tattoo/database"
"github.com/henriquepw/imperium-tattoo/web"
"github.com/henriquepw/imperium-tattoo/web/types"
)

type EmployeeService interface {
CreateEmployee(ctx context.Context, payload types.EmployeeCreateDTO) (*string, error)
}

type EmployeeSvc struct {
repo database.EmployeeRepo
}

func NewEmployeeService(repo database.EmployeeRepo) *EmployeeSvc {
return &EmployeeSvc{repo}
}

func (s *EmployeeSvc) CreateEmployee(ctx context.Context, payload types.EmployeeCreateDTO) (*string, error) {
if err := web.CheckPayload(payload); err != nil {
return nil, err
}

if s.repo.CheckEmail(ctx, payload.Email) {
return nil, web.InvalidRequestDataError(map[string]string{"email": "Email já cadastrado"})
}

hash, err := web.HashPassword(payload.Password)
if err != nil {
return nil, err
}

id, err := s.repo.Insert(ctx, types.EmployeeCreateDTO{
Name: payload.Name,
Email: payload.Email,
Roles: payload.Roles,
Password: hash,
})
if err != nil {
return nil, err
}

return id, nil
}
1 change: 0 additions & 1 deletion web/service/employee_service.go

This file was deleted.

8 changes: 4 additions & 4 deletions web/types/employee.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ type Employee struct {
}

type EmployeeCreateDTO struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
Roles string `json:"roles" validate:"required"`
PasswordHash string
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
Roles string `json:"roles" validate:"required"`
Password string `json:"password" validate:"required"`
}
17 changes: 13 additions & 4 deletions web/view/client/clients.templ
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
package client

import "github.com/henriquepw/imperium-tattoo/web/view/layout"
import (
"github.com/henriquepw/imperium-tattoo/web/view/layout"
"github.com/henriquepw/imperium-tattoo/web/view/ui"
)

templ ClientsPage() {
@layout.Dashbaord("Painel", "clients", false) {
<div>
MAIN
</div>
@layout.PageHeader(
"Clientes",
[]ui.BreadcrumbItem{
{Label: "Clientes", Href: "/clients"},
},
)
<section>
CLIENTS
</section>
}
}
Loading

0 comments on commit 8db397d

Please sign in to comment.