diff --git a/Dockerfile b/Dockerfile index d38e4582..ee3b5603 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,7 @@ ENV REACT_APP_BUILD_COMMIT_SHA=${COMMIT_SHA:-} WORKDIR /app/ui -COPY ui/package.json ui/package-lock.json /app/ui +COPY ui/package.json ui/package-lock.json /app/ui/ RUN npm ci COPY ui/ /app/ui @@ -33,7 +33,7 @@ RUN if [ "${BUILD_DATE}" = "undefined" ]; then \ export BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ'); \ export REACT_APP_BUILD_DATE=${BUILD_DATE}; \ fi; \ - npm run build -- --base=$UI_PUBLIC_URL + npm run build -- --base="${UI_PUBLIC_URL}" ### Build API ### FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.23-bookworm AS api diff --git a/api/database/database.go b/api/database/database.go index f3ab5804..fb452f8c 100644 --- a/api/database/database.go +++ b/api/database/database.go @@ -191,7 +191,7 @@ func MigrateDatabase(db *gorm.DB) error { // v2.3.0 - Changed type of MediaEXIF.Exposure and MediaEXIF.Flash // from string values to decimal and int respectively - if err := migrate_exif_fields(db); err != nil { + if err := migrateExifFields(db); err != nil { log.Printf("Failed to run exif fields migration: %v\n", err) } @@ -206,20 +206,20 @@ func MigrateDatabase(db *gorm.DB) error { func ClearDatabase(db *gorm.DB) error { err := db.Transaction(func(tx *gorm.DB) error { - db_driver := drivers.DatabaseDriverFromEnv() + dbDriver := drivers.DatabaseDriverFromEnv() - if db_driver == drivers.MYSQL { + if dbDriver == drivers.MYSQL { if err := tx.Exec("SET FOREIGN_KEY_CHECKS = 0;").Error; err != nil { return err } } - dry_run := tx.Session(&gorm.Session{DryRun: true}) + dryRun := tx.Session(&gorm.Session{DryRun: true}) for _, model := range database_models { // get table name of model structure - table := dry_run.Find(model).Statement.Table + table := dryRun.Find(model).Statement.Table - switch db_driver { + switch dbDriver { case drivers.POSTGRES: if err := tx.Exec(fmt.Sprintf("TRUNCATE TABLE %s CASCADE", table)).Error; err != nil { return err @@ -236,7 +236,7 @@ func ClearDatabase(db *gorm.DB) error { } - if db_driver == drivers.MYSQL { + if dbDriver == drivers.MYSQL { if err := tx.Exec("SET FOREIGN_KEY_CHECKS = 1;").Error; err != nil { return err } diff --git a/api/database/migration_exif.go b/api/database/migration_exif.go index 7b0aac9d..d6f8a40a 100644 --- a/api/database/migration_exif.go +++ b/api/database/migration_exif.go @@ -12,7 +12,7 @@ import ( ) // Migrate MediaExif fields "exposure" and "flash" from strings to integers -func migrate_exif_fields(db *gorm.DB) error { +func migrateExifFields(db *gorm.DB) error { mediaExifColumns, err := db.Migrator().ColumnTypes(&models.MediaEXIF{}) if err != nil { return err @@ -26,7 +26,7 @@ func migrate_exif_fields(db *gorm.DB) error { // correct type, do nothing default: // do migration - if err := migrate_exif_fields_exposure(db); err != nil { + if err := migrateExifFieldsExposure(db); err != nil { return err } } @@ -38,7 +38,7 @@ func migrate_exif_fields(db *gorm.DB) error { // correct type, do nothing default: // do migration - if err := migrate_exif_fields_flash(db); err != nil { + if err := migrateExifFieldsFlash(db); err != nil { return err } } @@ -59,7 +59,7 @@ func migrate_exif_fields(db *gorm.DB) error { return nil } -func migrate_exif_fields_exposure(db *gorm.DB) error { +func migrateExifFieldsExposure(db *gorm.DB) error { log.Println("Migrating `media_exif.exposure` from string to double") err := db.Transaction(func(tx *gorm.DB) error { @@ -113,17 +113,17 @@ func migrate_exif_fields_exposure(db *gorm.DB) error { return nil } -func migrate_exif_fields_flash(db *gorm.DB) error { +func migrateExifFieldsFlash(db *gorm.DB) error { log.Println("Migrating `media_exif.flash` from string to int") err := db.Transaction(func(tx *gorm.DB) error { - var data_type string - if err := tx.Raw("SELECT data_type FROM information_schema.columns WHERE table_name = 'media_exif' AND column_name = 'flash';").Find(&data_type).Error; err != nil { + var dataType string + if err := tx.Raw("SELECT data_type FROM information_schema.columns WHERE table_name = 'media_exif' AND column_name = 'flash';").Find(&dataType).Error; err != nil { return errors.Wrapf(err, "read data_type of column media_exif.flash") } - if data_type == "bigint" { + if dataType == "bigint" { return nil } diff --git a/api/graphql/models/actions/album_actions.go b/api/graphql/models/actions/album_actions.go index c8f87edf..143dad38 100644 --- a/api/graphql/models/actions/album_actions.go +++ b/api/graphql/models/actions/album_actions.go @@ -90,7 +90,7 @@ func Album(db *gorm.DB, user *models.User, id int) (*models.Album, error) { } func AlbumPath(db *gorm.DB, user *models.User, album *models.Album) ([]*models.Album, error) { - var album_path []*models.Album + var albumPath []*models.Album err := db.Raw(` WITH recursive path_albums AS ( @@ -99,11 +99,11 @@ func AlbumPath(db *gorm.DB, user *models.User, album *models.Album) ([]*models.A SELECT parent.* FROM path_albums child JOIN albums parent ON parent.id = child.parent_album_id ) SELECT * FROM path_albums WHERE id != ? - `, album.ID, album.ID).Scan(&album_path).Error + `, album.ID, album.ID).Scan(&albumPath).Error // Make sure to only return albums this user owns - for i := len(album_path) - 1; i >= 0; i-- { - album := album_path[i] + for i := len(albumPath) - 1; i >= 0; i-- { + album := albumPath[i] owns, err := user.OwnsAlbum(db, album) if err != nil { @@ -111,7 +111,7 @@ func AlbumPath(db *gorm.DB, user *models.User, album *models.Album) ([]*models.A } if !owns { - album_path = album_path[i+1:] + albumPath = albumPath[i+1:] break } @@ -121,7 +121,7 @@ func AlbumPath(db *gorm.DB, user *models.User, album *models.Album) ([]*models.A return nil, err } - return album_path, nil + return albumPath, nil } func SetAlbumCover(db *gorm.DB, user *models.User, mediaID int) (*models.Album, error) { diff --git a/api/graphql/models/actions/album_actions_test.go b/api/graphql/models/actions/album_actions_test.go index 3122dfe5..af91543d 100644 --- a/api/graphql/models/actions/album_actions_test.go +++ b/api/graphql/models/actions/album_actions_test.go @@ -140,8 +140,8 @@ func TestAlbumCover(t *testing.T) { return } - user_pass := "password" - regularUser, err := models.RegisterUser(db, "user1", &user_pass, false) + userPass := "password" + regularUser, err := models.RegisterUser(db, "user1", &userPass, false) if !assert.NoError(t, err) { return } diff --git a/api/graphql/models/actions/search_actions.go b/api/graphql/models/actions/search_actions.go index e1f81244..c39e5032 100644 --- a/api/graphql/models/actions/search_actions.go +++ b/api/graphql/models/actions/search_actions.go @@ -10,16 +10,16 @@ import ( "gorm.io/gorm/clause" ) -func Search(db *gorm.DB, query string, userID int, _limitMedia *int, _limitAlbums *int) (*models.SearchResult, error) { - limitMedia := 10 - limitAlbums := 10 +func Search(db *gorm.DB, query string, userID int, limitMedia *int, limitAlbums *int) (*models.SearchResult, error) { + limitMediaInternal := 10 + limitAlbumsInternal := 10 - if _limitMedia != nil { - limitMedia = *_limitMedia + if limitMedia != nil { + limitMediaInternal = *limitMedia } - if _limitAlbums != nil { - limitAlbums = *_limitAlbums + if limitAlbums != nil { + limitAlbumsInternal = *limitAlbums } wildQuery := "%" + strings.ToLower(query) + "%" @@ -42,7 +42,7 @@ func Search(db *gorm.DB, query string, userID int, _limitMedia *int, _limitAlbum Vars: []interface{}{wildQuery, wildQuery}, WithoutParentheses: true}, }). - Limit(limitMedia).Find(&media).Error + Limit(limitMediaInternal).Find(&media).Error if err != nil { return nil, errors.Wrapf(err, "searching media") @@ -59,7 +59,7 @@ func Search(db *gorm.DB, query string, userID int, _limitMedia *int, _limitAlbum Vars: []interface{}{wildQuery, wildQuery}, WithoutParentheses: true}, }). - Limit(limitAlbums). + Limit(limitAlbumsInternal). Find(&albums).Error if err != nil { diff --git a/api/graphql/models/actions/timeline_actions.go b/api/graphql/models/actions/timeline_actions.go index f0dc5e2f..b7efe5ba 100644 --- a/api/graphql/models/actions/timeline_actions.go +++ b/api/graphql/models/actions/timeline_actions.go @@ -9,6 +9,7 @@ import ( ) func MyTimeline(db *gorm.DB, user *models.User, paginate *models.Pagination, onlyFavorites *bool, fromDate *time.Time) ([]*models.Media, error) { + const albumsTitleASC = "albums.title ASC" query := db. Joins("JOIN albums ON media.album_id = albums.id"). @@ -20,19 +21,19 @@ func MyTimeline(db *gorm.DB, user *models.User, paginate *models.Pagination, onl Order("DATE_TRUNC('year', date_shot) DESC"). Order("DATE_TRUNC('month', date_shot) DESC"). Order("DATE_TRUNC('day', date_shot) DESC"). - Order("albums.title ASC"). + Order(albumsTitleASC). Order("media.date_shot DESC") case drivers.SQLITE: query = query. Order("strftime('%Y-%m-%d', media.date_shot) DESC"). // convert to YYYY-MM-DD - Order("albums.title ASC"). + Order(albumsTitleASC). Order("TIME(media.date_shot) DESC") default: query = query. Order("YEAR(media.date_shot) DESC"). Order("MONTH(media.date_shot) DESC"). Order("DAY(media.date_shot) DESC"). - Order("albums.title ASC"). + Order(albumsTitleASC). Order("TIME(media.date_shot) DESC") } diff --git a/api/graphql/models/album_test.go b/api/graphql/models/album_test.go index 21be0dfe..c4c25b38 100644 --- a/api/graphql/models/album_test.go +++ b/api/graphql/models/album_test.go @@ -9,11 +9,14 @@ import ( ) func TestAlbumGetChildrenAndParents(t *testing.T) { + const photosPath = "/photos" + const photosChild1Path = "/photos/child1" + const photosChild1SubchildPath = "/photos/child1/subchild" db := test_utils.DatabaseTest(t) rootAlbum := models.Album{ Title: "root", - Path: "/photos", + Path: photosPath, } if !assert.NoError(t, db.Save(&rootAlbum).Error) { @@ -23,7 +26,7 @@ func TestAlbumGetChildrenAndParents(t *testing.T) { children := []models.Album{ { Title: "child1", - Path: "/photos/child1", + Path: photosChild1Path, ParentAlbumID: &rootAlbum.ID, }, { @@ -41,47 +44,47 @@ func TestAlbumGetChildrenAndParents(t *testing.T) { return } - sub_child := models.Album{ + subChild := models.Album{ Title: "subchild", - Path: "/photos/child1/subchild", + Path: photosChild1SubchildPath, ParentAlbumID: &children[0].ID, } - if !assert.NoError(t, db.Save(&sub_child).Error) { + if !assert.NoError(t, db.Save(&subChild).Error) { return } - verifyResult := func(t *testing.T, expected_albums []*models.Album, result []*models.Album) { - assert.Equal(t, len(expected_albums), len(result)) + verifyResult := func(t *testing.T, expectedAlbums []*models.Album, result []*models.Album) { + assert.Equal(t, len(expectedAlbums), len(result)) - for _, expected := range expected_albums { - found_expected := false + for _, expected := range expectedAlbums { + foundExpected := false for _, item := range result { if item.Title == expected.Title && item.Path == expected.Path { - found_expected = true + foundExpected = true break } } - if !found_expected { + if !foundExpected { assert.Failf(t, "albums did not match", "expected to find item: %v", expected) } } } t.Run("Album get children", func(t *testing.T) { - root_children, err := rootAlbum.GetChildren(db, nil) + rootChildren, err := rootAlbum.GetChildren(db, nil) if !assert.NoError(t, err) { return } - expected_children := []*models.Album{ + expectedChildren := []*models.Album{ { Title: "root", - Path: "/photos", + Path: photosPath, }, { Title: "child1", - Path: "/photos/child1", + Path: photosChild1Path, }, { Title: "child2", @@ -89,35 +92,35 @@ func TestAlbumGetChildrenAndParents(t *testing.T) { }, { Title: "subchild", - Path: "/photos/child1/subchild", + Path: photosChild1SubchildPath, }, } - verifyResult(t, expected_children, root_children) + verifyResult(t, expectedChildren, rootChildren) }) t.Run("Album get parents", func(t *testing.T) { - parents, err := sub_child.GetParents(db, nil) + parents, err := subChild.GetParents(db, nil) if !assert.NoError(t, err) { return } - expected_parents := []*models.Album{ + expectedParents := []*models.Album{ { Title: "root", - Path: "/photos", + Path: photosPath, }, { Title: "child1", - Path: "/photos/child1", + Path: photosChild1Path, }, { Title: "subchild", - Path: "/photos/child1/subchild", + Path: photosChild1SubchildPath, }, } - verifyResult(t, expected_parents, parents) + verifyResult(t, expectedParents, parents) }) } diff --git a/api/graphql/models/face_detection.go b/api/graphql/models/face_detection.go index 32e98db3..833ac1f8 100644 --- a/api/graphql/models/face_detection.go +++ b/api/graphql/models/face_detection.go @@ -111,7 +111,7 @@ func (fr *FaceRectangle) Scan(value interface{}) error { slices := strings.Split(stringArray, ":") if len(slices) != 4 { - return fmt.Errorf("Invalid face rectangle format, expected 4 values, got %d", len(slices)) + return fmt.Errorf("invalid face rectangle format, expected 4 values, got %d", len(slices)) } var err error diff --git a/api/graphql/models/media_test.go b/api/graphql/models/media_test.go index 48a453df..65805069 100644 --- a/api/graphql/models/media_test.go +++ b/api/graphql/models/media_test.go @@ -8,6 +8,8 @@ import ( "github.com/stretchr/testify/assert" ) +const mimeJpeg = "image/jpeg" + func TestSanitizeMediaName(t *testing.T) { tests := [][2]string{ {"filename.png", "filename_png"}, @@ -53,7 +55,7 @@ func TestMediaURLCachePath(t *testing.T) { func TestMediaURLGetURL(t *testing.T) { photo := models.MediaURL{ MediaName: "photo.jpg", - ContentType: "image/jpeg", + ContentType: mimeJpeg, Purpose: models.PhotoHighRes, } @@ -76,12 +78,12 @@ func TestMediaGetThumbnail(t *testing.T) { MediaURL: []models.MediaURL{ { MediaName: "photo.jpg", - ContentType: "image/jpeg", + ContentType: mimeJpeg, Purpose: models.PhotoHighRes, }, { MediaName: "thumbnail.jpg", - ContentType: "image/jpeg", + ContentType: mimeJpeg, Purpose: models.PhotoThumbnail, }, { diff --git a/api/graphql/models/user.go b/api/graphql/models/user.go index 6b276214..19b85e39 100644 --- a/api/graphql/models/user.go +++ b/api/graphql/models/user.go @@ -54,16 +54,16 @@ func (u *UserPreferences) BeforeSave(tx *gorm.DB) error { } if u.Language != nil { - lang_str := string(*u.Language) - found_match := false + langStr := string(*u.Language) + foundMatch := false for _, lang := range AllLanguageTranslation { - if string(lang) == lang_str { - found_match = true + if string(lang) == langStr { + foundMatch = true break } } - if !found_match { + if !foundMatch { return errors.New("invalid language value") } } @@ -133,12 +133,12 @@ func (user *User) GenerateAccessToken(db *gorm.DB) (*AccessToken, error) { bytes[i] = CHARACTERS[b%byte(len(CHARACTERS))] } - token_value := string(bytes) + tokenValue := string(bytes) expire := time.Now().Add(14 * 24 * time.Hour) token := AccessToken{ UserID: user.ID, - Value: token_value, + Value: tokenValue, Expire: expire, } diff --git a/api/graphql/models/user_test.go b/api/graphql/models/user_test.go index 1daf38a0..5be9ead8 100644 --- a/api/graphql/models/user_test.go +++ b/api/graphql/models/user_test.go @@ -137,7 +137,7 @@ func TestUserOwnsAlbum(t *testing.T) { return } - sub_albums := []models.Album{ + subAlbums := []models.Album{ { Title: "subalbum1", Path: "/photos/album2/subalbum1", @@ -155,7 +155,7 @@ func TestUserOwnsAlbum(t *testing.T) { }, } - if !assert.NoError(t, db.Model(&user).Association("Albums").Append(&sub_albums)) { + if !assert.NoError(t, db.Model(&user).Association("Albums").Append(&subAlbums)) { return } @@ -165,22 +165,22 @@ func TestUserOwnsAlbum(t *testing.T) { assert.True(t, owns) } - for _, album := range sub_albums { + for _, album := range subAlbums { owns, err := user.OwnsAlbum(db, &album) assert.NoError(t, err) assert.True(t, owns) } - separate_album := models.Album{ + separateAlbum := models.Album{ Title: "separate_album", Path: "/my_media/album123", } - if !assert.NoError(t, db.Save(&separate_album).Error) { + if !assert.NoError(t, db.Save(&separateAlbum).Error) { return } - owns, err := user.OwnsAlbum(db, &separate_album) + owns, err := user.OwnsAlbum(db, &separateAlbum) assert.NoError(t, err) assert.False(t, owns) } diff --git a/api/graphql/resolvers/faces.go b/api/graphql/resolvers/faces.go index b6284e4c..857fa328 100644 --- a/api/graphql/resolvers/faces.go +++ b/api/graphql/resolvers/faces.go @@ -11,6 +11,12 @@ import ( "gorm.io/gorm" ) +const faceGroupIDisQuestion = "face_group_id = ?" +const mediaAlbumIDinQuestion = "media.album_id IN (?)" +const imageFacesIDinQuestion = "image_faces.id IN (?)" + +var ErrFaceDetectorNotInitialized = errors.New("face detector not initialized") + type imageFaceResolver struct { *Resolver } @@ -33,7 +39,7 @@ func (r imageFaceResolver) FaceGroup(ctx context.Context, obj *models.ImageFace) } if face_detection.GlobalFaceDetector == nil { - return nil, errors.New("face detector not initialized") + return nil, ErrFaceDetectorNotInitialized } var faceGroup models.FaceGroup @@ -62,7 +68,7 @@ func (r faceGroupResolver) ImageFaces(ctx context.Context, obj *models.FaceGroup } if face_detection.GlobalFaceDetector == nil { - return nil, errors.New("face detector not initialized") + return nil, ErrFaceDetectorNotInitialized } if err := user.FillAlbums(db); err != nil { @@ -76,7 +82,7 @@ func (r faceGroupResolver) ImageFaces(ctx context.Context, obj *models.FaceGroup query := db. Joins("Media"). - Where("face_group_id = ?", obj.ID). + Where(faceGroupIDisQuestion, obj.ID). Where("album_id IN (?)", userAlbumIDs) query = models.FormatSQL(query, nil, paginate) @@ -97,7 +103,7 @@ func (r faceGroupResolver) ImageFaceCount(ctx context.Context, obj *models.FaceG } if face_detection.GlobalFaceDetector == nil { - return -1, errors.New("face detector not initialized") + return -1, ErrFaceDetectorNotInitialized } if err := user.FillAlbums(db); err != nil { @@ -112,7 +118,7 @@ func (r faceGroupResolver) ImageFaceCount(ctx context.Context, obj *models.FaceG query := db. Model(&models.ImageFace{}). Joins("Media"). - Where("face_group_id = ?", obj.ID). + Where(faceGroupIDisQuestion, obj.ID). Where("album_id IN (?)", userAlbumIDs) var count int64 @@ -131,7 +137,7 @@ func (r *queryResolver) FaceGroup(ctx context.Context, id int) (*models.FaceGrou } if face_detection.GlobalFaceDetector == nil { - return nil, errors.New("face detector not initialized") + return nil, ErrFaceDetectorNotInitialized } if err := user.FillAlbums(db); err != nil { @@ -147,7 +153,7 @@ func (r *queryResolver) FaceGroup(ctx context.Context, id int) (*models.FaceGrou Joins("LEFT JOIN image_faces ON image_faces.face_group_id = face_groups.id"). Joins("LEFT JOIN media ON image_faces.media_id = media.id"). Where("face_groups.id = ?", id). - Where("media.album_id IN (?)", userAlbumIDs) + Where(mediaAlbumIDinQuestion, userAlbumIDs) var faceGroup models.FaceGroup if err := faceGroupQuery.Find(&faceGroup).Error; err != nil { @@ -165,7 +171,7 @@ func (r *queryResolver) MyFaceGroups(ctx context.Context, paginate *models.Pagin } if face_detection.GlobalFaceDetector == nil { - return nil, errors.New("face detector not initialized") + return nil, ErrFaceDetectorNotInitialized } if err := user.FillAlbums(db); err != nil { @@ -179,7 +185,7 @@ func (r *queryResolver) MyFaceGroups(ctx context.Context, paginate *models.Pagin faceGroupQuery := db. Joins("JOIN image_faces ON image_faces.face_group_id = face_groups.id"). - Where("image_faces.media_id IN (?)", db.Select("media.id").Table("media").Where("media.album_id IN (?)", userAlbumIDs)). + Where("image_faces.media_id IN (?)", db.Select("media.id").Table("media").Where(mediaAlbumIDinQuestion, userAlbumIDs)). Group("image_faces.face_group_id"). Group("face_groups.id"). Order("CASE WHEN label IS NULL THEN 1 ELSE 0 END"). @@ -203,7 +209,7 @@ func (r *mutationResolver) SetFaceGroupLabel(ctx context.Context, faceGroupID in } if face_detection.GlobalFaceDetector == nil { - return nil, errors.New("face detector not initialized") + return nil, ErrFaceDetectorNotInitialized } faceGroup, err := userOwnedFaceGroup(db, user, faceGroupID) @@ -226,7 +232,7 @@ func (r *mutationResolver) CombineFaceGroups(ctx context.Context, destinationFac } if face_detection.GlobalFaceDetector == nil { - return nil, errors.New("face detector not initialized") + return nil, ErrFaceDetectorNotInitialized } destinationFaceGroup, err := userOwnedFaceGroup(db, user, destinationFaceGroupID) @@ -240,7 +246,7 @@ func (r *mutationResolver) CombineFaceGroups(ctx context.Context, destinationFac } updateError := db.Transaction(func(tx *gorm.DB) error { - if err := tx.Model(&models.ImageFace{}).Where("face_group_id = ?", sourceFaceGroup.ID).Update("face_group_id", destinationFaceGroup.ID).Error; err != nil { + if err := tx.Model(&models.ImageFace{}).Where(faceGroupIDisQuestion, sourceFaceGroup.ID).Update("face_group_id", destinationFaceGroup.ID).Error; err != nil { return err } @@ -268,7 +274,7 @@ func (r *mutationResolver) MoveImageFaces(ctx context.Context, imageFaceIDs []in } if face_detection.GlobalFaceDetector == nil { - return nil, errors.New("face detector not initialized") + return nil, ErrFaceDetectorNotInitialized } userOwnedImageFaceIDs := make([]int, 0) @@ -294,7 +300,7 @@ func (r *mutationResolver) MoveImageFaces(ctx context.Context, imageFaceIDs []in var sourceFaceGroups []*models.FaceGroup if err := tx. Joins("LEFT JOIN image_faces ON image_faces.face_group_id = face_groups.id"). - Where("image_faces.id IN (?)", userOwnedImageFaceIDs). + Where(imageFacesIDinQuestion, userOwnedImageFaceIDs). Find(&sourceFaceGroups).Error; err != nil { return err } @@ -309,7 +315,7 @@ func (r *mutationResolver) MoveImageFaces(ctx context.Context, imageFaceIDs []in // delete face groups if they have become empty for _, faceGroup := range sourceFaceGroups { var count int64 - if err := tx.Model(&models.ImageFace{}).Where("face_group_id = ?", faceGroup.ID).Count(&count).Error; err != nil { + if err := tx.Model(&models.ImageFace{}).Where(faceGroupIDisQuestion, faceGroup.ID).Count(&count).Error; err != nil { return err } @@ -340,7 +346,7 @@ func (r *mutationResolver) RecognizeUnlabeledFaces(ctx context.Context) ([]*mode } if face_detection.GlobalFaceDetector == nil { - return nil, errors.New("face detector not initialized") + return nil, ErrFaceDetectorNotInitialized } var updatedImageFaces []*models.ImageFace @@ -367,7 +373,7 @@ func (r *mutationResolver) DetachImageFaces(ctx context.Context, imageFaceIDs [] } if face_detection.GlobalFaceDetector == nil { - return nil, errors.New("face detector not initialized") + return nil, ErrFaceDetectorNotInitialized } userOwnedImageFaceIDs := make([]int, 0) @@ -431,13 +437,13 @@ func userOwnedFaceGroup(db *gorm.DB, user *models.User, faceGroupID int) (*model Select("image_faces.id"). Table("image_faces"). Joins("JOIN media ON media.id = image_faces.media_id"). - Where("media.album_id IN (?)", userAlbumIDs) + Where(mediaAlbumIDinQuestion, userAlbumIDs) faceGroupQuery := db. Model(&models.FaceGroup{}). Joins("JOIN image_faces ON face_groups.id = image_faces.face_group_id"). Where("face_groups.id = ?", faceGroupID). - Where("image_faces.id IN (?)", imageFaceQuery) + Where(imageFacesIDinQuestion, imageFaceQuery) var faceGroup models.FaceGroup if err := faceGroupQuery.Find(&faceGroup).Error; err != nil { @@ -463,8 +469,8 @@ func getUserOwnedImageFaces(tx *gorm.DB, user *models.User, imageFaceIDs []int) var userOwnedImageFaces []*models.ImageFace if err := tx. Joins("JOIN media ON media.id = image_faces.media_id"). - Where("media.album_id IN (?)", userAlbumIDs). - Where("image_faces.id IN (?)", imageFaceIDs). + Where(mediaAlbumIDinQuestion, userAlbumIDs). + Where(imageFacesIDinQuestion, imageFaceIDs). Find(&userOwnedImageFaces).Error; err != nil { return nil, err } diff --git a/api/routes/authenticate_routes.go b/api/routes/authenticate_routes.go index 50a06acd..49ed8a37 100644 --- a/api/routes/authenticate_routes.go +++ b/api/routes/authenticate_routes.go @@ -11,18 +11,20 @@ import ( "gorm.io/gorm" ) +const internalServerError = "internal server error" + func authenticateMedia(media *models.Media, db *gorm.DB, r *http.Request) (success bool, responseMessage string, responseStatus int, errorMessage error) { user := auth.UserFromContext(r.Context()) if user != nil { var album models.Album if err := db.First(&album, media.AlbumID).Error; err != nil { - return false, "internal server error", http.StatusInternalServerError, err + return false, internalServerError, http.StatusInternalServerError, err } ownsAlbum, err := user.OwnsAlbum(db, &album) if err != nil { - return false, "internal server error", http.StatusInternalServerError, err + return false, internalServerError, http.StatusInternalServerError, err } if !ownsAlbum { @@ -44,7 +46,7 @@ func authenticateAlbum(album *models.Album, db *gorm.DB, r *http.Request) (succe if user != nil { ownsAlbum, err := user.OwnsAlbum(db, album) if err != nil { - return false, "internal server error", http.StatusInternalServerError, err + return false, internalServerError, http.StatusInternalServerError, err } if !ownsAlbum { @@ -70,7 +72,7 @@ func shareTokenFromRequest(db *gorm.DB, r *http.Request, mediaID *int, albumID * var shareToken models.ShareToken if err := db.Where("value = ?", token).First(&shareToken).Error; err != nil { - return false, "internal server error", http.StatusInternalServerError, err + return false, internalServerError, http.StatusInternalServerError, err } // Validate share token password, if set @@ -86,7 +88,7 @@ func shareTokenFromRequest(db *gorm.DB, r *http.Request, mediaID *int, albumID * if err == bcrypt.ErrMismatchedHashAndPassword { return false, "unauthorized", http.StatusForbidden, errors.New("incorrect password for share token") } else { - return false, "internal server error", http.StatusInternalServerError, err + return false, internalServerError, http.StatusInternalServerError, err } } } @@ -113,7 +115,7 @@ func shareTokenFromRequest(db *gorm.DB, r *http.Request, mediaID *int, albumID * `, *shareToken.AlbumID, albumID).Find(&count).Error if err != nil { - return false, "internal server error", http.StatusInternalServerError, err + return false, internalServerError, http.StatusInternalServerError, err } if count == 0 { diff --git a/api/routes/authenticate_routes_test.go b/api/routes/authenticate_routes_test.go index 9f67b0bf..e74bac35 100644 --- a/api/routes/authenticate_routes_test.go +++ b/api/routes/authenticate_routes_test.go @@ -16,6 +16,9 @@ import ( ) func TestAuthenticateRoute(t *testing.T) { + const imageData = "IMAGE DATA" + const albumData = "ALBUM DATA" + db := test_utils.DatabaseTest(t) user, err := models.RegisterUser(db, "username", nil, false) @@ -44,7 +47,7 @@ func TestAuthenticateRoute(t *testing.T) { t.Run("Authenticate Media", func(t *testing.T) { t.Run("Authorized request", func(t *testing.T) { - req := httptest.NewRequest("GET", "/photo/image.jpg", strings.NewReader("IMAGE DATA")) + req := httptest.NewRequest("GET", "/photo/image.jpg", strings.NewReader(imageData)) ctx := auth.AddUserToContext(req.Context(), user) req = req.WithContext(ctx) @@ -57,7 +60,7 @@ func TestAuthenticateRoute(t *testing.T) { }) t.Run("Request without access token", func(t *testing.T) { - req := httptest.NewRequest("GET", "/photo/image.jpg", strings.NewReader("IMAGE DATA")) + req := httptest.NewRequest("GET", "/photo/image.jpg", strings.NewReader(imageData)) success, responseMessage, responseStatus, err := authenticateMedia(&media, db, req) @@ -76,7 +79,7 @@ func TestAuthenticateRoute(t *testing.T) { t.Run("Request with share token", func(t *testing.T) { url := fmt.Sprintf("/photo/image.jpg?token=%s", shareToken.Value) - req := httptest.NewRequest("GET", url, strings.NewReader("IMAGE DATA")) + req := httptest.NewRequest("GET", url, strings.NewReader(imageData)) cookie := http.Cookie{ Name: fmt.Sprintf("share-token-pw-%s", shareToken.Value), @@ -95,7 +98,7 @@ func TestAuthenticateRoute(t *testing.T) { t.Run("Authenticate Album", func(t *testing.T) { t.Run("Authorized request", func(t *testing.T) { - req := httptest.NewRequest("GET", "/download/album/1", strings.NewReader("ALBUM DATA")) + req := httptest.NewRequest("GET", "/download/album/1", strings.NewReader(albumData)) ctx := auth.AddUserToContext(req.Context(), user) req = req.WithContext(ctx) @@ -108,7 +111,7 @@ func TestAuthenticateRoute(t *testing.T) { }) t.Run("Request without access token", func(t *testing.T) { - req := httptest.NewRequest("GET", "/download/album/1", strings.NewReader("ALBUM DATA")) + req := httptest.NewRequest("GET", "/download/album/1", strings.NewReader(albumData)) success, responseMessage, responseStatus, err := authenticateAlbum(&album, db, req) @@ -127,7 +130,7 @@ func TestAuthenticateRoute(t *testing.T) { t.Run("Request with share token", func(t *testing.T) { url := fmt.Sprintf("/download/album/1?token=%s", shareToken.Value) - req := httptest.NewRequest("GET", url, strings.NewReader("ALBUM DATA")) + req := httptest.NewRequest("GET", url, strings.NewReader(albumData)) cookie := http.Cookie{ Name: fmt.Sprintf("share-token-pw-%s", shareToken.Value), diff --git a/api/routes/downloads.go b/api/routes/downloads.go index bda34942..b4504ba5 100644 --- a/api/routes/downloads.go +++ b/api/routes/downloads.go @@ -47,7 +47,7 @@ func RegisterDownloadRoutes(db *gorm.DB, router *mux.Router) { var mediaURLs []*models.MediaURL if err := db.Joins("Media").Where(mediaWhereQuery, album.ID).Where("media_urls.purpose IN (?)", mediaPurposeList).Find(&mediaURLs).Error; err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) + w.Write([]byte(internalServerError)) return } @@ -67,7 +67,7 @@ func RegisterDownloadRoutes(db *gorm.DB, router *mux.Router) { if err != nil { log.Printf("ERROR: Failed to create a file in zip, when downloading album (%d): %v\n", album.ID, err) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) + w.Write([]byte(internalServerError)) return } @@ -75,7 +75,7 @@ func RegisterDownloadRoutes(db *gorm.DB, router *mux.Router) { if err != nil { log.Printf("ERROR: Failed to get mediaURL cache path, when downloading album (%d): %v\n", album.ID, err) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) + w.Write([]byte(internalServerError)) return } @@ -83,7 +83,7 @@ func RegisterDownloadRoutes(db *gorm.DB, router *mux.Router) { if err != nil { log.Printf("ERROR: Failed to open file to include in zip, when downloading album (%d): %v\n", album.ID, err) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) + w.Write([]byte(internalServerError)) return } @@ -91,14 +91,14 @@ func RegisterDownloadRoutes(db *gorm.DB, router *mux.Router) { if err != nil { log.Printf("ERROR: Failed to copy file data, when downloading album (%d): %v\n", album.ID, err) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) + w.Write([]byte(internalServerError)) return } if err := fileData.Close(); err != nil { log.Printf("ERROR: Failed to close file, when downloading album (%d): %v\n", album.ID, err) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) + w.Write([]byte(internalServerError)) return } } diff --git a/api/routes/photos.go b/api/routes/photos.go index b1b91e18..9235c7b7 100644 --- a/api/routes/photos.go +++ b/api/routes/photos.go @@ -40,7 +40,7 @@ func RegisterPhotoRoutes(db *gorm.DB, router *mux.Router) { if err != nil { log.Printf("ERROR: %s\n", err) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) + w.Write([]byte(internalServerError)) return } @@ -49,14 +49,14 @@ func RegisterPhotoRoutes(db *gorm.DB, router *mux.Router) { if err = scanner.ProcessSingleMedia(db, media); err != nil { log.Printf("ERROR: processing image not found in cache (%s): %s\n", cachedPath, err) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) + w.Write([]byte(internalServerError)) return } if _, err = os.Stat(cachedPath); err != nil { log.Printf("ERROR: after reprocessing image not found in cache (%s): %s\n", cachedPath, err) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) + w.Write([]byte(internalServerError)) return } } diff --git a/api/routes/videos.go b/api/routes/videos.go index 2717eee6..6048a89b 100644 --- a/api/routes/videos.go +++ b/api/routes/videos.go @@ -45,7 +45,7 @@ func RegisterVideoRoutes(db *gorm.DB, router *mux.Router) { } else { log.Printf("ERROR: Can not handle media_purpose for video: %s\n", mediaURL.Purpose) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) + w.Write([]byte(internalServerError)) return } @@ -54,14 +54,14 @@ func RegisterVideoRoutes(db *gorm.DB, router *mux.Router) { if err := scanner.ProcessSingleMedia(db, media); err != nil { log.Printf("ERROR: processing video not found in cache: %s\n", err) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) + w.Write([]byte(internalServerError)) return } if _, err := os.Stat(cachedPath); err != nil { log.Printf("ERROR: after reprocessing video not found in cache: %s\n", err) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) + w.Write([]byte(internalServerError)) return } } diff --git a/api/scanner/exif/exif_parser_external.go b/api/scanner/exif/exif_parser_external.go index 2eb905e8..4faeb862 100644 --- a/api/scanner/exif/exif_parser_external.go +++ b/api/scanner/exif/exif_parser_external.go @@ -63,7 +63,7 @@ func sanitizeEXIF(exif *models.MediaEXIF) { } } -func extractValidGpsData(fileInfo *exiftool.FileMetadata, media_path string) (*float64, *float64) { +func extractValidGpsData(fileInfo *exiftool.FileMetadata, mediaPath string) (*float64, *float64) { var GPSLat, GPSLong *float64 // GPS coordinates - longitude @@ -82,13 +82,13 @@ func extractValidGpsData(fileInfo *exiftool.FileMetadata, media_path string) (*f if (GPSLat != nil && math.Abs(*GPSLat) > 90) || (GPSLong != nil && math.Abs(*GPSLong) > 90) { log.Printf( "Incorrect GPS data in the %s Exif data: %f, %f, while expected values between '-90' and '90'. Ignoring GPS data.", - media_path, *GPSLat, *GPSLong) + mediaPath, *GPSLat, *GPSLong) return nil, nil } return GPSLat, GPSLong } -func (p *externalExifParser) ParseExif(media_path string) (returnExif *models.MediaEXIF, returnErr error) { +func (p *externalExifParser) ParseExif(mediaPath string) (returnExif *models.MediaEXIF, returnErr error) { // ExifTool - No print conversion mode if p.et == nil { et, err := exiftool.NewExiftool(exiftool.NoPrintConversion()) @@ -100,39 +100,39 @@ func (p *externalExifParser) ParseExif(media_path string) (returnExif *models.Me } } - fileInfo, err := p.dataLoader.Load(media_path) + fileInfo, err := p.dataLoader.Load(mediaPath) if err != nil { return nil, err } newExif := models.MediaEXIF{} - found_exif := false + foundExif := false // Get description description, err := fileInfo.GetString("ImageDescription") if err == nil { - found_exif = true + foundExif = true newExif.Description = &description } // Get camera model model, err := fileInfo.GetString("Model") if err == nil { - found_exif = true + foundExif = true newExif.Camera = &model } // Get Camera make make, err := fileInfo.GetString("Make") if err == nil { - found_exif = true + foundExif = true newExif.Maker = &make } // Get lens lens, err := fileInfo.GetString("LensModel") if err == nil { - found_exif = true + foundExif = true newExif.Lens = &lens } @@ -144,13 +144,13 @@ func (p *externalExifParser) ParseExif(media_path string) (returnExif *models.Me layout := "2006:01:02 15:04:05" dateTime, err := time.Parse(layout, date) if err == nil { - found_exif = true + foundExif = true newExif.DateShot = &dateTime } else { layoutWithOffset := "2006:01:02 15:04:05-07:00" dateTime, err = time.Parse(layoutWithOffset, date) if err == nil { - found_exif = true + foundExif = true newExif.DateShot = &dateTime } } @@ -161,59 +161,59 @@ func (p *externalExifParser) ParseExif(media_path string) (returnExif *models.Me // Get exposure time exposureTime, err := fileInfo.GetFloat("ExposureTime") if err == nil { - found_exif = true + foundExif = true newExif.Exposure = &exposureTime } // Get aperture aperture, err := fileInfo.GetFloat("Aperture") if err == nil { - found_exif = true + foundExif = true newExif.Aperture = &aperture } // Get ISO iso, err := fileInfo.GetInt("ISO") if err == nil { - found_exif = true + foundExif = true newExif.Iso = &iso } // Get focal length focalLen, err := fileInfo.GetFloat("FocalLength") if err == nil { - found_exif = true + foundExif = true newExif.FocalLength = &focalLen } // Get flash info flash, err := fileInfo.GetInt("Flash") if err == nil { - found_exif = true + foundExif = true newExif.Flash = &flash } // Get orientation orientation, err := fileInfo.GetInt("Orientation") if err == nil { - found_exif = true + foundExif = true newExif.Orientation = &orientation } // Get exposure program expProgram, err := fileInfo.GetInt("ExposureProgram") if err == nil { - found_exif = true + foundExif = true newExif.ExposureProgram = &expProgram } // Get GPS data - newExif.GPSLatitude, newExif.GPSLongitude = extractValidGpsData(&fileInfo, media_path) + newExif.GPSLatitude, newExif.GPSLongitude = extractValidGpsData(&fileInfo, mediaPath) if (newExif.GPSLatitude != nil) && (newExif.GPSLongitude != nil) { - found_exif = true + foundExif = true } - if !found_exif { + if !foundExif { return nil, nil } diff --git a/api/scanner/exif/exif_parser_internal.go b/api/scanner/exif/exif_parser_internal.go index 398635dc..9b1f08b3 100644 --- a/api/scanner/exif/exif_parser_internal.go +++ b/api/scanner/exif/exif_parser_internal.go @@ -17,12 +17,17 @@ import ( // internalExifParser is an exif parser that parses the media without the use of external tools type internalExifParser struct{} +const couldNotReadXfromEXIFy = "could not read %s from EXIF: %s" +const warnEXIFtagXreturnedNully = "WARN: EXIF tag %s returned null: %s\n" + +var ErrNullExifTag = errors.New("exif tag returned null") + func NewInternalExifParser() ExifParser { return internalExifParser{} } -func (p internalExifParser) ParseExif(media_path string) (returnExif *models.MediaEXIF, returnErr error) { - photoFile, err := os.Open(media_path) +func (p internalExifParser) ParseExif(mediaPath string) (returnExif *models.MediaEXIF, returnErr error) { + photoFile, err := os.Open(mediaPath) if err != nil { return nil, err } @@ -45,22 +50,22 @@ func (p internalExifParser) ParseExif(media_path string) (returnExif *models.Med newExif := models.MediaEXIF{} - description, err := p.readStringTag(exifTags, exif.ImageDescription, media_path) + description, err := p.readStringTag(exifTags, exif.ImageDescription, mediaPath) if err == nil { newExif.Description = description } - model, err := p.readStringTag(exifTags, exif.Model, media_path) + model, err := p.readStringTag(exifTags, exif.Model, mediaPath) if err == nil { newExif.Camera = model } - maker, err := p.readStringTag(exifTags, exif.Make, media_path) + maker, err := p.readStringTag(exifTags, exif.Make, mediaPath) if err == nil { newExif.Maker = maker } - lens, err := p.readStringTag(exifTags, exif.LensModel, media_path) + lens, err := p.readStringTag(exifTags, exif.LensModel, mediaPath) if err == nil { newExif.Lens = lens } @@ -68,8 +73,8 @@ func (p internalExifParser) ParseExif(media_path string) (returnExif *models.Med date, err := exifTags.DateTime() if err == nil { _, tz := date.Zone() - date_utc := date.Add(time.Duration(tz) * time.Second).UTC() - newExif.DateShot = &date_utc + dateUTC := date.Add(time.Duration(tz) * time.Second).UTC() + newExif.DateShot = &dateUTC } exposureTag, err := exifTags.Get(exif.ExposureTime) @@ -81,7 +86,7 @@ func (p internalExifParser) ParseExif(media_path string) (returnExif *models.Med } } - apertureRat, err := p.readRationalTag(exifTags, exif.FNumber, media_path) + apertureRat, err := p.readRationalTag(exifTags, exif.FNumber, mediaPath) if err == nil { aperture, _ := apertureRat.Float64() newExif.Aperture = &aperture @@ -89,11 +94,11 @@ func (p internalExifParser) ParseExif(media_path string) (returnExif *models.Med isoTag, err := exifTags.Get(exif.ISOSpeedRatings) if err != nil { - log.Printf("WARN: Could not read ISOSpeedRatings from EXIF: %v\n", media_path) + log.Printf("WARN: Could not read ISOSpeedRatings from EXIF: %v\n", mediaPath) } else { iso, err := isoTag.Int(0) if err != nil { - log.Printf("WARN: Could not parse EXIF ISOSpeedRatings as integer: %v\n", media_path) + log.Printf("WARN: Could not parse EXIF ISOSpeedRatings as integer: %v\n", mediaPath) } else { iso64 := int64(iso) newExif.Iso = &iso64 @@ -106,36 +111,32 @@ func (p internalExifParser) ParseExif(media_path string) (returnExif *models.Med if err == nil { focalLength, _ := focalLengthRat.Float64() newExif.FocalLength = &focalLength - } else { // For some photos, the focal length cannot be read as a rational value, // but is instead the second value read as an integer - - if err == nil { - focalLength, err := focalLengthTag.Int(1) - if err != nil { - log.Printf("WARN: Could not parse EXIF FocalLength as rational or integer: %v\n%s\n", media_path, err) - } else { - focalLenFloat := float64(focalLength) - newExif.FocalLength = &focalLenFloat - } + focalLength, err := focalLengthTag.Int(1) + if err != nil { + log.Printf("WARN: Could not parse EXIF FocalLength as rational or integer: %v\n%s\n", mediaPath, err) + } else { + focalLenFloat := float64(focalLength) + newExif.FocalLength = &focalLenFloat } } } - flash, err := p.readIntegerTag(exifTags, exif.Flash, media_path) + flash, err := p.readIntegerTag(exifTags, exif.Flash, mediaPath) if err == nil { flash64 := int64(*flash) newExif.Flash = &flash64 } - orientation, err := p.readIntegerTag(exifTags, exif.Orientation, media_path) + orientation, err := p.readIntegerTag(exifTags, exif.Orientation, mediaPath) if err == nil { orientation64 := int64(*orientation) newExif.Orientation = &orientation64 } - exposureProgram, err := p.readIntegerTag(exifTags, exif.ExposureProgram, media_path) + exposureProgram, err := p.readIntegerTag(exifTags, exif.ExposureProgram, mediaPath) if err == nil { exposureProgram64 := int64(*exposureProgram) newExif.ExposureProgram = &exposureProgram64 @@ -147,7 +148,7 @@ func (p internalExifParser) ParseExif(media_path string) (returnExif *models.Med returnExif = &newExif log.Printf( "Incorrect GPS data in the %s Exif data: %f, %f, while expected values between '-90' and '90'. Ignoring GPS data.", - media_path, long, lat) + mediaPath, long, lat) return } else { newExif.GPSLatitude = &lat @@ -159,59 +160,59 @@ func (p internalExifParser) ParseExif(media_path string) (returnExif *models.Med return } -func (p *internalExifParser) readStringTag(tags *exif.Exif, name exif.FieldName, media_path string) (*string, error) { +func (p *internalExifParser) readStringTag(tags *exif.Exif, name exif.FieldName, mediaPath string) (*string, error) { tag, err := tags.Get(name) if err != nil { - return nil, errors.Wrapf(err, "could not read %s from EXIF: %s", name, media_path) + return nil, errors.Wrapf(err, couldNotReadXfromEXIFy, name, mediaPath) } if tag != nil { value, err := tag.StringVal() if err != nil { - return nil, errors.Wrapf(err, "could not parse %s from EXIF as string: %s", name, media_path) + return nil, errors.Wrapf(err, "could not parse %s from EXIF as string: %s", name, mediaPath) } return &value, nil } - log.Printf("WARN: EXIF tag %s returned null: %s\n", name, media_path) - return nil, errors.New("exif tag returned null") + log.Printf(warnEXIFtagXreturnedNully, name, mediaPath) + return nil, ErrNullExifTag } -func (p *internalExifParser) readRationalTag(tags *exif.Exif, name exif.FieldName, media_path string) (*big.Rat, error) { +func (p *internalExifParser) readRationalTag(tags *exif.Exif, name exif.FieldName, mediaPath string) (*big.Rat, error) { tag, err := tags.Get(name) if err != nil { - return nil, errors.Wrapf(err, "could not read %s from EXIF: %s", name, media_path) + return nil, errors.Wrapf(err, couldNotReadXfromEXIFy, name, mediaPath) } if tag != nil { value, err := tag.Rat(0) if err != nil { - return nil, errors.Wrapf(err, "could not parse %s from EXIF as rational: %s", name, media_path) + return nil, errors.Wrapf(err, "could not parse %s from EXIF as rational: %s", name, mediaPath) } return value, nil } - log.Printf("WARN: EXIF tag %s returned null: %s\n", name, media_path) - return nil, errors.New("exif tag returned null") + log.Printf(warnEXIFtagXreturnedNully, name, mediaPath) + return nil, ErrNullExifTag } -func (p *internalExifParser) readIntegerTag(tags *exif.Exif, name exif.FieldName, media_path string) (*int, error) { +func (p *internalExifParser) readIntegerTag(tags *exif.Exif, name exif.FieldName, mediaPath string) (*int, error) { tag, err := tags.Get(name) if err != nil { - return nil, errors.Wrapf(err, "could not read %s from EXIF: %s", name, media_path) + return nil, errors.Wrapf(err, couldNotReadXfromEXIFy, name, mediaPath) } if tag != nil { value, err := tag.Int(0) if err != nil { - return nil, errors.Wrapf(err, "Could not parse %s from EXIF as integer: %s", name, media_path) + return nil, errors.Wrapf(err, "Could not parse %s from EXIF as integer: %s", name, mediaPath) } return &value, nil } - log.Printf("WARN: EXIF tag %s returned null: %s\n", name, media_path) - return nil, errors.New("exif tag returned null") + log.Printf(warnEXIFtagXreturnedNully, name, mediaPath) + return nil, ErrNullExifTag } diff --git a/api/scanner/media_encoding/executable_worker/executable_worker_test.go b/api/scanner/media_encoding/executable_worker/executable_worker_test.go index 756ffeb9..f243f4f6 100644 --- a/api/scanner/media_encoding/executable_worker/executable_worker_test.go +++ b/api/scanner/media_encoding/executable_worker/executable_worker_test.go @@ -17,7 +17,9 @@ func TestMain(m *testing.M) { func setPathWithCurrent(paths ...string) func() { _, file, _, ok := runtime.Caller(0) if !ok { - return func() {} + return func() { + // Return an empty function in case of error + } } base := filepath.Dir(file) diff --git a/api/scanner/media_encoding/executable_worker/magick_cli_test.go b/api/scanner/media_encoding/executable_worker/magick_cli_test.go index 6696f19b..0f9462a0 100644 --- a/api/scanner/media_encoding/executable_worker/magick_cli_test.go +++ b/api/scanner/media_encoding/executable_worker/magick_cli_test.go @@ -7,6 +7,8 @@ import ( "github.com/photoview/photoview/api/scanner/media_encoding/executable_worker" ) +const testdataBinPath = "./testdata/bin" + func TestMagickCliNotExist(t *testing.T) { done := setPathWithCurrent() defer done() @@ -18,7 +20,7 @@ func TestMagickCliNotExist(t *testing.T) { } func TestMagickCliIgnore(t *testing.T) { - donePath := setPathWithCurrent("./testdata/bin") + donePath := setPathWithCurrent(testdataBinPath) defer donePath() doneDisableRaw := setEnv("PHOTOVIEW_DISABLE_RAW_PROCESSING", "true") @@ -31,7 +33,7 @@ func TestMagickCliIgnore(t *testing.T) { } func TestMagickCliFail(t *testing.T) { - donePath := setPathWithCurrent("./testdata/bin") + donePath := setPathWithCurrent(testdataBinPath) defer donePath() executable_worker.InitializeExecutableWorkers() @@ -53,7 +55,7 @@ func TestMagickCliFail(t *testing.T) { } func TestMagickCliSucceed(t *testing.T) { - donePath := setPathWithCurrent("./testdata/bin") + donePath := setPathWithCurrent(testdataBinPath) defer donePath() executable_worker.InitializeExecutableWorkers() diff --git a/api/scanner/periodic_scanner/periodic_scanner.go b/api/scanner/periodic_scanner/periodic_scanner.go index d05ee4dc..f5e6963c 100644 --- a/api/scanner/periodic_scanner/periodic_scanner.go +++ b/api/scanner/periodic_scanner/periodic_scanner.go @@ -52,9 +52,9 @@ func InitializePeriodicScanner(db *gorm.DB) error { } func ChangePeriodicScanInterval(duration time.Duration) { - var new_ticker *time.Ticker = nil + var newTicker *time.Ticker = nil if duration > 0 { - new_ticker = time.NewTicker(duration) + newTicker = time.NewTicker(duration) log.Printf("Periodic scan interval changed: %s", duration.String()) } else { log.Print("Periodic scan interval changed: disabled") @@ -68,7 +68,7 @@ func ChangePeriodicScanInterval(duration time.Duration) { mainPeriodicScanner.ticker.Stop() } - mainPeriodicScanner.ticker = new_ticker + mainPeriodicScanner.ticker = newTicker mainPeriodicScanner.ticker_changed <- true } } diff --git a/api/scanner/scanner_album.go b/api/scanner/scanner_album.go index ee8c082b..708abfc3 100644 --- a/api/scanner/scanner_album.go +++ b/api/scanner/scanner_album.go @@ -2,7 +2,6 @@ package scanner import ( "fmt" - "io/ioutil" "log" "os" "path" @@ -118,7 +117,7 @@ func findMediaForAlbum(ctx scanner_task.TaskContext) ([]*models.Media, error) { albumMedia := make([]*models.Media, 0) - dirContent, err := ioutil.ReadDir(ctx.GetAlbum().Path) + dirContent, err := os.ReadDir(ctx.GetAlbum().Path) if err != nil { return nil, err } @@ -133,7 +132,11 @@ func findMediaForAlbum(ctx scanner_task.TaskContext) ([]*models.Media, error) { } if !item.IsDir() && !isDirSymlink && ctx.GetCache().IsPathMedia(mediaPath) { - skip, err := scanner_tasks.Tasks.MediaFound(ctx, item, mediaPath) + itemInfo, err := item.Info() + if err != nil { + return nil, err + } + skip, err := scanner_tasks.Tasks.MediaFound(ctx, itemInfo, mediaPath) if err != nil { return nil, err } diff --git a/api/scanner/scanner_album_test.go b/api/scanner/scanner_album_test.go index dc3f7175..41068c3d 100644 --- a/api/scanner/scanner_album_test.go +++ b/api/scanner/scanner_album_test.go @@ -9,6 +9,8 @@ import ( "github.com/stretchr/testify/assert" ) +const testDataPath = "./test_data" + func TestNewRootPath(t *testing.T) { db := test_utils.DatabaseTest(t) @@ -21,7 +23,7 @@ func TestNewRootPath(t *testing.T) { } t.Run("Insert valid root album", func(t *testing.T) { - album, err := scanner.NewRootAlbum(db, "./test_data", &user) + album, err := scanner.NewRootAlbum(db, testDataPath, &user) if !assert.NoError(t, err) { return } @@ -33,7 +35,7 @@ func TestNewRootPath(t *testing.T) { t.Run("Insert duplicate root album", func(t *testing.T) { - _, err := scanner.NewRootAlbum(db, "./test_data", &user) + _, err := scanner.NewRootAlbum(db, testDataPath, &user) assert.Error(t, err) assert.Contains(t, err.Error(), "user already owns a path containing this path:") @@ -57,7 +59,7 @@ func TestNewRootPath(t *testing.T) { return } - album, err := scanner.NewRootAlbum(db, "./test_data", &user2) + album, err := scanner.NewRootAlbum(db, testDataPath, &user2) if !assert.NoError(t, err) { return } @@ -65,8 +67,8 @@ func TestNewRootPath(t *testing.T) { assert.NotNil(t, album) assert.Contains(t, album.Path, "/api/scanner/test_data") - owner_count := db.Model(&album).Association("Owners").Count() - assert.EqualValues(t, 2, owner_count) + ownerCount := db.Model(&album).Association("Owners").Count() + assert.EqualValues(t, 2, ownerCount) }) } diff --git a/api/scanner/scanner_cache/cache.go b/api/scanner/scanner_cache/cache.go index c90655ac..50653bea 100644 --- a/api/scanner/scanner_cache/cache.go +++ b/api/scanner/scanner_cache/cache.go @@ -27,25 +27,25 @@ func MakeAlbumCache() *AlbumScannerCache { } // Insert single album directory in cache -func (c *AlbumScannerCache) InsertAlbumPath(path string, contains_photo bool) { +func (c *AlbumScannerCache) InsertAlbumPath(path string, containsPhoto bool) { c.mutex.Lock() defer c.mutex.Unlock() - c.path_contains_photos[path] = contains_photo + c.path_contains_photos[path] = containsPhoto } // Insert album path and all parent directories up to the given root directory in cache -func (c *AlbumScannerCache) InsertAlbumPaths(end_path string, root string, contains_photo bool) { - curr_path := path.Clean(end_path) - root_path := path.Clean(root) +func (c *AlbumScannerCache) InsertAlbumPaths(endPath string, root string, containsPhoto bool) { + currPath := path.Clean(endPath) + rootPath := path.Clean(root) c.mutex.Lock() defer c.mutex.Unlock() - for curr_path != root_path || curr_path == "." { + for currPath != rootPath || currPath == "." { - c.path_contains_photos[curr_path] = contains_photo + c.path_contains_photos[currPath] = containsPhoto - curr_path = path.Dir(curr_path) + currPath = path.Dir(currPath) } } @@ -103,11 +103,11 @@ func (c *AlbumScannerCache) GetAlbumIgnore(path string) *[]string { return nil } -func (c *AlbumScannerCache) InsertAlbumIgnore(path string, ignore_data []string) { +func (c *AlbumScannerCache) InsertAlbumIgnore(path string, ignoreData []string) { c.mutex.Lock() defer c.mutex.Unlock() - c.ignore_data[path] = ignore_data + c.ignore_data[path] = ignoreData } func (c *AlbumScannerCache) IsPathMedia(mediaPath string) bool { diff --git a/api/scanner/scanner_media.go b/api/scanner/scanner_media.go index 5abb45c1..416e538e 100644 --- a/api/scanner/scanner_media.go +++ b/api/scanner/scanner_media.go @@ -71,17 +71,17 @@ func ScanMedia(tx *gorm.DB, mediaPath string, albumId int, cache *scanner_cache. // ProcessSingleMedia processes a single media, might be used to reprocess media with corrupted cache // Function waits for processing to finish before returning. func ProcessSingleMedia(db *gorm.DB, media *models.Media) error { - album_cache := scanner_cache.MakeAlbumCache() + albumCache := scanner_cache.MakeAlbumCache() var album models.Album if err := db.Model(media).Association("Album").Find(&album); err != nil { return err } - media_data := media_encoding.NewEncodeMediaData(media) + mediaData := media_encoding.NewEncodeMediaData(media) - task_context := scanner_task.NewTaskContext(context.Background(), db, &album, album_cache) - if err := scanMedia(task_context, media, &media_data, 0, 1); err != nil { + taskContext := scanner_task.NewTaskContext(context.Background(), db, &album, albumCache) + if err := scanMedia(taskContext, media, &mediaData, 0, 1); err != nil { return errors.Wrap(err, "single media scan") } diff --git a/api/scanner/scanner_queue/queue.go b/api/scanner/scanner_queue/queue.go index 234655e5..acd4bd3f 100644 --- a/api/scanner/scanner_queue/queue.go +++ b/api/scanner/scanner_queue/queue.go @@ -18,6 +18,8 @@ import ( "gorm.io/gorm" ) +const globalScannerProgress = "global-scanner-progress" + // ScannerJob describes a job on the queue to be run by the scanner over a single album type ScannerJob struct { ctx scanner_task.TaskContext @@ -104,11 +106,11 @@ func (queue *ScannerQueue) startBackgroundWorker() { <-queue.idle_chan queue.mutex.Lock() - should_stop := queue.close_chan != nil && len(queue.in_progress) == 0 && len(queue.up_next) == 0 + shouldStop := queue.close_chan != nil && len(queue.in_progress) == 0 && len(queue.up_next) == 0 queue.running = false queue.mutex.Unlock() - if should_stop { + if shouldStop { *queue.close_chan <- true break } @@ -121,14 +123,14 @@ func (queue *ScannerQueue) startBackgroundWorker() { func (queue *ScannerQueue) CloseBackgroundWorker() { queue.mutex.Lock() - close_chan := make(chan bool) - queue.close_chan = &close_chan + closeChan := make(chan bool) + queue.close_chan = &closeChan queue.mutex.Unlock() queue.notify() log.Println("Waiting for scanner background worker to finish all jobs...") - <-close_chan + <-closeChan } func (queue *ScannerQueue) processQueue(notifyThrottle *utils.Throttle) { @@ -162,14 +164,14 @@ func (queue *ScannerQueue) processQueue(notifyThrottle *utils.Throttle) { }() } - in_progress_length := len(global_scanner_queue.in_progress) - up_next_length := len(global_scanner_queue.up_next) + inProgressLength := len(global_scanner_queue.in_progress) + upNextLength := len(global_scanner_queue.up_next) queue.mutex.Unlock() - if in_progress_length+up_next_length == 0 { + if inProgressLength+upNextLength == 0 { notification.BroadcastNotification(&models.Notification{ - Key: "global-scanner-progress", + Key: globalScannerProgress, Type: models.NotificationTypeMessage, Header: "Generating blurhashes", Content: "Generating blurhashes for newly scanned media", @@ -181,7 +183,7 @@ func (queue *ScannerQueue) processQueue(notifyThrottle *utils.Throttle) { } notification.BroadcastNotification(&models.Notification{ - Key: "global-scanner-progress", + Key: globalScannerProgress, Type: models.NotificationTypeMessage, Header: "Scanner complete", Content: "All jobs have been scanned", @@ -190,10 +192,10 @@ func (queue *ScannerQueue) processQueue(notifyThrottle *utils.Throttle) { } else { notifyThrottle.Trigger(func() { notification.BroadcastNotification(&models.Notification{ - Key: "global-scanner-progress", + Key: globalScannerProgress, Type: models.NotificationTypeMessage, Header: "Scanning media", - Content: fmt.Sprintf("%d jobs in progress\n%d jobs waiting", in_progress_length, up_next_length), + Content: fmt.Sprintf("%d jobs in progress\n%d jobs waiting", inProgressLength, upNextLength), }) }) } @@ -229,8 +231,8 @@ func AddAllToQueue() error { // AddUserToQueue finds all root albums owned by the given user and adds them to the scanner queue. // Function does not block. func AddUserToQueue(user *models.User) error { - album_cache := scanner_cache.MakeAlbumCache() - albums, album_errors := scanner.FindAlbumsForUser(global_scanner_queue.db, user, album_cache) + albumCache := scanner_cache.MakeAlbumCache() + albums, album_errors := scanner.FindAlbumsForUser(global_scanner_queue.db, user, albumCache) for _, err := range album_errors { return errors.Wrapf(err, "find albums for user (user_id: %d)", user.ID) } @@ -238,7 +240,7 @@ func AddUserToQueue(user *models.User) error { global_scanner_queue.mutex.Lock() for _, album := range albums { global_scanner_queue.addJob(&ScannerJob{ - ctx: scanner_task.NewTaskContext(context.Background(), global_scanner_queue.db, album, album_cache), + ctx: scanner_task.NewTaskContext(context.Background(), global_scanner_queue.db, album, albumCache), }) } global_scanner_queue.mutex.Unlock() diff --git a/api/scanner/scanner_queue/queue_test.go b/api/scanner/scanner_queue/queue_test.go index 2b2db964..f2280ab8 100644 --- a/api/scanner/scanner_queue/queue_test.go +++ b/api/scanner/scanner_queue/queue_test.go @@ -24,7 +24,7 @@ func makeScannerJob(albumID int) ScannerJob { return NewScannerJob(scanner_task.NewTaskContext(context.Background(), nil, makeAlbumWithID(albumID), scanner_cache.MakeAlbumCache())) } -func TestScannerQueue_AddJob(t *testing.T) { +func TestScannerQueueAddJob(t *testing.T) { scannerJobs := []ScannerJob{ makeScannerJob(100), @@ -72,7 +72,7 @@ func TestScannerQueue_AddJob(t *testing.T) { }) } -func TestScannerQueue_JobOnQueue(t *testing.T) { +func TestScannerQueueJobOnQueue(t *testing.T) { scannerJobs := []ScannerJob{ makeScannerJob(100), diff --git a/api/scanner/scanner_tasks/cleanup_tasks/cleanup_media_test.go b/api/scanner/scanner_tasks/cleanup_tasks/cleanup_media_test.go index a58484d4..8f9eaffa 100644 --- a/api/scanner/scanner_tasks/cleanup_tasks/cleanup_media_test.go +++ b/api/scanner/scanner_tasks/cleanup_tasks/cleanup_media_test.go @@ -30,23 +30,23 @@ func TestCleanupMedia(t *testing.T) { return } - test_dir := t.TempDir() - assert.NoError(t, copy.Copy("../../test_data", test_dir)) + testDir := t.TempDir() + assert.NoError(t, copy.Copy("../../test_data", testDir)) countAllMedia := func() int { - var all_media []*models.Media - if !assert.NoError(t, db.Find(&all_media).Error) { + var allMedia []*models.Media + if !assert.NoError(t, db.Find(&allMedia).Error) { return -1 } - return len(all_media) + return len(allMedia) } countAllMediaURLs := func() int { - var all_media_urls []*models.MediaURL - if !assert.NoError(t, db.Find(&all_media_urls).Error) { + var allMediaURLs []*models.MediaURL + if !assert.NoError(t, db.Find(&allMediaURLs).Error) { return -1 } - return len(all_media_urls) + return len(allMediaURLs) } pass := "1234" @@ -60,20 +60,20 @@ func TestCleanupMedia(t *testing.T) { return } - root_album := models.Album{ + rootAlbum := models.Album{ Title: "root album", - Path: test_dir, + Path: testDir, } - if !assert.NoError(t, db.Save(&root_album).Error) { + if !assert.NoError(t, db.Save(&rootAlbum).Error) { return } - err = db.Model(user1).Association("Albums").Append(&root_album) + err = db.Model(user1).Association("Albums").Append(&rootAlbum) if !assert.NoError(t, err) { return } - err = db.Model(user2).Association("Albums").Append(&root_album) + err = db.Model(user2).Association("Albums").Append(&rootAlbum) if !assert.NoError(t, err) { return } @@ -84,25 +84,25 @@ func TestCleanupMedia(t *testing.T) { assert.Equal(t, 18, countAllMediaURLs()) // move faces directory - assert.NoError(t, os.Rename(path.Join(test_dir, "faces"), path.Join(test_dir, "faces_moved"))) + assert.NoError(t, os.Rename(path.Join(testDir, "faces"), path.Join(testDir, "faces_moved"))) test_utils.RunScannerAll(t, db) assert.Equal(t, 9, countAllMedia()) assert.Equal(t, 18, countAllMediaURLs()) // remove faces_moved directory - assert.NoError(t, os.RemoveAll(path.Join(test_dir, "faces_moved"))) + assert.NoError(t, os.RemoveAll(path.Join(testDir, "faces_moved"))) test_utils.RunScannerAll(t, db) assert.Equal(t, 3, countAllMedia()) assert.Equal(t, 6, countAllMediaURLs()) }) t.Run("Modify images", func(t *testing.T) { - assert.NoError(t, os.Rename(path.Join(test_dir, "buttercup_close_summer_yellow.jpg"), path.Join(test_dir, "yellow-flower.jpg"))) + assert.NoError(t, os.Rename(path.Join(testDir, "buttercup_close_summer_yellow.jpg"), path.Join(testDir, "yellow-flower.jpg"))) test_utils.RunScannerAll(t, db) assert.Equal(t, 3, countAllMedia()) assert.Equal(t, 6, countAllMediaURLs()) - assert.NoError(t, os.Remove(path.Join(test_dir, "lilac_lilac_bush_lilac.jpg"))) + assert.NoError(t, os.Remove(path.Join(testDir, "lilac_lilac_bush_lilac.jpg"))) test_utils.RunScannerAll(t, db) assert.Equal(t, 2, countAllMedia()) assert.Equal(t, 4, countAllMediaURLs()) diff --git a/api/scanner/scanner_tasks/cleanup_tasks/media_cleanup_task.go b/api/scanner/scanner_tasks/cleanup_tasks/media_cleanup_task.go index 4183c2b1..f7d6d3ec 100644 --- a/api/scanner/scanner_tasks/cleanup_tasks/media_cleanup_task.go +++ b/api/scanner/scanner_tasks/cleanup_tasks/media_cleanup_task.go @@ -12,8 +12,8 @@ type MediaCleanupTask struct { func (t MediaCleanupTask) AfterScanAlbum(ctx scanner_task.TaskContext, changedMedia []*models.Media, albumMedia []*models.Media) error { - cleanup_errors := CleanupMedia(ctx.GetDB(), ctx.GetAlbum().ID, albumMedia) - for _, err := range cleanup_errors { + cleanupErrors := CleanupMedia(ctx.GetDB(), ctx.GetAlbum().ID, albumMedia) + for _, err := range cleanupErrors { scanner_utils.ScannerError("delete old media: %s", err) } diff --git a/api/scanner/scanner_tasks/processing_tasks/process_photo_task.go b/api/scanner/scanner_tasks/processing_tasks/process_photo_task.go index 5ea94d3b..311061e3 100644 --- a/api/scanner/scanner_tasks/processing_tasks/process_photo_task.go +++ b/api/scanner/scanner_tasks/processing_tasks/process_photo_task.go @@ -55,7 +55,6 @@ func (t ProcessPhotoTask) ProcessMedia(ctx scanner_task.TaskContext, mediaData * return []*models.MediaURL{}, errors.Wrap(err, "error processing photo highres") } - var photoDimensions *media_utils.PhotoDimensions var baseImagePath string = photo.Path // Generate high res jpeg @@ -92,15 +91,14 @@ func (t ProcessPhotoTask) ProcessMedia(ctx scanner_task.TaskContext, mediaData * } } + var photoDimensions *media_utils.PhotoDimensions // Save original photo to database if origURL == nil { // Make sure photo dimensions is set - if photoDimensions == nil { - photoDimensions, err = media_utils.GetPhotoDimensions(baseImagePath) - if err != nil { - return []*models.MediaURL{}, err - } + photoDimensions, err = media_utils.GetPhotoDimensions(baseImagePath) + if err != nil { + return []*models.MediaURL{}, err } original, err := saveOriginalPhotoToDB(ctx.GetDB(), photo, mediaData, photoDimensions) diff --git a/api/scanner/scanner_tasks/processing_tasks/process_video_task.go b/api/scanner/scanner_tasks/processing_tasks/process_video_task.go index b29f4825..c042207e 100644 --- a/api/scanner/scanner_tasks/processing_tasks/process_video_task.go +++ b/api/scanner/scanner_tasks/processing_tasks/process_video_task.go @@ -87,12 +87,12 @@ func (t ProcessVideoTask) ProcessMedia(ctx scanner_task.TaskContext, mediaData * } if videoWebURL == nil && !videoType.IsWebCompatible() { - web_video_name := fmt.Sprintf("web_video_%s_%s", path.Base(video.Path), utils.GenerateToken()) - web_video_name = strings.ReplaceAll(web_video_name, ".", "_") - web_video_name = strings.ReplaceAll(web_video_name, " ", "_") - web_video_name = web_video_name + ".mp4" + webVideoName := fmt.Sprintf("web_video_%s_%s", path.Base(video.Path), utils.GenerateToken()) + webVideoName = strings.ReplaceAll(webVideoName, ".", "_") + webVideoName = strings.ReplaceAll(webVideoName, " ", "_") + webVideoName = webVideoName + ".mp4" - webVideoPath := path.Join(mediaCachePath, web_video_name) + webVideoPath := path.Join(mediaCachePath, webVideoName) err = executable_worker.FfmpegCli.EncodeMp4(video.Path, webVideoPath) if err != nil { @@ -111,7 +111,7 @@ func (t ProcessVideoTask) ProcessMedia(ctx scanner_task.TaskContext, mediaData * mediaURL := models.MediaURL{ MediaID: video.ID, - MediaName: web_video_name, + MediaName: webVideoName, Width: webMetadata.Width, Height: webMetadata.Height, Purpose: models.VideoWeb, @@ -132,12 +132,12 @@ func (t ProcessVideoTask) ProcessMedia(ctx scanner_task.TaskContext, mediaData * } if videoThumbnailURL == nil { - video_thumb_name := fmt.Sprintf("video_thumb_%s_%s", path.Base(video.Path), utils.GenerateToken()) - video_thumb_name = strings.ReplaceAll(video_thumb_name, ".", "_") - video_thumb_name = strings.ReplaceAll(video_thumb_name, " ", "_") - video_thumb_name = video_thumb_name + ".jpg" + videoThumbName := fmt.Sprintf("video_thumb_%s_%s", path.Base(video.Path), utils.GenerateToken()) + videoThumbName = strings.ReplaceAll(videoThumbName, ".", "_") + videoThumbName = strings.ReplaceAll(videoThumbName, " ", "_") + videoThumbName = videoThumbName + ".jpg" - thumbImagePath := path.Join(mediaCachePath, video_thumb_name) + thumbImagePath := path.Join(mediaCachePath, videoThumbName) err = executable_worker.FfmpegCli.EncodeVideoThumbnail(video.Path, thumbImagePath, probeData) if err != nil { @@ -156,7 +156,7 @@ func (t ProcessVideoTask) ProcessMedia(ctx scanner_task.TaskContext, mediaData * thumbMediaURL := models.MediaURL{ MediaID: video.ID, - MediaName: video_thumb_name, + MediaName: videoThumbName, Width: thumbDimensions.Width, Height: thumbDimensions.Height, Purpose: models.VideoThumbnail, diff --git a/api/scanner/scanner_tasks/processing_tasks/processing_functions.go b/api/scanner/scanner_tasks/processing_tasks/processing_functions.go index 6e08ad5c..3ea60c6b 100644 --- a/api/scanner/scanner_tasks/processing_tasks/processing_functions.go +++ b/api/scanner/scanner_tasks/processing_tasks/processing_functions.go @@ -11,7 +11,7 @@ import ( "gorm.io/gorm" ) -func generateSaveHighResJPEG(tx *gorm.DB, media *models.Media, imageData *media_encoding.EncodeMediaData, highres_name string, imagePath string, mediaURL *models.MediaURL) (*models.MediaURL, error) { +func generateSaveHighResJPEG(tx *gorm.DB, media *models.Media, imageData *media_encoding.EncodeMediaData, highResName string, imagePath string, mediaURL *models.MediaURL) (*models.MediaURL, error) { err := imageData.EncodeHighRes(imagePath) if err != nil { @@ -32,7 +32,7 @@ func generateSaveHighResJPEG(tx *gorm.DB, media *models.Media, imageData *media_ mediaURL = &models.MediaURL{ MediaID: media.ID, - MediaName: highres_name, + MediaName: highResName, Width: photoDimensions.Width, Height: photoDimensions.Height, Purpose: models.PhotoHighRes, @@ -41,7 +41,7 @@ func generateSaveHighResJPEG(tx *gorm.DB, media *models.Media, imageData *media_ } if err := tx.Create(&mediaURL).Error; err != nil { - return nil, errors.Wrapf(err, "could not insert highres media url (%d, %s)", media.ID, highres_name) + return nil, errors.Wrapf(err, "could not insert highres media url (%d, %s)", media.ID, highResName) } } else { mediaURL.Width = photoDimensions.Width @@ -49,15 +49,15 @@ func generateSaveHighResJPEG(tx *gorm.DB, media *models.Media, imageData *media_ mediaURL.FileSize = fileStats.Size() if err := tx.Save(&mediaURL).Error; err != nil { - return nil, errors.Wrapf(err, "could not update media url after side car changes (%d, %s)", media.ID, highres_name) + return nil, errors.Wrapf(err, "could not update media url after side car changes (%d, %s)", media.ID, highResName) } } return mediaURL, nil } -func generateSaveThumbnailJPEG(tx *gorm.DB, media *models.Media, thumbnail_name string, photoCachePath string, baseImagePath string, mediaURL *models.MediaURL) (*models.MediaURL, error) { - thumbOutputPath := path.Join(photoCachePath, thumbnail_name) +func generateSaveThumbnailJPEG(tx *gorm.DB, media *models.Media, thumbnailName string, photoCachePath string, baseImagePath string, mediaURL *models.MediaURL) (*models.MediaURL, error) { + thumbOutputPath := path.Join(photoCachePath, thumbnailName) thumbSize, err := media_encoding.EncodeThumbnail(tx, baseImagePath, thumbOutputPath) if err != nil { @@ -73,7 +73,7 @@ func generateSaveThumbnailJPEG(tx *gorm.DB, media *models.Media, thumbnail_name mediaURL = &models.MediaURL{ MediaID: media.ID, - MediaName: thumbnail_name, + MediaName: thumbnailName, Width: thumbSize.Width, Height: thumbSize.Height, Purpose: models.PhotoThumbnail, @@ -82,7 +82,7 @@ func generateSaveThumbnailJPEG(tx *gorm.DB, media *models.Media, thumbnail_name } if err := tx.Create(&mediaURL).Error; err != nil { - return nil, errors.Wrapf(err, "could not insert thumbnail media url (%d, %s)", media.ID, thumbnail_name) + return nil, errors.Wrapf(err, "could not insert thumbnail media url (%d, %s)", media.ID, thumbnailName) } } else { mediaURL.Width = thumbSize.Width @@ -90,7 +90,7 @@ func generateSaveThumbnailJPEG(tx *gorm.DB, media *models.Media, thumbnail_name mediaURL.FileSize = fileStats.Size() if err := tx.Save(&mediaURL).Error; err != nil { - return nil, errors.Wrapf(err, "could not update media url after side car changes (%d, %s)", media.ID, thumbnail_name) + return nil, errors.Wrapf(err, "could not update media url after side car changes (%d, %s)", media.ID, thumbnailName) } } diff --git a/api/scanner/scanner_test.go b/api/scanner/scanner_test.go index e4d66ecc..9e84b39d 100644 --- a/api/scanner/scanner_test.go +++ b/api/scanner/scanner_test.go @@ -25,16 +25,16 @@ func TestFullScan(t *testing.T) { return } - root_album := models.Album{ + rootAlbum := models.Album{ Title: "root album", Path: "./test_data", } - if !assert.NoError(t, db.Save(&root_album).Error) { + if !assert.NoError(t, db.Save(&rootAlbum).Error) { return } - err = db.Model(user).Association("Albums").Append(&root_album) + err = db.Model(user).Association("Albums").Append(&rootAlbum) if !assert.NoError(t, err) { return } @@ -45,37 +45,37 @@ func TestFullScan(t *testing.T) { test_utils.RunScannerOnUser(t, db, user) - var all_media []*models.Media - if !assert.NoError(t, db.Find(&all_media).Error) { + var allMedia []*models.Media + if !assert.NoError(t, db.Find(&allMedia).Error) { return } - assert.Equal(t, 9, len(all_media)) + assert.Equal(t, 9, len(allMedia)) - var all_media_url []*models.MediaURL - if !assert.NoError(t, db.Find(&all_media_url).Error) { + var allMediaURL []*models.MediaURL + if !assert.NoError(t, db.Find(&allMediaURL).Error) { return } - assert.Equal(t, 18, len(all_media_url)) + assert.Equal(t, 18, len(allMediaURL)) // Verify that faces was recognized assert.Eventually(t, func() bool { - var all_face_groups []*models.FaceGroup - if !assert.NoError(t, db.Find(&all_face_groups).Error) { + var allFaceGroups []*models.FaceGroup + if !assert.NoError(t, db.Find(&allFaceGroups).Error) { return false } - return len(all_face_groups) == 3 + return len(allFaceGroups) == 3 }, time.Second*5, time.Millisecond*500) assert.Eventually(t, func() bool { - var all_image_faces []*models.ImageFace - if !assert.NoError(t, db.Find(&all_image_faces).Error) { + var allImageFaces []*models.ImageFace + if !assert.NoError(t, db.Find(&allImageFaces).Error) { return false } - return len(all_image_faces) == 6 + return len(allImageFaces) == 6 }, time.Second*5, time.Millisecond*500) } diff --git a/api/scanner/scanner_user.go b/api/scanner/scanner_user.go index 2ee41457..ef3cd8dc 100644 --- a/api/scanner/scanner_user.go +++ b/api/scanner/scanner_user.go @@ -3,7 +3,6 @@ package scanner import ( "bufio" "container/list" - "io/ioutil" "log" "os" "path" @@ -43,7 +42,7 @@ func getPhotoviewIgnore(ignorePath string) ([]string, error) { return photoviewIgnore, scanner.Err() } -func FindAlbumsForUser(db *gorm.DB, user *models.User, album_cache *scanner_cache.AlbumScannerCache) ([]*models.Album, []error) { +func FindAlbumsForUser(db *gorm.DB, user *models.User, albumCache *scanner_cache.AlbumScannerCache) ([]*models.Album, []error) { if err := user.FillAlbums(db); err != nil { return nil, []error{err} @@ -101,7 +100,7 @@ func FindAlbumsForUser(db *gorm.DB, user *models.User, album_cache *scanner_cach albumIgnore := albumInfo.ignore // Read path - dirContent, err := ioutil.ReadDir(albumPath) + dirContent, err := os.ReadDir(albumPath) if err != nil { scanErrors = append(scanErrors, errors.Wrapf(err, "read directory (%s)", albumPath)) continue @@ -156,7 +155,7 @@ func FindAlbumsForUser(db *gorm.DB, user *models.User, album_cache *scanner_cach } // Store album ignore - album_cache.InsertAlbumIgnore(albumPath, albumIgnore) + albumCache.InsertAlbumIgnore(albumPath, albumIgnore) if err := tx.Create(&album).Error; err != nil { return errors.Wrap(err, "insert album into database") @@ -182,7 +181,7 @@ func FindAlbumsForUser(db *gorm.DB, user *models.User, album_cache *scanner_cach } // Update album ignore - album_cache.InsertAlbumIgnore(albumPath, albumIgnore) + albumCache.InsertAlbumIgnore(albumPath, albumIgnore) } userAlbums = append(userAlbums, album) @@ -210,7 +209,7 @@ func FindAlbumsForUser(db *gorm.DB, user *models.User, album_cache *scanner_cach continue } - if (item.IsDir() || isDirSymlink) && directoryContainsPhotos(subalbumPath, album_cache, albumIgnore) { + if (item.IsDir() || isDirSymlink) && directoryContainsPhotos(subalbumPath, albumCache, albumIgnore) { scanQueue.PushBack(scanInfo{ path: subalbumPath, parent: album, @@ -228,21 +227,21 @@ func FindAlbumsForUser(db *gorm.DB, user *models.User, album_cache *scanner_cach func directoryContainsPhotos(rootPath string, cache *scanner_cache.AlbumScannerCache, albumIgnore []string) bool { - if contains_image := cache.AlbumContainsPhotos(rootPath); contains_image != nil { - return *contains_image + if containsImage := cache.AlbumContainsPhotos(rootPath); containsImage != nil { + return *containsImage } scanQueue := list.New() scanQueue.PushBack(rootPath) - scanned_directories := make([]string, 0) + scannedDirectories := make([]string, 0) for scanQueue.Front() != nil { dirPath := scanQueue.Front().Value.(string) scanQueue.Remove(scanQueue.Front()) - scanned_directories = append(scanned_directories, dirPath) + scannedDirectories = append(scannedDirectories, dirPath) // Update ignore dir list photoviewIgnore, err := getPhotoviewIgnore(dirPath) @@ -253,7 +252,7 @@ func directoryContainsPhotos(rootPath string, cache *scanner_cache.AlbumScannerC } ignoreEntries := ignore.CompileIgnoreLines(albumIgnore...) - dirContent, err := ioutil.ReadDir(dirPath) + dirContent, err := os.ReadDir(dirPath) if err != nil { scanner_utils.ScannerError("Could not read directory (%s): %s\n", dirPath, err.Error()) return false @@ -285,7 +284,7 @@ func directoryContainsPhotos(rootPath string, cache *scanner_cache.AlbumScannerC } - for _, scanned_path := range scanned_directories { + for _, scanned_path := range scannedDirectories { log.Printf("Insert Album %s, contains photo is false", scanned_path) cache.InsertAlbumPath(scanned_path, false) } diff --git a/api/utils/media_cache.go b/api/utils/media_cache.go index 42a38d4b..82ed8995 100644 --- a/api/utils/media_cache.go +++ b/api/utils/media_cache.go @@ -37,16 +37,16 @@ func CachePathForMedia(albumID int, mediaID int) (string, error) { return photoCachePath, nil } -var test_cache_path string = "" +var testCachePath string = "" -func ConfigureTestCache(tmp_dir string) { - test_cache_path = tmp_dir +func ConfigureTestCache(tmpDir string) { + testCachePath = tmpDir } // MediaCachePath returns the path for where the media cache is located on the file system func MediaCachePath() string { - if test_cache_path != "" { - return test_cache_path + if testCachePath != "" { + return testCachePath } photoCache := EnvMediaCachePath.GetValue() diff --git a/api/utils/utils_test.go b/api/utils/utils_test.go index ed4ebc9e..57c3fa6e 100644 --- a/api/utils/utils_test.go +++ b/api/utils/utils_test.go @@ -1,7 +1,6 @@ package utils_test import ( - "io/ioutil" "os" "path" "testing" @@ -18,7 +17,7 @@ func TestIsDirSymlink(t *testing.T) { test_utils.FilesystemTest(t) // Prepare a temporary directory for testing purposes - dir, err := ioutil.TempDir("", "testing") + dir, err := os.MkdirTemp("", "testing") if err != nil { t.Fatalf("unable to create temp directory for testing") }