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