Skip to content
Snippets Groups Projects
Verified Commit 69326f74 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Improve image APIs

parent 171cd46c
Branches
No related tags found
1 merge request!1Replace entire project structure
Pipeline #2575 failed
package api
import (
"context"
"database/sql"
"git.kuschku.de/justjanne/imghost-frontend/environment"
"git.kuschku.de/justjanne/imghost-frontend/model"
"git.kuschku.de/justjanne/imghost-frontend/util"
"github.com/gorilla/mux"
"net/http"
)
func EnrichImageInfo(env environment.FrontendEnvironment, image model.Image) (info model.ImageInfo, err error) {
info.Image = image
info.State, err = env.Repositories.ImageStates.Get(image.Id)
if err != nil {
return
}
imageUrl, err := env.Storage.UrlFor(context.Background(), env.Configuration.Storage.ImageBucket, info.Image.Id)
if err != nil {
return
}
info.Url = imageUrl.String()
return
}
func GetImage(env environment.FrontendEnvironment) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
var err error
......@@ -37,12 +21,12 @@ func GetImage(env environment.FrontendEnvironment) http.Handler {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
info, err := EnrichImageInfo(env, image)
err = image.LoadUrl(env.Storage, env.Configuration.Storage)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
util.ReturnJson(writer, info)
util.ReturnJson(writer, image)
})
}
......@@ -3,7 +3,6 @@ package api
import (
"git.kuschku.de/justjanne/imghost-frontend/auth"
"git.kuschku.de/justjanne/imghost-frontend/environment"
"git.kuschku.de/justjanne/imghost-frontend/model"
"git.kuschku.de/justjanne/imghost-frontend/util"
"net/http"
)
......@@ -15,15 +14,15 @@ func ListImages(env environment.FrontendEnvironment) http.Handler {
http.Error(writer, err.Error(), http.StatusUnauthorized)
}
images, err := env.Repositories.Images.List(user)
var infos []model.ImageInfo
for _, image := range images {
info, err := EnrichImageInfo(env, image)
for idx, image := range images {
err = image.LoadUrl(env.Storage, env.Configuration.Storage)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
infos = append(infos, info)
images[idx] = image
}
util.ReturnJson(writer, infos)
util.ReturnJson(writer, images)
})
}
......@@ -139,7 +139,7 @@ func UploadImage(env environment.FrontendEnvironment) http.Handler {
return
}
println("Enqueued task")
err = env.Repositories.ImageStates.Update(image.Id, repo.StateQueued)
err = env.Repositories.Images.UpdateState(image.Id, repo.StateQueued)
if err != nil {
println("failed updating image state")
http.Error(writer, err.Error(), http.StatusInternalServerError)
......
......@@ -24,9 +24,6 @@ func NewBackendEnvironment(config configuration.BackendConfiguration) (env Backe
if env.Repositories.Images, err = repo.NewImageRepo(env.Database); err != nil {
return
}
if env.Repositories.ImageStates, err = repo.NewImageStateRepo(env.Database); err != nil {
return
}
if env.Repositories.Albums, err = repo.NewAlbumRepo(env.Database); err != nil {
return
}
......
......@@ -26,9 +26,6 @@ func NewFrontendEnvironment(config configuration.FrontendConfiguration) (env Fro
if env.Repositories.Images, err = repo.NewImageRepo(env.Database); err != nil {
return
}
if env.Repositories.ImageStates, err = repo.NewImageStateRepo(env.Database); err != nil {
return
}
if env.Repositories.Albums, err = repo.NewAlbumRepo(env.Database); err != nil {
return
}
......
......@@ -4,7 +4,6 @@ import "git.kuschku.de/justjanne/imghost-frontend/repo"
type Repositories struct {
Images repo.Images
ImageStates repo.ImageStates
Albums repo.Albums
AlbumImages repo.AlbumImages
}
......@@ -2,6 +2,8 @@ package model
import (
"errors"
"git.kuschku.de/justjanne/imghost-frontend/configuration"
"git.kuschku.de/justjanne/imghost-frontend/storage"
"time"
)
......@@ -14,6 +16,8 @@ type Image struct {
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
OriginalName string `json:"original_name" db:"original_name"`
MimeType string `json:"mime_type" db:"mime_type"`
State string `json:"state" db:"state"`
Url string `json:"url"`
}
func (image Image) VerifyOwner(user User) error {
......@@ -23,3 +27,8 @@ func (image Image) VerifyOwner(user User) error {
return nil
}
func (image *Image) LoadUrl(storage storage.Storage, config configuration.StorageConfiguration) (err error) {
image.Url = storage.UrlFor(config.ImageBucket, image.Id).String()
return
}
package model
type ImageInfo struct {
Image Image `json:"image"`
State string `json:"state"`
Url string `json:"url"`
}
package repo
import (
"github.com/jmoiron/sqlx"
)
const (
StateCreated = "created"
StateQueued = "queued"
StateInProgress = "in_progress"
StateDone = "done"
StateError = "error"
)
type ImageStates struct {
db *sqlx.DB
queryGet *sqlx.NamedStmt
stmtUpdate *sqlx.NamedStmt
}
func NewImageStateRepo(db *sqlx.DB) (repo ImageStates, err error) {
repo.db = db
repo.queryGet, err = db.PrepareNamed(`
SELECT state
FROM images
WHERE id = :imageId
`)
if err != nil {
return
}
repo.stmtUpdate, err = db.PrepareNamed(`
UPDATE images
SET state = :state
WHERE id = :imageId
`)
if err != nil {
return
}
return repo, nil
}
func (repo ImageStates) Get(imageId string) (state string, err error) {
err = repo.queryGet.Get(&state, map[string]interface{}{
"imageId": imageId,
})
return
}
func (repo ImageStates) Update(imageId string, state string) (err error) {
_, err = repo.stmtUpdate.Exec(map[string]interface{}{
"imageId": imageId,
"state": state,
})
return
}
......@@ -6,14 +6,23 @@ import (
)
type Images struct {
db *sqlx.DB
queryList *sqlx.NamedStmt
queryGet *sqlx.NamedStmt
stmtCreate *sqlx.NamedStmt
stmtUpdate *sqlx.NamedStmt
stmtDelete *sqlx.NamedStmt
db *sqlx.DB
queryList *sqlx.NamedStmt
queryGet *sqlx.NamedStmt
stmtCreate *sqlx.NamedStmt
stmtUpdate *sqlx.NamedStmt
stmtUpdateState *sqlx.NamedStmt
stmtDelete *sqlx.NamedStmt
}
const (
StateCreated = "created"
StateQueued = "queued"
StateInProgress = "in_progress"
StateDone = "done"
StateError = "error"
)
func NewImageRepo(db *sqlx.DB) (repo Images, err error) {
repo.db = db
repo.queryList, err = db.PrepareNamed(`
......@@ -23,7 +32,8 @@ func NewImageRepo(db *sqlx.DB) (repo Images, err error) {
description,
original_name,
created_at,
updated_at
updated_at,
state
FROM images
WHERE owner = :userId
ORDER BY created_at DESC
......@@ -38,7 +48,8 @@ func NewImageRepo(db *sqlx.DB) (repo Images, err error) {
description,
original_name,
created_at,
updated_at
updated_at,
state
FROM images
WHERE id = :imageId
`)
......@@ -62,6 +73,14 @@ func NewImageRepo(db *sqlx.DB) (repo Images, err error) {
if err != nil {
return
}
repo.stmtUpdateState, err = db.PrepareNamed(`
UPDATE images
SET state = :state
WHERE id = :imageId
`)
if err != nil {
return
}
repo.stmtDelete, err = db.PrepareNamed(`
DELETE FROM images
WHERE id = :imageId
......@@ -120,6 +139,14 @@ func (repo Images) Update(changed model.Image) (err error) {
return
}
func (repo Images) UpdateState(imageId string, state string) (err error) {
_, err = repo.stmtUpdateState.Exec(map[string]interface{}{
"imageId": imageId,
"state": state,
})
return
}
func (repo Images) Delete(changed model.Image) (err error) {
_, err = repo.stmtDelete.Exec(map[string]interface{}{
"imageId": changed.Id,
......
......@@ -8,7 +8,7 @@ import (
"io"
"net/url"
"os"
"time"
"path/filepath"
)
type Storage struct {
......@@ -60,12 +60,8 @@ func (storage Storage) DownloadFile(ctx context.Context, bucketName string, file
return
}
func (storage Storage) UrlFor(ctx context.Context, bucketName string, fileName string) (url *url.URL, err error) {
url, err = storage.s3client.PresignedGetObject(
ctx,
bucketName,
fileName,
7*24*time.Hour,
map[string][]string{})
return
func (storage Storage) UrlFor(bucketName string, fileName string) *url.URL {
fileUrl := *storage.s3client.EndpointURL()
fileUrl.Path = filepath.Join(fileUrl.Path, bucketName, fileName)
return &fileUrl
}
......@@ -31,7 +31,7 @@ func (processor *ImageProcessor) ProcessTask(ctx context.Context, task *asynq.Ta
println("parsed task: " + payload.ImageId)
if err = processor.env.Repositories.ImageStates.Update(payload.ImageId, repo.StateInProgress); err != nil {
if err = processor.env.Repositories.Images.UpdateState(payload.ImageId, repo.StateInProgress); err != nil {
println("failed to set image state: " + payload.ImageId)
println(err.Error())
return
......@@ -44,7 +44,7 @@ func (processor *ImageProcessor) ProcessTask(ctx context.Context, task *asynq.Ta
if err != nil {
println("failed to create temp file: " + payload.ImageId)
println(err.Error())
_ = processor.env.Repositories.ImageStates.Update(payload.ImageId, repo.StateError)
_ = processor.env.Repositories.Images.UpdateState(payload.ImageId, repo.StateError)
return
}
err = processor.env.Storage.DownloadFile(
......@@ -55,20 +55,20 @@ func (processor *ImageProcessor) ProcessTask(ctx context.Context, task *asynq.Ta
if err != nil {
println("failed to download file: " + sourceFile.Name())
println(err.Error())
_ = processor.env.Repositories.ImageStates.Update(payload.ImageId, repo.StateError)
_ = processor.env.Repositories.Images.UpdateState(payload.ImageId, repo.StateError)
return
}
if err = wand.ReadImage(sourceFile.Name()); err != nil {
println("failed to read file: " + sourceFile.Name())
println(err.Error())
_ = processor.env.Repositories.ImageStates.Update(payload.ImageId, repo.StateError)
_ = processor.env.Repositories.Images.UpdateState(payload.ImageId, repo.StateError)
return
}
var originalImage imgconv.ImageHandle
if originalImage, err = imgconv.NewImage(wand); err != nil {
println("failed to load file: " + sourceFile.Name())
println(err.Error())
_ = processor.env.Repositories.ImageStates.Update(payload.ImageId, repo.StateError)
_ = processor.env.Repositories.Images.UpdateState(payload.ImageId, repo.StateError)
return err
}
......@@ -102,11 +102,11 @@ func (processor *ImageProcessor) ProcessTask(ctx context.Context, task *asynq.Ta
if err != nil {
println("failed to convert image file")
println(err.Error())
_ = processor.env.Repositories.ImageStates.Update(payload.ImageId, repo.StateError)
_ = processor.env.Repositories.Images.UpdateState(payload.ImageId, repo.StateError)
return
}
if err = processor.env.Repositories.ImageStates.Update(payload.ImageId, repo.StateDone); err != nil {
if err = processor.env.Repositories.Images.UpdateState(payload.ImageId, repo.StateDone); err != nil {
return
}
......
......@@ -10,16 +10,18 @@ export default function ImageList() {
<p>{error as string}</p>
<ul>
{data?.map(info => (
<li>
<p>{info.image?.id}</p>
<p>{info.image?.title}</p>
<p>{info.image?.description}</p>
<p>{info.image?.original_name}</p>
<p>{info.image?.mime_type}</p>
<p>{info.image?.created_at}</p>
<p>{info.image?.updated_at}</p>
<li key={info.id}>
<p>{info.id}</p>
<p>{info.owner}</p>
<p>{info.title}</p>
<p>{info.description}</p>
<p>{info.original_name}</p>
<p>{info.mime_type}</p>
<p>{info.created_at}</p>
<p>{info.updated_at}</p>
<p>{info.state}</p>
<img src={info.url} alt=""/>
<p>{info.url}</p>
<img src={info.url+"t"} alt=""/>
</li>
))}
</ul>
......
......@@ -7,4 +7,6 @@ export interface Image {
updated_at: string,
original_name: string,
mime_type: string,
state: string,
url: string,
}
import {Image} from "./Image";
export interface ImageInfo {
image: Image,
state: string,
url: string,
}
import {useQuery} from "react-query";
import axios from "axios";
import {useBaseUrl} from "./baseUrlContext";
import {ImageInfo} from "./model/ImageInfo";
import {Image} from "./model/Image";
export const useListImages = () => {
const baseUrl = useBaseUrl();
return useQuery(
"connector-deployments",
() => axios.get<ImageInfo[]>(
() => axios.get<Image[]>(
"api/v1/images",
{
baseURL: baseUrl
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment