Skip to content
Snippets Groups Projects
Commit 066686cf authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Implement all basic APIs

parent 780ad861
Branches ui-rewrite
No related tags found
1 merge request!1Replace entire project structure
Pipeline #2582 failed
Showing
with 235 additions and 73 deletions
package api
import (
"encoding/json"
"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"
)
func CreateAlbum(env environment.FrontendEnvironment) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
var err error
user, err := auth.ParseUser(request, env)
if err != nil {
http.Error(writer, err.Error(), http.StatusUnauthorized)
return
}
println("parsed user: " + user.Name)
var data model.Album
err = json.NewDecoder(request.Body).Decode(&data)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
data.Id = generateId()
data.Owner = user.Id
err = env.Repositories.Albums.Create(data)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
album, err := env.Repositories.Albums.Get(data.Id)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
util.ReturnJson(writer, album)
})
}
......@@ -30,6 +30,11 @@ func GetAlbum(env environment.FrontendEnvironment) http.Handler {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
image.Metadata, err = env.Repositories.ImageMetadata.List(image)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
album.Images[i] = image
}
......
......@@ -34,6 +34,11 @@ func ListAlbums(env environment.FrontendEnvironment) http.Handler {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
image.Metadata, err = env.Repositories.ImageMetadata.List(image)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
album.Images[j] = image
}
albums[i] = album
......
......@@ -23,7 +23,7 @@ func ReorderAlbum(env environment.FrontendEnvironment) http.Handler {
return
}
var changes []model.AlbumImage
var changes []model.Image
err = json.NewDecoder(request.Body).Decode(&changes)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
......@@ -32,8 +32,8 @@ func ReorderAlbum(env environment.FrontendEnvironment) http.Handler {
for index, image := range changes {
image.Album = album.Id
err = env.Repositories.AlbumImages.Reorder(image, index)
position := index
err = env.Repositories.AlbumImages.Reorder(image, position)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
......
package api
import (
"encoding/json"
"git.kuschku.de/justjanne/imghost-frontend/environment"
"git.kuschku.de/justjanne/imghost-frontend/model"
"github.com/gorilla/mux"
"net/http"
)
func CreateAlbumImage(env environment.FrontendEnvironment) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
vars := mux.Vars(request)
var data model.Image
err := json.NewDecoder(request.Body).Decode(&data)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
data.Album = vars["albumId"]
err = env.Repositories.AlbumImages.Create(data)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
writer.WriteHeader(http.StatusNoContent)
})
}
......@@ -25,7 +25,7 @@ func UpdateAlbumImage(env environment.FrontendEnvironment) http.Handler {
return
}
var changes model.AlbumImage
var changes model.Image
err = json.NewDecoder(request.Body).Decode(&changes)
if err != nil {
http.Error(writer, err.Error(), http.StatusInternalServerError)
......
......@@ -51,6 +51,9 @@ func main() {
router.Handle(
"/api/v1/albums",
api.ListAlbums(env)).Methods(http.MethodGet, http.MethodOptions)
router.Handle(
"/api/v1/albums",
api.CreateAlbum(env)).Methods(http.MethodPost, http.MethodOptions)
router.Handle(
"/api/v1/albums/{albumId}",
api.GetAlbum(env)).Methods(http.MethodGet, http.MethodOptions)
......@@ -68,6 +71,9 @@ func main() {
router.Handle(
"/api/v1/albums/{albumId}/images/{imageId}",
api.UpdateAlbumImage(env)).Methods(http.MethodPost, http.MethodOptions)
router.Handle(
"/api/v1/albums/{albumId}/images",
api.CreateAlbumImage(env)).Methods(http.MethodPost, http.MethodOptions)
router.Handle(
"/api/v1/albums/{albumId}/images/{imageId}",
api.DeleteAlbumImage(env)).Methods(http.MethodDelete, http.MethodOptions)
......
......@@ -6,13 +6,13 @@ import (
)
type Album struct {
Id string `json:"id" db:"id"`
Owner string `json:"owner" db:"owner"`
Title string `json:"title" db:"title"`
Description string `json:"description" db:"description"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
Images []AlbumImage `json:"images"`
Id string `json:"id" db:"id"`
Owner string `json:"owner" db:"owner"`
Title string `json:"title" db:"title"`
Description string `json:"description" db:"description"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
Images []Image `json:"images"`
}
func (album Album) VerifyOwner(user User) error {
......
package model
import (
"git.kuschku.de/justjanne/imghost-frontend/configuration"
"git.kuschku.de/justjanne/imghost-frontend/storage"
)
type AlbumImage struct {
Album string `json:"album" db:"album"`
Image string `json:"image" db:"image"`
Title string `json:"title" db:"title"`
Description string `json:"description" db:"description"`
Url string `json:"url"`
}
func (image *AlbumImage) LoadUrl(storage storage.Storage, config configuration.StorageConfiguration) (err error) {
image.Url = storage.UrlFor(config.ImageBucket, image.Image).String()
return
}
......@@ -8,6 +8,7 @@ import (
)
type Image struct {
Album string `json:"album,omitempty" db:"album"`
Id string `json:"id" db:"id"`
Owner string `json:"owner" db:"owner"`
Title string `json:"title" db:"title"`
......
......@@ -19,26 +19,42 @@ type AlbumImages struct {
func NewAlbumImageRepo(db *sqlx.DB) (repo AlbumImages, err error) {
repo.db = db
repo.queryList, err = db.PrepareNamed(`
SELECT album,
image,
title,
description
SELECT album_images.album,
images.id,
albums.owner,
album_images.title,
album_images.description,
albums.created_at,
albums.updated_at,
images.original_name,
images.type,
images.state
FROM album_images
WHERE album = :albumId
ORDER BY position
JOIN albums ON album_images.album = albums.id
JOIN images ON album_images.image = images.id
WHERE album_images.album = :albumId
ORDER BY album_images.position
`)
if err != nil {
return
}
repo.queryGet, err = db.PrepareNamed(`
SELECT album,
image,
title,
description
SELECT album_images.album,
images.id,
albums.owner,
album_images.title,
album_images.description,
albums.created_at,
albums.updated_at,
images.original_name,
images.type,
images.state
FROM album_images
WHERE album = :albumId
AND image = :imageId
ORDER BY position
JOIN albums ON album_images.album = albums.id
JOIN images ON album_images.image = images.id
WHERE album_images.album = :albumId
AND album_images.image = :imageId
ORDER BY album_images.position
`)
if err != nil {
return
......@@ -67,7 +83,7 @@ func NewAlbumImageRepo(db *sqlx.DB) (repo AlbumImages, err error) {
repo.stmtDelete, err = db.PrepareNamed(`
DELETE FROM album_images
WHERE album = :albumId
AND image = :imageID
AND image = :imageId
`)
if err != nil {
return
......@@ -92,7 +108,7 @@ func NewAlbumImageRepo(db *sqlx.DB) (repo AlbumImages, err error) {
return repo, nil
}
func (repo AlbumImages) List(albumId string) (images []model.AlbumImage, err error) {
func (repo AlbumImages) List(albumId string) (images []model.Image, err error) {
rows, err := repo.queryList.Queryx(map[string]interface{}{
"albumId": albumId,
})
......@@ -100,7 +116,7 @@ func (repo AlbumImages) List(albumId string) (images []model.AlbumImage, err err
return
}
for rows.Next() {
var image model.AlbumImage
var image model.Image
err = rows.StructScan(&image)
if err != nil {
return
......@@ -110,7 +126,7 @@ func (repo AlbumImages) List(albumId string) (images []model.AlbumImage, err err
return
}
func (repo AlbumImages) Get(albumId string, imageId string) (image model.AlbumImage, err error) {
func (repo AlbumImages) Get(albumId string, imageId string) (image model.Image, err error) {
err = repo.queryGet.Get(&image, map[string]interface{}{
"albumId": albumId,
"imageId": imageId,
......@@ -118,46 +134,46 @@ func (repo AlbumImages) Get(albumId string, imageId string) (image model.AlbumIm
return
}
func (repo AlbumImages) Create(new model.AlbumImage) (err error) {
func (repo AlbumImages) Create(new model.Image) (err error) {
_, err = repo.stmtCreate.Exec(map[string]interface{}{
"albumId": new.Album,
"imageId": new.Image,
"imageId": new.Id,
"title": new.Title,
"description": new.Description,
})
return
}
func (repo AlbumImages) Update(changed model.AlbumImage) (err error) {
func (repo AlbumImages) Update(changed model.Image) (err error) {
_, err = repo.stmtUpdate.Exec(map[string]interface{}{
"albumId": changed.Album,
"imageId": changed.Image,
"imageId": changed.Id,
"title": changed.Title,
"description": changed.Description,
})
return
}
func (repo AlbumImages) Reorder(changed model.AlbumImage, position int) (err error) {
func (repo AlbumImages) Reorder(changed model.Image, position int) (err error) {
_, err = repo.stmtReorder.Exec(map[string]interface{}{
"albumId": changed.Album,
"imageId": changed.Image,
"imageId": changed.Id,
"position": position,
})
return
}
func (repo AlbumImages) Delete(changed model.AlbumImage) (err error) {
func (repo AlbumImages) Delete(changed model.Image) (err error) {
_, err = repo.stmtDelete.Exec(map[string]interface{}{
"albumId": changed.Album,
"imageId": changed.Image,
"imageId": changed.Id,
})
return
}
func (repo AlbumImages) DeleteAll(changed model.AlbumImage) (err error) {
func (repo AlbumImages) DeleteAll(changed model.Album) (err error) {
_, err = repo.stmtDeleteAll.Exec(map[string]interface{}{
"albumId": changed.Album,
"albumId": changed.Id,
})
return
}
import './App.css';
import {BaseUrlProvider} from './api/baseUrlContext';
import {BaseUrlProvider} from './api/util/BaseUrlContext';
import {QueryClient, QueryClientProvider} from "react-query";
import {BrowserRouter, Link, Route} from "react-router-dom";
import {Redirect, Switch} from "react-router";
import {AppBar, Button, Toolbar, Typography} from "@material-ui/core";
import {useErrorDisplay} from "./components/ErrorContext";
import {useErrorDisplay} from "./components/error/ErrorContext";
import {AlbumListPage} from "./pages/AlbumListPage";
import {ImageDetailPage} from './pages/ImageDetailPage';
import {ImageListPage} from "./pages/ImageListPage";
import {UploadView} from "./components/UploadView";
import {AlbumDetailPage} from "./pages/AlbumDetailPage";
const queryClient = new QueryClient();
......@@ -62,6 +63,9 @@ export function App() {
<Route path="/albums">
<AlbumListPage/>
</Route>
<Route path="/a/:albumId">
<AlbumDetailPage/>
</Route>
<Redirect from="/" to="/images"/>
</Switch>
</ErrorWrapper>
......
export interface AlbumCreate {
title: string,
description: string
}
export interface AlbumImage {
album: string,
image: string,
title: string,
description: string,
url: string,
import {Image} from "./Image";
export interface AlbumImage extends Image {
album: string
}
export interface AlbumImageCreate {
album: string,
id: string,
title: string,
description: string
}
import {ImageState} from "./ImageState";
export interface Image {
id: string,
owner: string,
......@@ -13,11 +15,3 @@ export interface Image {
},
url: string,
}
export enum ImageState {
CREATED = "created",
QUEUED = "queued",
IN_PROGRESS = "in_progress",
DONE = "done",
ERROR = "error"
}
export enum ImageState {
CREATED = "created",
QUEUED = "queued",
IN_PROGRESS = "in_progress",
DONE = "done",
ERROR = "error"
}
import {useBaseUrl} from "./util/BaseUrlContext";
import {useMutation, useQueryClient} from "react-query";
import axios from "axios";
import {Album} from "./model/Album";
import {AlbumCreate} from "./model/AlbumCreate";
export const useCreateAlbum = () => {
const baseUrl = useBaseUrl();
const queryClient = useQueryClient();
return useMutation<Album, unknown, AlbumCreate>((album: AlbumCreate) => axios.post(
`api/v1/albums`,
album,
{
baseURL: baseUrl
}
), {
onSuccess: () => {
queryClient.invalidateQueries('album')
},
})
}
import {useBaseUrl} from "./util/BaseUrlContext";
import {useMutation, useQueryClient} from "react-query";
import axios from "axios";
import {AlbumImageCreate} from "./model/AlbumImageCreate";
export const useCreateAlbumImage = () => {
const baseUrl = useBaseUrl();
const queryClient = useQueryClient();
return useMutation<void, unknown, AlbumImageCreate>((albumImage: AlbumImageCreate) => axios.post(
`api/v1/albums/${albumImage.album}/images`,
albumImage,
{
baseURL: baseUrl
}
), {
onSuccess: () => {
queryClient.invalidateQueries('album')
},
})
}
import {useBaseUrl} from "./util/BaseUrlContext";
import {useMutation, useQueryClient} from "react-query";
import axios from "axios";
import {Album} from "./model/Album";
export const useDeleteAlbum = () => {
const baseUrl = useBaseUrl();
const queryClient = useQueryClient();
return useMutation<void, unknown, Album>((album: Album) => axios.delete(
`api/v1/albums/${album.id}`,
{
baseURL: baseUrl
}
), {
onSuccess: () => {
queryClient.invalidateQueries('album')
},
})
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment