2020-01-05 14:18:40 +01:00
package query
2019-12-11 07:37:39 +01:00
import (
2020-05-26 19:27:29 +02:00
"time"
2020-01-29 16:49:42 +01:00
"github.com/jinzhu/gorm"
2019-12-11 16:55:18 +01:00
"github.com/photoprism/photoprism/internal/entity"
2019-12-11 07:37:39 +01:00
)
2020-03-28 15:29:17 +01:00
// PhotoByID returns a Photo based on the ID.
2020-05-08 15:41:01 +02:00
func PhotoByID ( photoID uint64 ) ( photo entity . Photo , err error ) {
if err := UnscopedDb ( ) . Where ( "id = ?" , photoID ) .
2020-05-26 19:27:29 +02:00
Preload ( "Labels" , func ( db * gorm . DB ) * gorm . DB {
return db . Order ( "photos_labels.uncertainty ASC, photos_labels.label_id DESC" )
} ) .
Preload ( "Labels.Label" ) .
2020-05-18 22:18:58 +02:00
Preload ( "Camera" ) .
Preload ( "Lens" ) .
Preload ( "Details" ) .
2020-05-27 13:40:21 +02:00
Preload ( "Place" ) .
2020-07-12 08:27:05 +02:00
Preload ( "Cell" ) .
Preload ( "Cell.Place" ) .
2020-04-16 20:57:00 +02:00
First ( & photo ) . Error ; err != nil {
2019-12-11 07:37:39 +01:00
return photo , err
}
return photo , nil
}
2020-05-23 20:58:58 +02:00
// PhotoByUID returns a Photo based on the UID.
func PhotoByUID ( photoUID string ) ( photo entity . Photo , err error ) {
if err := UnscopedDb ( ) . Where ( "photo_uid = ?" , photoUID ) .
2020-05-26 19:27:29 +02:00
Preload ( "Labels" , func ( db * gorm . DB ) * gorm . DB {
return db . Order ( "photos_labels.uncertainty ASC, photos_labels.label_id DESC" )
} ) .
Preload ( "Labels.Label" ) .
2020-05-18 22:18:58 +02:00
Preload ( "Camera" ) .
Preload ( "Lens" ) .
Preload ( "Details" ) .
2020-05-27 13:40:21 +02:00
Preload ( "Place" ) .
2020-07-12 08:27:05 +02:00
Preload ( "Cell" ) .
Preload ( "Cell.Place" ) .
2020-04-16 20:57:00 +02:00
First ( & photo ) . Error ; err != nil {
2019-12-11 07:37:39 +01:00
return photo , err
}
return photo , nil
}
2019-12-11 19:11:44 +01:00
2020-05-26 19:27:29 +02:00
// PhotoPreloadByUID returns a Photo based on the UID with all dependencies preloaded.
func PhotoPreloadByUID ( photoUID string ) ( photo entity . Photo , err error ) {
2020-05-23 20:58:58 +02:00
if err := UnscopedDb ( ) . Where ( "photo_uid = ?" , photoUID ) .
2020-01-29 16:49:42 +01:00
Preload ( "Labels" , func ( db * gorm . DB ) * gorm . DB {
2020-04-19 01:13:55 +02:00
return db . Order ( "photos_labels.uncertainty ASC, photos_labels.label_id DESC" )
2020-01-29 16:49:42 +01:00
} ) .
2020-01-29 15:28:20 +01:00
Preload ( "Labels.Label" ) .
Preload ( "Camera" ) .
Preload ( "Lens" ) .
2020-05-26 19:27:29 +02:00
Preload ( "Details" ) .
2020-05-27 13:40:21 +02:00
Preload ( "Place" ) .
2020-07-12 08:27:05 +02:00
Preload ( "Cell" ) .
Preload ( "Cell.Place" ) .
2020-01-29 15:28:20 +01:00
First ( & photo ) . Error ; err != nil {
2019-12-11 19:11:44 +01:00
return photo , err
}
2020-04-30 20:07:03 +02:00
photo . PreloadMany ( )
2019-12-11 19:11:44 +01:00
return photo , nil
}
2020-05-07 19:42:04 +02:00
2020-05-26 19:27:29 +02:00
// PhotosMissing returns photo entities without existing files.
2020-06-01 09:45:24 +02:00
func PhotosMissing ( limit int , offset int ) ( entities entity . Photos , err error ) {
2020-05-08 15:41:01 +02:00
err = Db ( ) .
2020-05-07 20:33:11 +02:00
Select ( "photos.*" ) .
Joins ( "JOIN files a ON photos.id = a.photo_id " ) .
2020-11-21 23:28:03 +01:00
Joins ( "LEFT JOIN files b ON a.photo_id = b.photo_id AND a.id != b.id AND b.file_missing = 0 AND b.file_root = '/'" ) .
2020-05-07 20:33:11 +02:00
Where ( "a.file_missing = 1 AND b.id IS NULL" ) .
2020-05-21 10:03:56 +02:00
Where ( "photos.photo_type <> ?" , entity . TypeText ) .
2020-05-07 20:33:11 +02:00
Group ( "photos.id" ) .
Limit ( limit ) . Offset ( offset ) . Find ( & entities ) . Error
2020-05-07 19:42:04 +02:00
return entities , err
}
2020-05-08 12:01:22 +02:00
2020-05-26 19:27:29 +02:00
// ResetPhotoQuality resets the quality of photos without primary file to -1.
func ResetPhotoQuality ( ) error {
2020-12-09 13:08:55 +01:00
if err := Db ( ) . Table ( "photos" ) .
Where ( "id IN (SELECT photos.id FROM photos LEFT JOIN files ON photos.id = files.photo_id AND files.file_primary = 1 WHERE files.id IS NULL GROUP BY photos.id)" ) .
Where ( "id IN (SELECT id FROM (SELECT photos.id FROM photos LEFT JOIN files ON photos.id = files.photo_id AND files.file_primary = 1 WHERE files.id IS NULL GROUP BY photos.id) AS tmp)" ) .
Update ( "photo_quality" , - 1 ) . Error ; err == nil {
return nil
}
// MySQL fallback, see https://github.com/photoprism/photoprism/issues/599
2020-05-08 15:41:01 +02:00
return Db ( ) . Table ( "photos" ) .
2020-11-15 12:15:14 +01:00
Where ( "id IN (SELECT id FROM (SELECT photos.id FROM photos LEFT JOIN files ON photos.id = files.photo_id AND files.file_primary = 1 WHERE files.id IS NULL GROUP BY photos.id) AS tmp)" ) .
2020-05-08 12:01:22 +02:00
Update ( "photo_quality" , - 1 ) . Error
}
2020-05-26 19:27:29 +02:00
2020-06-24 08:34:23 +02:00
// PhotosCheck returns photos selected for maintenance.
2020-12-11 22:09:11 +01:00
func PhotosCheck ( limit , offset int , delay time . Duration ) ( entities entity . Photos , err error ) {
2020-05-26 19:27:29 +02:00
err = Db ( ) .
Preload ( "Labels" , func ( db * gorm . DB ) * gorm . DB {
return db . Order ( "photos_labels.uncertainty ASC, photos_labels.label_id DESC" )
} ) .
Preload ( "Labels.Label" ) .
Preload ( "Camera" ) .
Preload ( "Lens" ) .
Preload ( "Details" ) .
2020-05-27 13:40:21 +02:00
Preload ( "Place" ) .
2020-07-12 08:27:05 +02:00
Preload ( "Cell" ) .
Preload ( "Cell.Place" ) .
2020-06-24 08:34:23 +02:00
Where ( "checked_at IS NULL OR checked_at < ?" , time . Now ( ) . Add ( - 1 * time . Hour * 24 * 3 ) ) .
2020-12-11 22:09:11 +01:00
Where ( "updated_at < ? OR (cell_id = 'zz' AND photo_lat <> 0)" , time . Now ( ) . Add ( - 1 * delay ) ) .
2020-12-09 21:44:04 +01:00
Order ( "photos.ID ASC" ) . Limit ( limit ) . Offset ( offset ) . Find ( & entities ) . Error
2020-05-26 19:27:29 +02:00
return entities , err
2020-12-09 21:49:41 +01:00
}
2021-01-24 17:46:18 +01:00
2021-02-06 16:30:30 +01:00
// OrphanPhotos finds orphan index entries that may be removed.
func OrphanPhotos ( ) ( photos entity . Photos , err error ) {
2021-01-24 17:46:18 +01:00
err = UnscopedDb ( ) .
Raw ( ` SELECT * FROM photos WHERE
deleted_at IS NOT NULL
AND photo_quality = - 1
AND id NOT IN ( SELECT photo_id FROM files WHERE files . deleted_at IS NULL ) ` ) .
Find ( & photos ) . Error
return photos , err
}
2021-01-24 20:40:40 +01:00
// FixPrimaries tries to set a primary file for photos that have none.
func FixPrimaries ( ) error {
var photos entity . Photos
if err := UnscopedDb ( ) .
Raw ( ` SELECT * FROM photos WHERE
deleted_at IS NULL
AND id NOT IN ( SELECT photo_id FROM files WHERE file_primary = true ) ` ) .
Find ( & photos ) . Error ; err != nil {
return err
}
for _ , p := range photos {
log . Debugf ( "photo: finding new primary for %s" , p . PhotoUID )
if err := p . SetPrimary ( "" ) ; err != nil {
2021-02-08 07:14:55 +01:00
log . Infof ( "photo: %s" , err )
2021-01-24 20:40:40 +01:00
}
}
return nil
}