You've already forked reloading-manager
happy monday _ bleh _ #9
@@ -2,18 +2,12 @@ package handlers
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func ReadFile(c echo.Context, formName string) ([]byte, error) {
|
||||
file, err := c.FormFile(formName)
|
||||
if err != nil {
|
||||
c.Logger().Error(err)
|
||||
_ = c.JSON(http.StatusBadRequest, struct {
|
||||
Message string `json:"message"`
|
||||
}{
|
||||
Message: "No file provided",
|
||||
})
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package loads
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.siteworxpro.com/reloading-manager/backend/.gen/loading/public/table"
|
||||
"git.siteworxpro.com/reloading-manager/backend/database"
|
||||
"git.siteworxpro.com/reloading-manager/backend/handlers"
|
||||
@@ -13,6 +12,7 @@ import (
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/labstack/echo/v4"
|
||||
"mime"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
@@ -65,11 +65,29 @@ type ResultChan[T any] struct {
|
||||
}
|
||||
|
||||
func Post(c echo.Context) error {
|
||||
var exists *loads.GetLoadByIdRow
|
||||
|
||||
db := c.(*database.CustomContext).Db
|
||||
defer func() {
|
||||
_ = db.Db.Close(context.Background())
|
||||
}()
|
||||
|
||||
id := c.Param("id")
|
||||
|
||||
if id != "" {
|
||||
uuid, err := handlers.ParseUuid(id)
|
||||
if err != nil {
|
||||
return handlers.BadRequest(c, "id is not a valid UUID")
|
||||
}
|
||||
|
||||
gbi, err := db.Loads.GetLoadById(context.Background(), *uuid)
|
||||
if err != nil || !gbi.ID.Valid {
|
||||
return handlers.NotFound(c, "load not found")
|
||||
}
|
||||
|
||||
exists = &gbi
|
||||
}
|
||||
|
||||
cartridgeID, err := handlers.ParseUuid(c.FormValue("cartridge_id"))
|
||||
if err != nil {
|
||||
return handlers.BadRequest(c, "cartridge_id is not a valid UUID")
|
||||
@@ -91,8 +109,11 @@ func Post(c echo.Context) error {
|
||||
}
|
||||
|
||||
file, err := handlers.ReadFile(c, "photo")
|
||||
if err != nil {
|
||||
if err != nil && exists == nil {
|
||||
return handlers.BadRequest(c, "photo is not valid")
|
||||
} else if err != nil {
|
||||
// If we are updating an existing load, we can ignore the error
|
||||
file = exists.Photo
|
||||
}
|
||||
|
||||
meta := c.FormValue("meta")
|
||||
@@ -119,6 +140,26 @@ func Post(c echo.Context) error {
|
||||
return handlers.BadRequest(c, "col is not valid")
|
||||
}
|
||||
|
||||
if exists != nil {
|
||||
err = db.Loads.UpdateLoad(context.Background(), loads.UpdateLoadParams{
|
||||
ID: exists.ID,
|
||||
CartridgeID: *cartridgeID,
|
||||
Col: colFl,
|
||||
PowderID: *powderId,
|
||||
PowderGr: powderGrFl,
|
||||
PrimerID: *primerId,
|
||||
BulletID: *bulletId,
|
||||
Photo: file,
|
||||
Meta: []byte(meta),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, handlers.Response[string]{Payload: exists.ID.String()})
|
||||
}
|
||||
|
||||
uid, err := db.Loads.CreateLoad(context.Background(), loads.CreateLoadParams{
|
||||
CartridgeID: *cartridgeID,
|
||||
Col: colFl,
|
||||
@@ -137,6 +178,32 @@ func Post(c echo.Context) error {
|
||||
return c.JSON(http.StatusCreated, handlers.Response[string]{Payload: uid.String()})
|
||||
}
|
||||
|
||||
func Photo(c echo.Context) error {
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
return handlers.BadRequest(c, "id is required")
|
||||
}
|
||||
|
||||
uuid, err := handlers.ParseUuid(id)
|
||||
if err != nil {
|
||||
return handlers.BadRequest(c, "id is not a valid UUID")
|
||||
}
|
||||
|
||||
db := c.(*database.CustomContext).Db
|
||||
defer func() {
|
||||
_ = db.Db.Close(context.Background())
|
||||
}()
|
||||
|
||||
file, err := db.Loads.GetLoadById(context.Background(), *uuid)
|
||||
if err != nil {
|
||||
return handlers.NotFound(c, "load photo not found")
|
||||
}
|
||||
|
||||
mt, _, _ := mime.ParseMediaType(string(file.Photo))
|
||||
|
||||
return c.Blob(http.StatusOK, mt, file.Photo)
|
||||
}
|
||||
|
||||
func Get(c echo.Context) error {
|
||||
id := c.Param("id")
|
||||
cResults := make(chan ResultChan[[]loadResponseResults])
|
||||
@@ -213,8 +280,6 @@ func execResultsQuery(ch chan ResultChan[[]loadResponseResults], c echo.Context)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(q.DebugSql())
|
||||
|
||||
sql, params := q.Sql()
|
||||
rows, err := db.Db.Query(context.Background(), sql, params...)
|
||||
|
||||
@@ -496,6 +561,35 @@ func getQuery(c echo.Context, countOnly bool) postgres.SelectStatement {
|
||||
return q
|
||||
}
|
||||
|
||||
func Delete(c echo.Context) error {
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
return handlers.BadRequest(c, "id is required")
|
||||
}
|
||||
|
||||
uuid, err := handlers.ParseUuid(id)
|
||||
if err != nil {
|
||||
return handlers.BadRequest(c, "id is not a valid UUID")
|
||||
}
|
||||
|
||||
db := c.(*database.CustomContext).Db
|
||||
defer func() {
|
||||
_ = db.Db.Close(context.Background())
|
||||
}()
|
||||
|
||||
exists, err := db.Loads.GetLoadById(context.Background(), *uuid)
|
||||
if err != nil || !exists.ID.Valid {
|
||||
return handlers.NotFound(c, "load not found")
|
||||
}
|
||||
|
||||
err = db.Loads.DeleteLoad(context.Background(), *uuid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.NoContent(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func getUuidExpr(ids []string) []postgres.Expression {
|
||||
expr := make([]postgres.Expression, 0)
|
||||
for _, id := range ids {
|
||||
|
||||
@@ -99,7 +99,10 @@ func main() {
|
||||
// loads
|
||||
e.GET("/load", loads.Get)
|
||||
e.GET("/load/:id", loads.Get)
|
||||
e.GET("/load/:id/photo", loads.Photo)
|
||||
e.POST("/load", loads.Post)
|
||||
e.POST("/load/:id", loads.Post)
|
||||
e.DELETE("/load/:id", loads.Delete)
|
||||
|
||||
addr := fmt.Sprintf("0.0.0.0:%s", Port.GetEnvString("8080"))
|
||||
|
||||
|
||||
@@ -18,6 +18,22 @@ delete
|
||||
from cartridges
|
||||
where id = $1;
|
||||
|
||||
-- name: DeleteLoad :exec
|
||||
delete from loads
|
||||
where id = $1;
|
||||
|
||||
-- name: UpdateLoad :exec
|
||||
update loads set
|
||||
cartridge_id = $1,
|
||||
col = $2,
|
||||
powder_id = $3,
|
||||
powder_gr = $4,
|
||||
primer_id = $5,
|
||||
bullet_id = $6,
|
||||
photo = $7,
|
||||
meta = $8
|
||||
where id = $9;
|
||||
|
||||
-- name: CreateLoad :one
|
||||
insert into loads (cartridge_id, col, powder_id, powder_gr, primer_id, bullet_id, photo, meta)
|
||||
values ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
@@ -25,6 +41,7 @@ returning id;
|
||||
|
||||
-- name: GetLoadById :one
|
||||
select l.id as id,
|
||||
l.photo as photo,
|
||||
c.id as cartridge_id,
|
||||
c.name as cartridge_name,
|
||||
c.meta as cartridge_meta,
|
||||
|
||||
@@ -73,6 +73,16 @@ func (q *Queries) DeleteCartridge(ctx context.Context, id pgtype.UUID) error {
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteLoad = `-- name: DeleteLoad :exec
|
||||
delete from loads
|
||||
where id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteLoad(ctx context.Context, id pgtype.UUID) error {
|
||||
_, err := q.db.Exec(ctx, deleteLoad, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const getCartridgeById = `-- name: GetCartridgeById :one
|
||||
select c.id as id, c.name, c.meta
|
||||
from cartridges c
|
||||
@@ -126,6 +136,7 @@ func (q *Queries) GetCartridges(ctx context.Context) ([]GetCartridgesRow, error)
|
||||
|
||||
const getLoadById = `-- name: GetLoadById :one
|
||||
select l.id as id,
|
||||
l.photo as photo,
|
||||
c.id as cartridge_id,
|
||||
c.name as cartridge_name,
|
||||
c.meta as cartridge_meta,
|
||||
@@ -147,6 +158,7 @@ where l.id = $1
|
||||
|
||||
type GetLoadByIdRow struct {
|
||||
ID pgtype.UUID `json:"id"`
|
||||
Photo []byte `json:"photo"`
|
||||
CartridgeID pgtype.UUID `json:"cartridge_id"`
|
||||
CartridgeName string `json:"cartridge_name"`
|
||||
CartridgeMeta []byte `json:"cartridge_meta"`
|
||||
@@ -165,6 +177,7 @@ func (q *Queries) GetLoadById(ctx context.Context, id pgtype.UUID) (GetLoadByIdR
|
||||
var i GetLoadByIdRow
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Photo,
|
||||
&i.CartridgeID,
|
||||
&i.CartridgeName,
|
||||
&i.CartridgeMeta,
|
||||
@@ -376,3 +389,43 @@ func (q *Queries) TotalLoads(ctx context.Context) (int64, error) {
|
||||
err := row.Scan(&count)
|
||||
return count, err
|
||||
}
|
||||
|
||||
const updateLoad = `-- name: UpdateLoad :exec
|
||||
update loads set
|
||||
cartridge_id = $1,
|
||||
col = $2,
|
||||
powder_id = $3,
|
||||
powder_gr = $4,
|
||||
primer_id = $5,
|
||||
bullet_id = $6,
|
||||
photo = $7,
|
||||
meta = $8
|
||||
where id = $9
|
||||
`
|
||||
|
||||
type UpdateLoadParams struct {
|
||||
CartridgeID pgtype.UUID `json:"cartridge_id"`
|
||||
Col float32 `json:"col"`
|
||||
PowderID pgtype.UUID `json:"powder_id"`
|
||||
PowderGr float32 `json:"powder_gr"`
|
||||
PrimerID pgtype.UUID `json:"primer_id"`
|
||||
BulletID pgtype.UUID `json:"bullet_id"`
|
||||
Photo []byte `json:"photo"`
|
||||
Meta []byte `json:"meta"`
|
||||
ID pgtype.UUID `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateLoad(ctx context.Context, arg UpdateLoadParams) error {
|
||||
_, err := q.db.Exec(ctx, updateLoad,
|
||||
arg.CartridgeID,
|
||||
arg.Col,
|
||||
arg.PowderID,
|
||||
arg.PowderGr,
|
||||
arg.PrimerID,
|
||||
arg.BulletID,
|
||||
arg.Photo,
|
||||
arg.Meta,
|
||||
arg.ID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
COL
|
||||
</div>
|
||||
<div class="w-full mt-3">
|
||||
<InputMask placeholder="0.000" v-model="load.col" mask="9.999" class="w-full" />
|
||||
<InputMask :unmask="loading" :value="load.col" placeholder="0.000" v-model="load.col" mask="9.999" class="w-full" />
|
||||
<Message v-if="v$.$dirty && v$.col.$invalid" :value="false" size="small" severity="error"
|
||||
variant="simple">COL Required
|
||||
</Message>
|
||||
@@ -75,15 +75,20 @@
|
||||
|
||||
<div class="w-full mt-5">
|
||||
<label>Picture</label>
|
||||
<Message v-if="v$.$dirty && !file" :value="false" size="small" severity="error"
|
||||
<Message v-if="v$.$dirty && (!route.params.id && !file)" :value="false" size="small" severity="error"
|
||||
variant="simple">Picture Required
|
||||
</Message>
|
||||
<div class="w-1/2">
|
||||
<img v-if="pictureUrl && route.params.id && !loading" :src="pictureUrl" alt="picture" />
|
||||
</div>
|
||||
<FileUpload v-model="file" mode="basic" @select="fileSelected" customUpload />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<Button label="Add" :icon="icons.add" @click="add" />
|
||||
<Button v-if="!route.params.id" label="Add" :icon="icons.add" @click="add" />
|
||||
<Button v-else label="Save" :icon="icons.edit" @click="add" />
|
||||
<Button class="ml-3" severity="danger" v-if="route.params.id" label="Delete" :icon="icons.delete" @click="deleteLoad" />
|
||||
</template>
|
||||
</Card>
|
||||
|
||||
@@ -161,6 +166,12 @@ const fileSelected = (e: FileUploadSelectEvent) => {
|
||||
file.value = e.files[0]
|
||||
}
|
||||
|
||||
const pictureUrl = ref<string | null>(null)
|
||||
const calcUrl = () => {
|
||||
const cache = new Date().getMilliseconds()
|
||||
pictureUrl.value = import.meta.env.VITE_API + `/load/${route.params.id}/photo?cache=${cache}`
|
||||
}
|
||||
|
||||
const load = ref({
|
||||
bullet: '',
|
||||
cartridge: '',
|
||||
@@ -243,7 +254,7 @@ const addCartridgeName = async () => {
|
||||
const add = async () => {
|
||||
v$.value.$touch()
|
||||
|
||||
if (v$.value.$invalid || !file.value) {
|
||||
if (v$.value.$invalid || (!route.params.id && !file.value)) {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
@@ -254,6 +265,12 @@ const add = async () => {
|
||||
return
|
||||
}
|
||||
|
||||
let id = ""
|
||||
|
||||
if (route.params.id) {
|
||||
id = "/" + route.params.id.toString()
|
||||
}
|
||||
|
||||
const formData = new FormData()
|
||||
formData.append('bullet_id', load.value.bullet)
|
||||
formData.append('cartridge_id', load.value.cartridge)
|
||||
@@ -261,22 +278,43 @@ const add = async () => {
|
||||
formData.append('powder_gr', load.value.powderGrs.toString())
|
||||
formData.append('primer_id', load.value.primer)
|
||||
formData.append('col', load.value.col)
|
||||
if (file.value) {
|
||||
formData.append('photo', file.value)
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post<any, Response<string>>(`${import.meta.env.VITE_API}/load`, formData, {
|
||||
const response = await axios.post<any, Response<string>>(`${import.meta.env.VITE_API}/load${id}`, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
})
|
||||
|
||||
const message = route.params.id ? 'Load updated' : 'Load added'
|
||||
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
summary: 'Success',
|
||||
detail: 'Load added',
|
||||
detail: message,
|
||||
life: 3000,
|
||||
})
|
||||
|
||||
if (route.params.id) {
|
||||
load.value = {
|
||||
bullet: '',
|
||||
cartridge: '',
|
||||
powder: '',
|
||||
powderGrs: 0,
|
||||
primer: '',
|
||||
col: '',
|
||||
}
|
||||
file.value = null
|
||||
|
||||
v$.value.$reset()
|
||||
await fetchLoad()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await router.push(`/loads/edit/${response.data.payload}`)
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
@@ -287,6 +325,31 @@ const add = async () => {
|
||||
})
|
||||
}
|
||||
}
|
||||
const deleteLoad = async () => {
|
||||
if (!route.params.id) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await axios.delete(`${import.meta.env.VITE_API}/load/${route.params.id}`)
|
||||
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
summary: 'Success',
|
||||
detail: 'Load deleted',
|
||||
life: 3000,
|
||||
})
|
||||
|
||||
await router.push('/loads/search')
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'Error deleting load',
|
||||
life: 3000,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const fetchLoad = async () => {
|
||||
if (!route.params.id) {
|
||||
@@ -302,6 +365,18 @@ const fetchLoad = async () => {
|
||||
load.value.powder = response.data.payload.powder.id
|
||||
load.value.powderGrs = response.data.payload.powder_gr
|
||||
load.value.primer = response.data.payload.primer.id
|
||||
load.value.col = response.data.payload.col.toString()
|
||||
|
||||
if (!load.value.col.includes('.')) {
|
||||
load.value.col = `${load.value.col}.000`
|
||||
} else {
|
||||
const parts = load.value.col.split('.')
|
||||
if (parts[1].length < 3) {
|
||||
load.value.col = `${parts[0]}.${parts[1].padEnd(3, '0')}`
|
||||
}
|
||||
}
|
||||
|
||||
calcUrl()
|
||||
} else {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
@@ -324,7 +399,9 @@ onMounted(() => {
|
||||
fetchCartridges()
|
||||
|
||||
if (route.params.id) {
|
||||
setTimeout(() => {
|
||||
fetchLoad()
|
||||
}, 100)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user