1
Fork 0

Start on image proccessing

This commit is contained in:
viktorstrate 2020-02-02 00:29:42 +01:00
parent a57c111630
commit d81e945b68
8 changed files with 720 additions and 16 deletions

View File

@ -1,3 +1,4 @@
DROP TABLE IF EXISTS photo; DROP TABLE IF EXISTS photo;
DROP TABLE IF EXISTS album; DROP TABLE IF EXISTS album;
DROP TABLE IF EXISTS photo_url; DROP TABLE IF EXISTS photo_url;
DROP TABLE IF EXISTS photo_exif;

View File

@ -1,12 +1,28 @@
CREATE TABLE IF NOT EXISTS photo_url ( CREATE TABLE IF NOT EXISTS photo_url (
url_id int NOT NULL AUTO_INCREMENT, url_id int NOT NULL AUTO_INCREMENT,
path varchar(256) NUT NULL, token varchar(256) NOT NULL,
width int NOT NULL, width int NOT NULL,
height int NOT NULL, height int NOT NULL,
PRIMARY KEY (url_id) PRIMARY KEY (url_id)
); );
CREATE TABLE IF NOT EXISTS photo_exif (
exif_id int NOT NULL AUTO_INCREMENT,
camera varchar(256),
maker varchar(256),
lens varchar(256),
dateShot timestamp,
file_size_bytes bigint,
exposure varchar(256),
aperature float,
iso int(6),
focal_length float,
flash varchar(256),
PRIMARY KEY (exif_id)
);
CREATE TABLE IF NOT EXISTS album ( CREATE TABLE IF NOT EXISTS album (
album_id int NOT NULL AUTO_INCREMENT, album_id int NOT NULL AUTO_INCREMENT,
title varchar(256) NOT NULL, title varchar(256) NOT NULL,
@ -23,12 +39,14 @@ CREATE TABLE IF NOT EXISTS photo (
photo_id int NOT NULL AUTO_INCREMENT, photo_id int NOT NULL AUTO_INCREMENT,
title varchar(256) NOT NULL, title varchar(256) NOT NULL,
path varchar(512) NOT NULL UNIQUE, path varchar(512) NOT NULL UNIQUE,
-- original_url int NOT NULL, original_url int NOT NULL,
-- thumbnail_url int NOT NULL, thumbnail_url int NOT NULL,
album_id int NOT NULL, album_id int NOT NULL,
-- exif_id int NOT NULL, exif_id int,
PRIMARY KEY (photo_id), PRIMARY KEY (photo_id),
FOREIGN KEY (album_id) REFERENCES album(album_id),
FOREIGN KEY (exif_id) REFERENCES photo_exif(exif_id),
FOREIGN KEY (original_url) REFERENCES photo_url(url_id), FOREIGN KEY (original_url) REFERENCES photo_url(url_id),
FOREIGN KEY (thumbnail_url) REFERENCES photo_url(url_id) FOREIGN KEY (thumbnail_url) REFERENCES photo_url(url_id)
); );

View File

@ -10,6 +10,7 @@ import (
"strconv" "strconv"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time"
"github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/introspection" "github.com/99designs/gqlgen/graphql/introspection"
@ -70,6 +71,7 @@ type ComplexityRoot struct {
Photo struct { Photo struct {
Album func(childComplexity int) int Album func(childComplexity int) int
Exif func(childComplexity int) int
ID func(childComplexity int) int ID func(childComplexity int) int
Original func(childComplexity int) int Original func(childComplexity int) int
Path func(childComplexity int) int Path func(childComplexity int) int
@ -77,6 +79,20 @@ type ComplexityRoot struct {
Title func(childComplexity int) int Title func(childComplexity int) int
} }
PhotoExif struct {
Aperture func(childComplexity int) int
Camera func(childComplexity int) int
DateShot func(childComplexity int) int
Exposure func(childComplexity int) int
FileSize func(childComplexity int) int
Flash func(childComplexity int) int
FocalLength func(childComplexity int) int
Iso func(childComplexity int) int
Lens func(childComplexity int) int
Maker func(childComplexity int) int
Photo func(childComplexity int) int
}
PhotoURL struct { PhotoURL struct {
Height func(childComplexity int) int Height func(childComplexity int) int
URL func(childComplexity int) int URL func(childComplexity int) int
@ -257,6 +273,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Photo.Album(childComplexity), true return e.complexity.Photo.Album(childComplexity), true
case "Photo.exif":
if e.complexity.Photo.Exif == nil {
break
}
return e.complexity.Photo.Exif(childComplexity), true
case "Photo.id": case "Photo.id":
if e.complexity.Photo.ID == nil { if e.complexity.Photo.ID == nil {
break break
@ -292,6 +315,83 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Photo.Title(childComplexity), true return e.complexity.Photo.Title(childComplexity), true
case "PhotoEXIF.aperture":
if e.complexity.PhotoExif.Aperture == nil {
break
}
return e.complexity.PhotoExif.Aperture(childComplexity), true
case "PhotoEXIF.camera":
if e.complexity.PhotoExif.Camera == nil {
break
}
return e.complexity.PhotoExif.Camera(childComplexity), true
case "PhotoEXIF.dateShot":
if e.complexity.PhotoExif.DateShot == nil {
break
}
return e.complexity.PhotoExif.DateShot(childComplexity), true
case "PhotoEXIF.exposure":
if e.complexity.PhotoExif.Exposure == nil {
break
}
return e.complexity.PhotoExif.Exposure(childComplexity), true
case "PhotoEXIF.fileSize":
if e.complexity.PhotoExif.FileSize == nil {
break
}
return e.complexity.PhotoExif.FileSize(childComplexity), true
case "PhotoEXIF.flash":
if e.complexity.PhotoExif.Flash == nil {
break
}
return e.complexity.PhotoExif.Flash(childComplexity), true
case "PhotoEXIF.focalLength":
if e.complexity.PhotoExif.FocalLength == nil {
break
}
return e.complexity.PhotoExif.FocalLength(childComplexity), true
case "PhotoEXIF.iso":
if e.complexity.PhotoExif.Iso == nil {
break
}
return e.complexity.PhotoExif.Iso(childComplexity), true
case "PhotoEXIF.lens":
if e.complexity.PhotoExif.Lens == nil {
break
}
return e.complexity.PhotoExif.Lens(childComplexity), true
case "PhotoEXIF.maker":
if e.complexity.PhotoExif.Maker == nil {
break
}
return e.complexity.PhotoExif.Maker(childComplexity), true
case "PhotoEXIF.photo":
if e.complexity.PhotoExif.Photo == nil {
break
}
return e.complexity.PhotoExif.Photo(childComplexity), true
case "PhotoURL.height": case "PhotoURL.height":
if e.complexity.PhotoURL.Height == nil { if e.complexity.PhotoURL.Height == nil {
break break
@ -574,11 +674,35 @@ type Photo {
thumbnail: PhotoURL thumbnail: PhotoURL
"The album that holds the photo" "The album that holds the photo"
album: Album! album: Album!
# exif: PhotoEXIF exif: PhotoEXIF
# shares: [ShareToken] # shares: [ShareToken]
# downloads: [PhotoDownload] # downloads: [PhotoDownload]
} }
"EXIF metadata from the camera"
type PhotoEXIF {
photo: Photo
"The model name of the camera"
camera: String
"The maker of the camera"
maker: String
"The name of the lens"
lens: String
dateShot: Time
"The formatted filesize of the image"
fileSize: String
"The exposure time of the image"
exposure: String
"The aperature stops of the image"
aperture: Float
"The ISO setting of the image"
iso: Int
"The focal length of the lens, when the image was taken"
focalLength: String
"A formatted description of the flash settings, when the image was taken"
flash: String
}
`}, `},
) )
@ -1461,6 +1585,414 @@ func (ec *executionContext) _Photo_album(ctx context.Context, field graphql.Coll
return ec.marshalNAlbum2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res) return ec.marshalNAlbum2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res)
} }
func (ec *executionContext) _Photo_exif(ctx context.Context, field graphql.CollectedField, obj *models.Photo) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
ec.Tracer.EndFieldExecution(ctx)
}()
rctx := &graphql.ResolverContext{
Object: "Photo",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Exif, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*models.PhotoExif)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOPhotoEXIF2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPhotoExif(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoEXIF_photo(ctx context.Context, field graphql.CollectedField, obj *models.PhotoExif) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
ec.Tracer.EndFieldExecution(ctx)
}()
rctx := &graphql.ResolverContext{
Object: "PhotoEXIF",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Photo, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*models.Photo)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOPhoto2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPhoto(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoEXIF_camera(ctx context.Context, field graphql.CollectedField, obj *models.PhotoExif) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
ec.Tracer.EndFieldExecution(ctx)
}()
rctx := &graphql.ResolverContext{
Object: "PhotoEXIF",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Camera, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoEXIF_maker(ctx context.Context, field graphql.CollectedField, obj *models.PhotoExif) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
ec.Tracer.EndFieldExecution(ctx)
}()
rctx := &graphql.ResolverContext{
Object: "PhotoEXIF",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Maker, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoEXIF_lens(ctx context.Context, field graphql.CollectedField, obj *models.PhotoExif) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
ec.Tracer.EndFieldExecution(ctx)
}()
rctx := &graphql.ResolverContext{
Object: "PhotoEXIF",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Lens, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoEXIF_dateShot(ctx context.Context, field graphql.CollectedField, obj *models.PhotoExif) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
ec.Tracer.EndFieldExecution(ctx)
}()
rctx := &graphql.ResolverContext{
Object: "PhotoEXIF",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.DateShot, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*time.Time)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoEXIF_fileSize(ctx context.Context, field graphql.CollectedField, obj *models.PhotoExif) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
ec.Tracer.EndFieldExecution(ctx)
}()
rctx := &graphql.ResolverContext{
Object: "PhotoEXIF",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.FileSize, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoEXIF_exposure(ctx context.Context, field graphql.CollectedField, obj *models.PhotoExif) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
ec.Tracer.EndFieldExecution(ctx)
}()
rctx := &graphql.ResolverContext{
Object: "PhotoEXIF",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Exposure, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoEXIF_aperture(ctx context.Context, field graphql.CollectedField, obj *models.PhotoExif) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
ec.Tracer.EndFieldExecution(ctx)
}()
rctx := &graphql.ResolverContext{
Object: "PhotoEXIF",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Aperture, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*float64)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOFloat2ᚖfloat64(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoEXIF_iso(ctx context.Context, field graphql.CollectedField, obj *models.PhotoExif) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
ec.Tracer.EndFieldExecution(ctx)
}()
rctx := &graphql.ResolverContext{
Object: "PhotoEXIF",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Iso, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*int)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOInt2ᚖint(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoEXIF_focalLength(ctx context.Context, field graphql.CollectedField, obj *models.PhotoExif) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
ec.Tracer.EndFieldExecution(ctx)
}()
rctx := &graphql.ResolverContext{
Object: "PhotoEXIF",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.FocalLength, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoEXIF_flash(ctx context.Context, field graphql.CollectedField, obj *models.PhotoExif) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
ec.Tracer.EndFieldExecution(ctx)
}()
rctx := &graphql.ResolverContext{
Object: "PhotoEXIF",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithResolverContext(ctx, rctx)
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Flash, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
rctx.Result = res
ctx = ec.Tracer.StartFieldChildExecution(ctx)
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) _PhotoURL_url(ctx context.Context, field graphql.CollectedField, obj *models.PhotoURL) (ret graphql.Marshaler) { func (ec *executionContext) _PhotoURL_url(ctx context.Context, field graphql.CollectedField, obj *models.PhotoURL) (ret graphql.Marshaler) {
ctx = ec.Tracer.StartFieldExecution(ctx, field) ctx = ec.Tracer.StartFieldExecution(ctx, field)
defer func() { defer func() {
@ -3499,6 +4031,52 @@ func (ec *executionContext) _Photo(ctx context.Context, sel ast.SelectionSet, ob
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
invalids++ invalids++
} }
case "exif":
out.Values[i] = ec._Photo_exif(ctx, field, obj)
default:
panic("unknown field " + strconv.Quote(field.Name))
}
}
out.Dispatch()
if invalids > 0 {
return graphql.Null
}
return out
}
var photoEXIFImplementors = []string{"PhotoEXIF"}
func (ec *executionContext) _PhotoEXIF(ctx context.Context, sel ast.SelectionSet, obj *models.PhotoExif) graphql.Marshaler {
fields := graphql.CollectFields(ec.RequestContext, sel, photoEXIFImplementors)
out := graphql.NewFieldSet(fields)
var invalids uint32
for i, field := range fields {
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("PhotoEXIF")
case "photo":
out.Values[i] = ec._PhotoEXIF_photo(ctx, field, obj)
case "camera":
out.Values[i] = ec._PhotoEXIF_camera(ctx, field, obj)
case "maker":
out.Values[i] = ec._PhotoEXIF_maker(ctx, field, obj)
case "lens":
out.Values[i] = ec._PhotoEXIF_lens(ctx, field, obj)
case "dateShot":
out.Values[i] = ec._PhotoEXIF_dateShot(ctx, field, obj)
case "fileSize":
out.Values[i] = ec._PhotoEXIF_fileSize(ctx, field, obj)
case "exposure":
out.Values[i] = ec._PhotoEXIF_exposure(ctx, field, obj)
case "aperture":
out.Values[i] = ec._PhotoEXIF_aperture(ctx, field, obj)
case "iso":
out.Values[i] = ec._PhotoEXIF_iso(ctx, field, obj)
case "focalLength":
out.Values[i] = ec._PhotoEXIF_focalLength(ctx, field, obj)
case "flash":
out.Values[i] = ec._PhotoEXIF_flash(ctx, field, obj)
default: default:
panic("unknown field " + strconv.Quote(field.Name)) panic("unknown field " + strconv.Quote(field.Name))
} }
@ -4515,6 +5093,17 @@ func (ec *executionContext) marshalOPhoto2ᚖgithubᚗcomᚋviktorstrateᚋphoto
return ec._Photo(ctx, sel, v) return ec._Photo(ctx, sel, v)
} }
func (ec *executionContext) marshalOPhotoEXIF2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPhotoExif(ctx context.Context, sel ast.SelectionSet, v models.PhotoExif) graphql.Marshaler {
return ec._PhotoEXIF(ctx, sel, &v)
}
func (ec *executionContext) marshalOPhotoEXIF2ᚖgithubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPhotoExif(ctx context.Context, sel ast.SelectionSet, v *models.PhotoExif) graphql.Marshaler {
if v == nil {
return graphql.Null
}
return ec._PhotoEXIF(ctx, sel, v)
}
func (ec *executionContext) marshalOPhotoURL2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPhotoURL(ctx context.Context, sel ast.SelectionSet, v models.PhotoURL) graphql.Marshaler { func (ec *executionContext) marshalOPhotoURL2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐPhotoURL(ctx context.Context, sel ast.SelectionSet, v models.PhotoURL) graphql.Marshaler {
return ec._PhotoURL(ctx, sel, &v) return ec._PhotoURL(ctx, sel, &v)
} }
@ -4549,6 +5138,29 @@ func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel as
return ec.marshalOString2string(ctx, sel, *v) return ec.marshalOString2string(ctx, sel, *v)
} }
func (ec *executionContext) unmarshalOTime2timeᚐTime(ctx context.Context, v interface{}) (time.Time, error) {
return graphql.UnmarshalTime(v)
}
func (ec *executionContext) marshalOTime2timeᚐTime(ctx context.Context, sel ast.SelectionSet, v time.Time) graphql.Marshaler {
return graphql.MarshalTime(v)
}
func (ec *executionContext) unmarshalOTime2ᚖtimeᚐTime(ctx context.Context, v interface{}) (*time.Time, error) {
if v == nil {
return nil, nil
}
res, err := ec.unmarshalOTime2timeᚐTime(ctx, v)
return &res, err
}
func (ec *executionContext) marshalOTime2ᚖtimeᚐTime(ctx context.Context, sel ast.SelectionSet, v *time.Time) graphql.Marshaler {
if v == nil {
return graphql.Null
}
return ec.marshalOTime2timeᚐTime(ctx, sel, *v)
}
func (ec *executionContext) marshalOUser2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx context.Context, sel ast.SelectionSet, v models.User) graphql.Marshaler { func (ec *executionContext) marshalOUser2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUser(ctx context.Context, sel ast.SelectionSet, v models.User) graphql.Marshaler {
return ec._User(ctx, sel, &v) return ec._User(ctx, sel, &v)
} }

View File

@ -2,6 +2,10 @@
package models package models
import (
"time"
)
type Album struct { type Album struct {
ID string `json:"id"` ID string `json:"id"`
Title *string `json:"title"` Title *string `json:"title"`
@ -28,7 +32,32 @@ type Photo struct {
// URL to display the photo in a smaller resolution // URL to display the photo in a smaller resolution
Thumbnail *PhotoURL `json:"thumbnail"` Thumbnail *PhotoURL `json:"thumbnail"`
// The album that holds the photo // The album that holds the photo
Album *Album `json:"album"` Album *Album `json:"album"`
Exif *PhotoExif `json:"exif"`
}
// EXIF metadata from the camera
type PhotoExif struct {
Photo *Photo `json:"photo"`
// The model name of the camera
Camera *string `json:"camera"`
// The maker of the camera
Maker *string `json:"maker"`
// The name of the lens
Lens *string `json:"lens"`
DateShot *time.Time `json:"dateShot"`
// The formatted filesize of the image
FileSize *string `json:"fileSize"`
// The exposure time of the image
Exposure *string `json:"exposure"`
// The aperature stops of the image
Aperture *float64 `json:"aperture"`
// The ISO setting of the image
Iso *int `json:"iso"`
// The focal length of the lens, when the image was taken
FocalLength *string `json:"focalLength"`
// A formatted description of the flash settings, when the image was taken
Flash *string `json:"flash"`
} }
type PhotoURL struct { type PhotoURL struct {

View File

@ -35,11 +35,7 @@ func NewUserFromRow(row *sql.Row) (*User, error) {
user := User{} user := User{}
if err := row.Scan(&user.UserID, &user.Username, &user.Password, &user.RootPath, &user.Admin); err != nil { if err := row.Scan(&user.UserID, &user.Username, &user.Password, &user.RootPath, &user.Admin); err != nil {
if err == sql.ErrNoRows { return nil, err
return nil, ErrorInvalidUserCredentials
} else {
return nil, err
}
} }
return &user, nil return &user, nil
@ -64,7 +60,11 @@ func AuthorizeUser(database *sql.DB, username string, password string) (*User, e
user, err := NewUserFromRow(row) user, err := NewUserFromRow(row)
if err != nil { if err != nil {
return nil, err if err == sql.ErrNoRows {
return nil, ErrorInvalidUserCredentials
} else {
return nil, err
}
} }
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil { if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
@ -107,7 +107,7 @@ func (user *User) GenerateAccessToken(database *sql.DB) (*AccessToken, error) {
if _, err := rand.Read(bytes); err != nil { if _, err := rand.Read(bytes); err != nil {
return nil, errors.New(fmt.Sprintf("Could not generate token: %s\n", err.Error())) return nil, errors.New(fmt.Sprintf("Could not generate token: %s\n", err.Error()))
} }
const CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" const CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
for i, b := range bytes { for i, b := range bytes {
bytes[i] = CHARACTERS[b%byte(len(CHARACTERS))] bytes[i] = CHARACTERS[b%byte(len(CHARACTERS))]
} }

View File

@ -89,8 +89,32 @@ type Photo {
thumbnail: PhotoURL thumbnail: PhotoURL
"The album that holds the photo" "The album that holds the photo"
album: Album! album: Album!
# exif: PhotoEXIF exif: PhotoEXIF
# shares: [ShareToken] # shares: [ShareToken]
# downloads: [PhotoDownload] # downloads: [PhotoDownload]
} }
"EXIF metadata from the camera"
type PhotoEXIF {
photo: Photo
"The model name of the camera"
camera: String
"The maker of the camera"
maker: String
"The name of the lens"
lens: String
dateShot: Time
"The formatted filesize of the image"
fileSize: String
"The exposure time of the image"
exposure: String
"The aperature stops of the image"
aperture: Float
"The ISO setting of the image"
iso: Int
"The focal length of the lens, when the image was taken"
focalLength: String
"A formatted description of the flash settings, when the image was taken"
flash: String
}

View File

@ -0,0 +1,15 @@
package scanner
import (
"database/sql"
"path"
)
func ProcessImage(tx *sql.Tx, photoPath string, albumId int) error {
photoName := path.Base(photoPath)
_, err := tx.Exec("INSERT IGNORE INTO photo (title, path, album_id) VALUES (?, ?, ?)", photoName, photoPath, albumId)
if err != nil {
return err
}
}

View File

@ -84,7 +84,11 @@ func scan(database *sql.DB, user *models.User) {
photoPath := path.Join(albumPath, item.Name()) photoPath := path.Join(albumPath, item.Name())
if !item.IsDir() && isPathImage(photoPath) { if !item.IsDir() && isPathImage(photoPath) {
tx.Exec("INSERT IGNORE INTO photo (title, path, original_url, thumbnail_url, album_id)") if err := ProcessImage(tx, photoPath, albumId); err != nil {
fmt.Printf("ERROR: Could not proccess image %s: %s", photoPath, err)
tx.Rollback()
return
}
} }
} }
@ -144,6 +148,7 @@ func directoryContainsPhotos(rootPath string) bool {
var supported_mimetypes = [...]string{ var supported_mimetypes = [...]string{
"image/jpeg", "image/jpeg",
"image/png", "image/png",
"image/tiff",
"image/x-canon-cr2", "image/x-canon-cr2",
"image/bmp", "image/bmp",
} }