mirror of
https://github.com/hazemKrimi/crimson-vault.git
synced 2026-05-02 02:30:28 +00:00
277 lines
6.5 KiB
Go
277 lines
6.5 KiB
Go
package lib
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/gorilla/sessions"
|
|
"github.com/johnfercher/maroto/v2"
|
|
"github.com/johnfercher/maroto/v2/pkg/components/col"
|
|
"github.com/johnfercher/maroto/v2/pkg/components/image"
|
|
"github.com/johnfercher/maroto/v2/pkg/components/row"
|
|
"github.com/johnfercher/maroto/v2/pkg/components/text"
|
|
"github.com/johnfercher/maroto/v2/pkg/config"
|
|
"github.com/johnfercher/maroto/v2/pkg/consts/align"
|
|
"github.com/johnfercher/maroto/v2/pkg/consts/fontstyle"
|
|
"github.com/johnfercher/maroto/v2/pkg/core"
|
|
"github.com/johnfercher/maroto/v2/pkg/props"
|
|
"github.com/labstack/echo/v4"
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
"github.com/hazemKrimi/crimson-vault/internal/types"
|
|
)
|
|
|
|
func GetConfigDirectoryPath() (string, error) {
|
|
home, err := os.UserHomeDir()
|
|
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
config, err := filepath.Abs(filepath.Join(home, DEFAULT_CONFIG_DIRECTORY))
|
|
|
|
return config, nil
|
|
}
|
|
|
|
func SaveSession(session *sessions.Session, context echo.Context) error {
|
|
if err := session.Save(context.Request(), context.Response()); err != nil {
|
|
return types.Error{Code: http.StatusInternalServerError, Cause: err, Messages: []string{"Unexpected error saving User session!"}}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func CreateSession(session *sessions.Session, context echo.Context, user *types.User) error {
|
|
if err := uuid.Validate(user.SessionID); err != nil {
|
|
return types.Error{Code: http.StatusInternalServerError, Cause: err, Messages: []string{"Unexpected error saving User session!"}}
|
|
}
|
|
|
|
session.Options = &sessions.Options{
|
|
Path: "/",
|
|
MaxAge: 3600,
|
|
HttpOnly: true,
|
|
}
|
|
session.Values["id"] = user.ID
|
|
session.Values["sessionId"] = user.SessionID
|
|
session.Values["username"] = user.Username
|
|
|
|
if err := SaveSession(session, context); err != nil {
|
|
return types.Error{Code: http.StatusInternalServerError, Cause: err, Messages: []string{"Unexpected error saving User session!"}}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func DeleteSession(session *sessions.Session, context echo.Context) error {
|
|
session.Options.MaxAge = -1
|
|
|
|
if err := SaveSession(session, context); err != nil {
|
|
return types.Error{Code: http.StatusInternalServerError, Cause: err, Messages: []string{"Unexpected error saving User session!"}}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func HashPassword(password string) (string, error) {
|
|
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
return string(bytes), err
|
|
}
|
|
|
|
func CheckPasswordHash(password, hash string) bool {
|
|
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
|
return err == nil
|
|
}
|
|
|
|
func getGrayColor() *props.Color {
|
|
return &props.Color{
|
|
Red: 200,
|
|
Green: 200,
|
|
Blue: 200,
|
|
}
|
|
}
|
|
|
|
func getDarkGrayColor() *props.Color {
|
|
return &props.Color{
|
|
Red: 200,
|
|
Green: 200,
|
|
Blue: 200,
|
|
}
|
|
}
|
|
|
|
func getBlueColor() *props.Color {
|
|
return &props.Color{
|
|
Red: 10,
|
|
Green: 10,
|
|
Blue: 150,
|
|
}
|
|
}
|
|
|
|
func getRedColor() *props.Color {
|
|
return &props.Color{
|
|
Red: 150,
|
|
Green: 10,
|
|
Blue: 10,
|
|
}
|
|
}
|
|
|
|
func getPageHeader(client types.Client, logo string) core.Row {
|
|
return row.New(20).Add(
|
|
image.NewFromFileCol(3, logo, props.Rect{
|
|
Center: true,
|
|
Percent: 80,
|
|
}),
|
|
col.New(6),
|
|
col.New(3).Add(
|
|
text.New(fmt.Sprintf("%s, %s, %s", client.Address, client.Zip, client.Country), props.Text{
|
|
Size: 8,
|
|
Align: align.Right,
|
|
Color: getRedColor(),
|
|
}),
|
|
text.New(client.Phone, props.Text{
|
|
Top: 12,
|
|
Style: fontstyle.BoldItalic,
|
|
Size: 8,
|
|
Align: align.Right,
|
|
Color: getBlueColor(),
|
|
}),
|
|
),
|
|
)
|
|
}
|
|
|
|
func getPageFooter(user types.User) core.Row {
|
|
return row.New(20).Add(
|
|
col.New(12).Add(
|
|
text.New(user.Phone, props.Text{
|
|
Top: 13,
|
|
Style: fontstyle.BoldItalic,
|
|
Size: 8,
|
|
Align: align.Left,
|
|
Color: getBlueColor(),
|
|
}),
|
|
),
|
|
)
|
|
}
|
|
|
|
func getTransactions(items []types.Item) []core.Row {
|
|
rows := []core.Row{
|
|
row.New(5).Add(
|
|
col.New(3),
|
|
text.NewCol(4, "Service", props.Text{Size: 9, Align: align.Center, Style: fontstyle.Bold}),
|
|
text.NewCol(2, "Quantity", props.Text{Size: 9, Align: align.Center, Style: fontstyle.Bold}),
|
|
text.NewCol(3, "Price", props.Text{Size: 9, Align: align.Center, Style: fontstyle.Bold}),
|
|
),
|
|
}
|
|
|
|
var contentsRow []core.Row
|
|
for i, item := range items {
|
|
r := row.New(4).Add(
|
|
col.New(3),
|
|
text.NewCol(4, item.Name, props.Text{Size: 8, Align: align.Center}),
|
|
text.NewCol(2, fmt.Sprintf("%d", item.Quantity), props.Text{Size: 8, Align: align.Center}),
|
|
text.NewCol(3, fmt.Sprintf("%.2f", item.Price), props.Text{Size: 8, Align: align.Center}),
|
|
)
|
|
if i%2 == 0 {
|
|
gray := getGrayColor()
|
|
r.WithStyle(&props.Cell{BackgroundColor: gray})
|
|
}
|
|
|
|
contentsRow = append(contentsRow, r)
|
|
}
|
|
|
|
rows = append(rows, contentsRow...)
|
|
|
|
rows = append(rows, row.New(20).Add(
|
|
col.New(7),
|
|
text.NewCol(2, "Total:", props.Text{
|
|
Top: 5,
|
|
Style: fontstyle.Bold,
|
|
Size: 8,
|
|
Align: align.Right,
|
|
}),
|
|
text.NewCol(3, "$2.567,00", props.Text{
|
|
Top: 5,
|
|
Style: fontstyle.Bold,
|
|
Size: 8,
|
|
Align: align.Center,
|
|
}),
|
|
))
|
|
|
|
return rows
|
|
}
|
|
|
|
func GenerateInvoice(invoice types.Invoice, user types.User, client types.Client) (string, error) {
|
|
cfg := config.NewBuilder().WithPageNumber().WithLeftMargin(10).WithRightMargin(10).WithTopMargin(15).Build()
|
|
darkGray := getDarkGrayColor()
|
|
mrt := maroto.New(cfg)
|
|
m := maroto.NewMetricsDecorator(mrt)
|
|
|
|
err := m.RegisterHeader(getPageHeader(client, user.Logo))
|
|
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
err = m.RegisterFooter(getPageFooter(user))
|
|
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
m.AddRows(text.NewRow(10, fmt.Sprintf("Invoice %s", invoice.ID), props.Text{
|
|
Top: 3,
|
|
Style: fontstyle.Bold,
|
|
Align: align.Center,
|
|
}))
|
|
|
|
m.AddRow(7,
|
|
text.NewCol(3, "Items", props.Text{
|
|
Top: 1.5,
|
|
Size: 9,
|
|
Style: fontstyle.Bold,
|
|
Align: align.Center,
|
|
Color: &props.WhiteColor,
|
|
}),
|
|
).WithStyle(&props.Cell{BackgroundColor: darkGray})
|
|
|
|
m.AddRows(getTransactions(invoice.Items)...)
|
|
|
|
document, err := m.Generate()
|
|
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
configDir, err := GetConfigDirectoryPath()
|
|
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
invoicesDir := filepath.Join(configDir, user.Username, client.ID)
|
|
|
|
if err := os.MkdirAll(invoicesDir, os.ModePerm); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
invoiceFileName := fmt.Sprintf("%s.pdf", invoice.ID)
|
|
invoicePath := filepath.Join(invoicesDir, invoiceFileName)
|
|
|
|
err = document.Save(invoicePath)
|
|
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return invoicePath, nil
|
|
}
|
|
|
|
func GenerateInvoiceReference(invoiceNumber uint32) string {
|
|
year, _, _ := time.Now().Date()
|
|
|
|
return fmt.Sprintf("INV/%d/%05d", year, invoiceNumber)
|
|
}
|