2020-02-05 14:51:46 +01:00
package resolvers
import (
"context"
2020-02-24 23:56:28 +01:00
"database/sql"
2020-02-14 13:31:44 +01:00
"strings"
2020-02-05 14:51:46 +01:00
2020-07-10 18:52:18 +02:00
"github.com/pkg/errors"
2020-02-05 14:51:46 +01:00
api "github.com/viktorstrate/photoview/api/graphql"
"github.com/viktorstrate/photoview/api/graphql/auth"
"github.com/viktorstrate/photoview/api/graphql/models"
2020-02-14 13:31:44 +01:00
"github.com/viktorstrate/photoview/api/scanner"
2020-02-05 14:51:46 +01:00
)
2020-07-10 14:26:19 +02:00
func ( r * queryResolver ) MyMedia ( ctx context . Context , filter * models . Filter ) ( [ ] * models . Media , error ) {
2020-02-09 14:21:53 +01:00
user := auth . UserFromContext ( ctx )
if user == nil {
return nil , errors . New ( "unauthorized" )
}
2020-10-13 17:27:28 +02:00
filterSQL , err := filter . FormatSQL ( "media" )
2020-02-09 15:26:59 +01:00
if err != nil {
return nil , err
}
2020-02-27 16:26:53 +01:00
rows , err := r . Database . Query ( `
2020-07-10 14:26:19 +02:00
SELECT media . * FROM media , album
WHERE media . album_id = album . album_id AND album . owner_id = ?
AND media . media_id IN (
SELECT media_id FROM media_url WHERE media_url . media_id = media . media_id
2020-02-27 16:26:53 +01:00
)
` + filterSQL , user . UserID )
2020-02-09 14:21:53 +01:00
if err != nil {
return nil , err
}
2020-07-10 14:26:19 +02:00
return models . NewMediaFromRows ( rows )
2020-02-05 14:51:46 +01:00
}
2020-07-10 14:26:19 +02:00
func ( r * queryResolver ) Media ( ctx context . Context , id int ) ( * models . Media , error ) {
2020-02-05 14:51:46 +01:00
user := auth . UserFromContext ( ctx )
if user == nil {
return nil , auth . ErrUnauthorized
}
row := r . Database . QueryRow ( `
2020-07-10 14:26:19 +02:00
SELECT media . * FROM media
JOIN album ON media . album_id = album . album_id
WHERE media . media_id = ? AND album . owner_id = ?
AND media . media_id IN (
SELECT media_id FROM media_url WHERE media_url . media_id = media . media_id
2020-02-27 16:26:53 +01:00
)
2020-02-05 14:51:46 +01:00
` , id , user . UserID )
2020-07-10 14:26:19 +02:00
media , err := models . NewMediaFromRow ( row )
2020-02-05 14:51:46 +01:00
if err != nil {
2020-07-10 18:52:18 +02:00
return nil , errors . Wrap ( err , "could not get media by media_id and user_id from database" )
2020-02-05 14:51:46 +01:00
}
2020-07-10 14:26:19 +02:00
return media , nil
2020-02-05 14:51:46 +01:00
}
2020-09-27 20:52:09 +02:00
func ( r * queryResolver ) MediaList ( ctx context . Context , ids [ ] int ) ( [ ] * models . Media , error ) {
user := auth . UserFromContext ( ctx )
if user == nil {
return nil , auth . ErrUnauthorized
}
if len ( ids ) == 0 {
return nil , errors . New ( "no ids provided" )
}
mediaIDQuestions := strings . Repeat ( "?," , len ( ids ) ) [ : len ( ids ) * 2 - 1 ]
queryArgs := make ( [ ] interface { } , 0 )
for _ , id := range ids {
queryArgs = append ( queryArgs , id )
}
queryArgs = append ( queryArgs , user . UserID )
rows , err := r . Database . Query ( `
SELECT media . * FROM media
JOIN album ON media . album_id = album . album_id
WHERE media . media_id IN ( ` +mediaIDQuestions+ ` ) AND album . owner_id = ?
AND media . media_id IN (
SELECT media_id FROM media_url WHERE media_url . media_id = media . media_id
)
` , queryArgs ... )
if err != nil {
return nil , errors . Wrap ( err , "could not get media list by media_id and user_id from database" )
}
media , err := models . NewMediaFromRows ( rows )
if err != nil {
return nil , errors . Wrap ( err , "could not convert database rows to media" )
}
return media , nil
}
2020-07-10 14:26:19 +02:00
type mediaResolver struct {
2020-02-05 14:51:46 +01:00
* Resolver
}
2020-07-10 14:26:19 +02:00
func ( r * Resolver ) Media ( ) api . MediaResolver {
return & mediaResolver { r }
2020-02-05 14:51:46 +01:00
}
2020-07-10 14:26:19 +02:00
func ( r * mediaResolver ) Shares ( ctx context . Context , obj * models . Media ) ( [ ] * models . ShareToken , error ) {
rows , err := r . Database . Query ( "SELECT * FROM share_token WHERE media_id = ?" , obj . MediaID )
2020-02-11 15:36:12 +01:00
if err != nil {
2020-07-10 18:52:18 +02:00
return nil , errors . Wrapf ( err , "get shares for media (%s)" , obj . Path )
2020-02-11 15:36:12 +01:00
}
return models . NewShareTokensFromRows ( rows )
2020-02-10 12:05:58 +01:00
}
2020-07-10 14:26:19 +02:00
func ( r * mediaResolver ) Downloads ( ctx context . Context , obj * models . Media ) ( [ ] * models . MediaDownload , error ) {
2020-02-21 22:42:39 +01:00
2020-07-10 14:26:19 +02:00
rows , err := r . Database . Query ( "SELECT * FROM media_url WHERE media_id = ?" , obj . MediaID )
2020-02-21 22:42:39 +01:00
if err != nil {
2020-07-10 18:52:18 +02:00
return nil , errors . Wrapf ( err , "get downloads for media (%s)" , obj . Path )
2020-02-21 22:42:39 +01:00
}
2020-07-10 14:26:19 +02:00
mediaUrls , err := models . NewMediaURLFromRows ( rows )
2020-02-21 22:42:39 +01:00
if err != nil {
return nil , err
}
2020-07-10 14:26:19 +02:00
downloads := make ( [ ] * models . MediaDownload , 0 )
2020-02-21 22:42:39 +01:00
2020-07-10 14:26:19 +02:00
for _ , url := range mediaUrls {
2020-02-21 22:42:39 +01:00
var title string
switch {
2020-07-10 12:58:11 +02:00
case url . Purpose == models . MediaOriginal :
2020-02-21 22:42:39 +01:00
title = "Original"
case url . Purpose == models . PhotoThumbnail :
title = "Small"
case url . Purpose == models . PhotoHighRes :
title = "Large"
2020-07-11 16:42:27 +02:00
case url . Purpose == models . VideoThumbnail :
title = "Video thumbnail"
case url . Purpose == models . VideoWeb :
title = "Web optimized video"
2020-02-21 22:42:39 +01:00
}
2020-07-10 14:26:19 +02:00
downloads = append ( downloads , & models . MediaDownload {
2020-08-11 22:34:42 +02:00
Title : title ,
MediaURL : url ,
2020-02-21 22:42:39 +01:00
} )
}
2020-02-10 12:05:58 +01:00
return downloads , nil
2020-02-09 12:53:21 +01:00
}
2020-07-10 14:26:19 +02:00
func ( r * mediaResolver ) HighRes ( ctx context . Context , obj * models . Media ) ( * models . MediaURL , error ) {
2020-02-14 13:31:44 +01:00
// Try high res first, then
web_types_questions := strings . Repeat ( "?," , len ( scanner . WebMimetypes ) ) [ : len ( scanner . WebMimetypes ) * 2 - 1 ]
args := make ( [ ] interface { } , 0 )
2020-07-10 14:26:19 +02:00
args = append ( args , obj . MediaID , models . PhotoHighRes , models . MediaOriginal )
2020-02-14 13:31:44 +01:00
for _ , webtype := range scanner . WebMimetypes {
args = append ( args , webtype )
}
row := r . Database . QueryRow ( `
2020-07-10 14:26:19 +02:00
SELECT * FROM media_url WHERE media_id = ? AND
2020-02-14 13:31:44 +01:00
(
purpose = ? OR ( purpose = ? AND content_type IN ( ` +web_types_questions+ ` ) )
) LIMIT 1
` , args ... )
2020-02-05 14:51:46 +01:00
2020-07-10 14:26:19 +02:00
url , err := models . NewMediaURLFromRow ( row )
2020-02-09 14:21:53 +01:00
if err != nil {
2020-07-11 14:21:10 +02:00
if err == sql . ErrNoRows {
return nil , nil
} else {
return nil , errors . Wrapf ( err , "could not query high-res (%s)" , obj . Path )
}
2020-02-09 14:21:53 +01:00
}
2020-02-05 14:51:46 +01:00
2020-02-09 14:21:53 +01:00
return url , nil
2020-02-05 14:51:46 +01:00
}
2020-07-10 14:26:19 +02:00
func ( r * mediaResolver ) Thumbnail ( ctx context . Context , obj * models . Media ) ( * models . MediaURL , error ) {
2020-07-11 14:21:10 +02:00
row := r . Database . QueryRow ( "SELECT * FROM media_url WHERE media_id = ? AND (purpose = ? OR purpose = ?)" , obj . MediaID , models . PhotoThumbnail , models . VideoThumbnail )
2020-02-05 14:51:46 +01:00
2020-07-10 14:26:19 +02:00
url , err := models . NewMediaURLFromRow ( row )
2020-02-09 14:21:53 +01:00
if err != nil {
2020-07-10 18:52:18 +02:00
return nil , errors . Wrapf ( err , "could not query thumbnail (%s)" , obj . Path )
2020-02-09 14:21:53 +01:00
}
2020-02-05 14:51:46 +01:00
2020-02-09 14:21:53 +01:00
return url , nil
2020-02-05 14:51:46 +01:00
}
2020-07-11 15:57:58 +02:00
func ( r * mediaResolver ) VideoWeb ( ctx context . Context , obj * models . Media ) ( * models . MediaURL , error ) {
row := r . Database . QueryRow ( "SELECT * FROM media_url WHERE media_id = ? AND (purpose = ?)" , obj . MediaID , models . VideoWeb )
url , err := models . NewMediaURLFromRow ( row )
if err != nil {
2020-07-11 16:42:27 +02:00
if err == sql . ErrNoRows {
return nil , nil
} else {
return nil , errors . Wrapf ( err , "could not query video web-format url (%s)" , obj . Path )
}
2020-07-11 15:57:58 +02:00
}
return url , nil
}
2020-07-10 14:26:19 +02:00
func ( r * mediaResolver ) Album ( ctx context . Context , obj * models . Media ) ( * models . Album , error ) {
row := r . Database . QueryRow ( "SELECT album.* from media JOIN album ON media.album_id = album.album_id WHERE media_id = ?" , obj . MediaID )
2020-03-05 20:34:19 +01:00
return models . NewAlbumFromRow ( row )
2020-02-05 14:51:46 +01:00
}
2020-07-10 14:26:19 +02:00
func ( r * mediaResolver ) Exif ( ctx context . Context , obj * models . Media ) ( * models . MediaEXIF , error ) {
row := r . Database . QueryRow ( "SELECT media_exif.* FROM media NATURAL JOIN media_exif WHERE media.media_id = ?" , obj . MediaID )
2020-02-24 23:56:28 +01:00
2020-07-10 14:26:19 +02:00
exif , err := models . NewMediaExifFromRow ( row )
2020-02-24 23:56:28 +01:00
if err != nil {
if err == sql . ErrNoRows {
return nil , nil
} else {
2020-07-10 18:52:18 +02:00
return nil , errors . Wrapf ( err , "could not get exif of media from database" )
2020-02-24 23:56:28 +01:00
}
}
return exif , nil
2020-02-05 14:51:46 +01:00
}
2020-06-17 18:00:58 +02:00
2020-07-12 14:17:49 +02:00
func ( r * mediaResolver ) VideoMetadata ( ctx context . Context , obj * models . Media ) ( * models . VideoMetadata , error ) {
row := r . Database . QueryRow ( "SELECT video_metadata.* FROM media JOIN video_metadata ON media.video_metadata_id = video_metadata.metadata_id WHERE media.media_id = ?" , obj . MediaID )
metadata , err := models . NewVideoMetadataFromRow ( row )
if err != nil {
if err == sql . ErrNoRows {
return nil , nil
} else {
return nil , errors . Wrapf ( err , "could not get video metadata of media from database" )
}
}
return metadata , nil
}
2020-07-10 14:26:19 +02:00
func ( r * mutationResolver ) FavoriteMedia ( ctx context . Context , mediaID int , favorite bool ) ( * models . Media , error ) {
2020-06-17 18:00:58 +02:00
user := auth . UserFromContext ( ctx )
2020-07-10 14:26:19 +02:00
row := r . Database . QueryRow ( "SELECT media.* FROM media JOIN album ON media.album_id = album.album_id WHERE media.media_id = ? AND album.owner_id = ?" , mediaID , user . UserID )
2020-06-17 18:00:58 +02:00
2020-07-10 14:26:19 +02:00
media , err := models . NewMediaFromRow ( row )
2020-06-17 18:00:58 +02:00
if err != nil {
return nil , err
}
2020-07-10 14:26:19 +02:00
_ , err = r . Database . Exec ( "UPDATE media SET favorite = ? WHERE media_id = ?" , favorite , media . MediaID )
2020-06-19 15:34:29 +02:00
if err != nil {
2020-07-10 18:52:18 +02:00
return nil , errors . Wrap ( err , "failed to update media favorite on database" )
2020-06-19 15:34:29 +02:00
}
2020-07-10 14:26:19 +02:00
media . Favorite = favorite
2020-06-17 18:00:58 +02:00
2020-07-10 14:26:19 +02:00
return media , nil
2020-06-17 18:00:58 +02:00
}