223 lines
6.2 KiB
Go
223 lines
6.2 KiB
Go
package models
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"screenmark/screenmark/.gen/haystack/haystack/enum"
|
|
"screenmark/screenmark/.gen/haystack/haystack/model"
|
|
. "screenmark/screenmark/.gen/haystack/haystack/table"
|
|
|
|
. "github.com/go-jet/jet/v2/postgres"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type ImageModel struct {
|
|
dbPool *sql.DB
|
|
}
|
|
|
|
type ImageData struct {
|
|
model.UserImages
|
|
|
|
Image model.Image
|
|
}
|
|
|
|
type ProcessingImageData struct {
|
|
model.UserImagesToProcess
|
|
|
|
Image model.Image
|
|
}
|
|
|
|
type UserProcessingImage struct {
|
|
model.UserImagesToProcess
|
|
|
|
Image model.Image
|
|
}
|
|
|
|
func (m ImageModel) Process(ctx context.Context, userId uuid.UUID, image model.Image) (model.UserImagesToProcess, error) {
|
|
tx, err := m.dbPool.BeginTx(ctx, nil)
|
|
if err != nil {
|
|
return model.UserImagesToProcess{}, fmt.Errorf("Failed to begin transaction", err)
|
|
}
|
|
|
|
insertImageStmt := Image.
|
|
INSERT(Image.ImageName, Image.Image, Image.Description).
|
|
VALUES(image.ImageName, image.Image, image.Description).
|
|
RETURNING(Image.ID)
|
|
|
|
insertedImage := model.Image{}
|
|
err = insertImageStmt.QueryContext(ctx, tx, &insertedImage)
|
|
if err != nil {
|
|
return model.UserImagesToProcess{}, fmt.Errorf("Could not insert/query new image. SQL %s.", insertImageStmt.DebugSql(), err)
|
|
}
|
|
|
|
stmt := UserImagesToProcess.
|
|
INSERT(UserImagesToProcess.UserID, UserImagesToProcess.ImageID).
|
|
VALUES(userId, insertedImage.ID).
|
|
RETURNING(UserImagesToProcess.AllColumns)
|
|
|
|
userImage := model.UserImagesToProcess{}
|
|
err = stmt.QueryContext(ctx, tx, &userImage)
|
|
if err != nil {
|
|
return model.UserImagesToProcess{}, fmt.Errorf("Could not insert user_image", err)
|
|
}
|
|
|
|
err = tx.Commit()
|
|
|
|
return userImage, err
|
|
}
|
|
|
|
func (m ImageModel) GetToProcess(ctx context.Context, imageId uuid.UUID) (UserProcessingImage, error) {
|
|
getToProcessStmt := SELECT(UserImagesToProcess.AllColumns, Image.ID, Image.ImageName).
|
|
FROM(
|
|
UserImagesToProcess.INNER_JOIN(
|
|
Image, Image.ID.EQ(UserImagesToProcess.ImageID),
|
|
),
|
|
).
|
|
WHERE(UserImagesToProcess.ID.EQ(UUID(imageId)))
|
|
|
|
images := []UserProcessingImage{}
|
|
err := getToProcessStmt.QueryContext(ctx, m.dbPool, &images)
|
|
|
|
if len(images) != 1 {
|
|
return UserProcessingImage{}, fmt.Errorf("Expected 1, got %d\n", len(images))
|
|
}
|
|
|
|
return images[0], err
|
|
}
|
|
|
|
func (m ImageModel) GetToProcessWithData(ctx context.Context, imageId uuid.UUID) (ProcessingImageData, error) {
|
|
stmt := SELECT(UserImagesToProcess.AllColumns, Image.AllColumns).
|
|
FROM(
|
|
UserImagesToProcess.INNER_JOIN(
|
|
Image, Image.ID.EQ(UserImagesToProcess.ImageID),
|
|
),
|
|
).WHERE(UserImagesToProcess.ID.EQ(UUID(imageId)))
|
|
|
|
images := []ProcessingImageData{}
|
|
err := stmt.QueryContext(ctx, m.dbPool, &images)
|
|
|
|
if len(images) != 1 {
|
|
return ProcessingImageData{}, fmt.Errorf("Expected 1, got %d\n", len(images))
|
|
}
|
|
|
|
return images[0], err
|
|
}
|
|
|
|
func (m ImageModel) FinishProcessing(ctx context.Context, imageId uuid.UUID) (model.UserImages, error) {
|
|
imageToProcess, err := m.GetToProcess(ctx, imageId)
|
|
if err != nil {
|
|
return model.UserImages{}, err
|
|
}
|
|
|
|
tx, err := m.dbPool.Begin()
|
|
if err != nil {
|
|
return model.UserImages{}, err
|
|
}
|
|
|
|
insertImageStmt := UserImages.
|
|
INSERT(UserImages.UserID, UserImages.ImageID).
|
|
VALUES(imageToProcess.UserID, imageToProcess.ImageID).
|
|
RETURNING(UserImages.ID, UserImages.UserID, UserImages.ImageID)
|
|
|
|
userImage := model.UserImages{}
|
|
err = insertImageStmt.QueryContext(ctx, tx, &userImage)
|
|
if err != nil {
|
|
return model.UserImages{}, err
|
|
}
|
|
|
|
// Hacky. Update the status before removing so we can get our regular triggers
|
|
// to work.
|
|
|
|
updateStatusStmt := UserImagesToProcess.
|
|
UPDATE(UserImagesToProcess.Status).
|
|
SET(model.Progress_Complete).
|
|
WHERE(UserImagesToProcess.ID.EQ(UUID(imageToProcess.ID)))
|
|
|
|
_, err = updateStatusStmt.ExecContext(ctx, tx)
|
|
if err != nil {
|
|
return model.UserImages{}, err
|
|
}
|
|
|
|
// TODO:
|
|
// We cannot delete the image to process because our events rely on it.
|
|
// This indicates our DB structure with the two tables might need some adjusting.
|
|
// Or re-doing all together perhaps.
|
|
// (switching to a one table (user_images) could work)
|
|
// But for now, we can just not delete the images to process and set them to complete
|
|
|
|
// removeProcessingStmt := UserImagesToProcess.
|
|
// DELETE().
|
|
// WHERE(UserImagesToProcess.ID.EQ(UUID(imageToProcess.ID)))
|
|
//
|
|
// _, err = removeProcessingStmt.ExecContext(ctx, tx)
|
|
// if err != nil {
|
|
// return model.UserImages{}, err
|
|
// }
|
|
|
|
err = tx.Commit()
|
|
return userImage, err
|
|
}
|
|
|
|
func (m ImageModel) StartProcessing(ctx context.Context, processingImageId uuid.UUID) error {
|
|
startProcessingStmt := UserImagesToProcess.
|
|
UPDATE(UserImagesToProcess.Status).
|
|
SET(model.Progress_InProgress).
|
|
WHERE(UserImagesToProcess.ID.EQ(UUID(processingImageId)))
|
|
|
|
_, err := startProcessingStmt.ExecContext(ctx, m.dbPool)
|
|
|
|
return err
|
|
}
|
|
|
|
func (m ImageModel) Get(ctx context.Context, imageId uuid.UUID) (model.Image, error) {
|
|
getImageStmt := Image.SELECT(Image.AllColumns).
|
|
WHERE(Image.ID.EQ(UUID(imageId)))
|
|
|
|
image := model.Image{}
|
|
err := getImageStmt.QueryContext(ctx, m.dbPool, &image)
|
|
|
|
return image, err
|
|
}
|
|
|
|
func (m ImageModel) GetProcessing(ctx context.Context, userId uuid.UUID) ([]UserProcessingImage, error) {
|
|
getProcessingStmt := SELECT(UserImagesToProcess.AllColumns, Image.ID, Image.ImageName).
|
|
FROM(
|
|
UserImagesToProcess.INNER_JOIN(
|
|
Image, Image.ID.EQ(UserImagesToProcess.ImageID),
|
|
),
|
|
).WHERE(
|
|
UserImagesToProcess.UserID.EQ(UUID(userId)).
|
|
AND(UserImagesToProcess.Status.NOT_EQ(enum.Progress.Complete)),
|
|
)
|
|
|
|
images := []UserProcessingImage{}
|
|
err := getProcessingStmt.QueryContext(ctx, m.dbPool, &images)
|
|
|
|
return images, err
|
|
}
|
|
|
|
func (m ImageModel) AddDescription(ctx context.Context, imageId uuid.UUID, description string) error {
|
|
updateImageStmt := Image.UPDATE(Image.Description).
|
|
SET(description).
|
|
WHERE(Image.ID.EQ(UUID(imageId)))
|
|
|
|
_, err := updateImageStmt.ExecContext(ctx, m.dbPool)
|
|
|
|
return err
|
|
}
|
|
|
|
func (m ImageModel) IsUserAuthorized(ctx context.Context, imageId uuid.UUID, userId uuid.UUID) bool {
|
|
getImageUserId := UserImages.SELECT(UserImages.UserID).WHERE(UserImages.ImageID.EQ(UUID(imageId)))
|
|
|
|
userImage := model.UserImages{}
|
|
err := getImageUserId.QueryContext(ctx, m.dbPool, &userImage)
|
|
|
|
return err != nil && userImage.UserID.String() == userId.String()
|
|
}
|
|
|
|
func NewImageModel(db *sql.DB) ImageModel {
|
|
return ImageModel{dbPool: db}
|
|
}
|