From e1c45c4d5ff4ce97dc22dd7a105bc31ff44897e9 Mon Sep 17 00:00:00 2001 From: Michael Mayer Date: Sat, 11 Jul 2020 23:43:29 +0200 Subject: [PATCH] Rename "location" to "geo" to have a short, common prefix for geo data Signed-off-by: Michael Mayer --- frontend/src/component/photo/list.vue | 2 +- frontend/src/dialog/photo/info.vue | 2 +- frontend/src/model/photo.js | 20 +-- frontend/src/pages/album/photos.vue | 10 +- frontend/src/pages/photos.vue | 10 +- frontend/src/share/photo/list.vue | 2 +- frontend/src/share/photos.vue | 10 +- frontend/tests/unit/model/photo_test.js | 10 +- internal/acl/resources.go | 2 +- internal/classify/label.go | 2 +- internal/config/client.go | 12 +- internal/entity/entity.go | 4 +- internal/entity/fixtures.go | 2 +- internal/entity/{location.go => geo.go} | 129 +++++++++--------- .../{location_fixtures.go => geo_fixtures.go} | 74 +++++----- ..._fixtures_test.go => geo_fixtures_test.go} | 20 +-- .../entity/{location_test.go => geo_test.go} | 30 ++-- internal/entity/photo.go | 40 +++--- internal/entity/photo_fixtures.go | 126 ++++++++--------- internal/entity/photo_location.go | 16 +-- internal/entity/photo_optimize.go | 10 +- internal/entity/photo_test.go | 20 +-- internal/entity/photo_yaml_test.go | 21 ++- internal/entity/place.go | 54 ++++---- internal/entity/place_fixtures.go | 98 ++++++------- internal/entity/place_fixtures_test.go | 16 +-- internal/entity/place_test.go | 38 +++--- internal/form/photo.go | 6 +- internal/form/photo_search.go | 2 +- internal/form/photo_test.go | 8 +- internal/maps/location.go | 14 -- internal/maps/location_test.go | 2 +- internal/photoprism/index_location.go | 4 +- internal/photoprism/index_mediafile.go | 4 +- internal/photoprism/location.go | 6 +- internal/photoprism/mediafile.go | 2 +- internal/query/geo.go | 4 +- internal/query/moments.go | 6 +- internal/query/photo.go | 16 +-- internal/query/photo_results.go | 14 +- internal/query/photo_results_test.go | 40 +++--- internal/query/photo_search.go | 14 +- internal/query/photo_search_test.go | 6 +- 43 files changed, 452 insertions(+), 476 deletions(-) rename internal/entity/{location.go => geo.go} (59%) rename internal/entity/{location_fixtures.go => geo_fixtures.go} (63%) rename internal/entity/{location_fixtures_test.go => geo_fixtures_test.go} (58%) rename internal/entity/{location_test.go => geo_test.go} (80%) diff --git a/frontend/src/component/photo/list.vue b/frontend/src/component/photo/list.vue index 6dc14000d..e8acd4cc5 100644 --- a/frontend/src/component/photo/list.vue +++ b/frontend/src/component/photo/list.vue @@ -116,7 +116,7 @@ { text: showName ? this.$gettext('Name') : this.$gettext('Location'), class: 'hidden-xs-only', - value: showName ? 'FileName' : 'LocLabel', + value: showName ? 'FileName' : 'GeoLabel', sortable: false }, {text: '', value: '', align: 'center', sortable: false}, diff --git a/frontend/src/dialog/photo/info.vue b/frontend/src/dialog/photo/info.vue index c072eeb5f..862c9b9e4 100644 --- a/frontend/src/dialog/photo/info.vue +++ b/frontend/src/dialog/photo/info.vue @@ -145,7 +145,7 @@ { }); it("should get location", () => { - const values = {ID: 5, Title: "Crazy Cat", LocUID: 6, LocType: "viewpoint", LocLabel: "Cape Point, South Africa", LocCountry: "South Africa"}; + const values = {ID: 5, Title: "Crazy Cat", GeoID: 6, GeoType: "viewpoint", GeoLabel: "Cape Point, South Africa", GeoCountry: "South Africa"}; const photo = new Photo(values); const result = photo.locationInfo(); assert.equal(result, "Cape Point, South Africa"); }); it("should get location", () => { - const values = {ID: 5, Title: "Crazy Cat", LocUID: 6, LocType: "viewpoint", LocLabel: "Cape Point, State, South Africa", LocCountry: "South Africa", LocCity: "Cape Town", LocCounty: "County", LocState: "State"}; + const values = {ID: 5, Title: "Crazy Cat", GeoID: 6, GeoType: "viewpoint", GeoLabel: "Cape Point, State, South Africa", GeoCountry: "South Africa", GeoCity: "Cape Town", GeoCounty: "County", GeoState: "State"}; const photo = new Photo(values); const result = photo.locationInfo(); assert.equal(result, "Cape Point, State, South Africa"); }); it("should get location", () => { - const values = {ID: 5, Title: "Crazy Cat", LocType: "viewpoint", LocName: "Cape Point", LocCountry: "Africa", LocCity: "Cape Town", LocCounty: "County", LocState: "State"}; + const values = {ID: 5, Title: "Crazy Cat", GeoType: "viewpoint", GeoName: "Cape Point", GeoCountry: "Africa", GeoCity: "Cape Town", GeoCounty: "County", GeoState: "State"}; const photo = new Photo(values); const result = photo.locationInfo(); assert.equal(result, "Unknown"); }); it("should get location", () => { - const values = {ID: 5, Title: "Crazy Cat", CountryName: "Africa", LocCity: "Cape Town"}; + const values = {ID: 5, Title: "Crazy Cat", CountryName: "Africa", GeoCity: "Cape Town"}; const photo = new Photo(values); const result = photo.locationInfo(); assert.equal(result, "Unknown"); @@ -425,7 +425,7 @@ describe("model/photo", () => { }); it("should get location info", () => { - const values = {ID: 5, UID: "ABC123", Country: "zz", PlaceID: "zz", LocLabel: "Nice beach"}; + const values = {ID: 5, UID: "ABC123", Country: "zz", PlaceID: "zz", GeoLabel: "Nice beach"}; const photo = new Photo(values); assert.equal(photo.locationInfo(), "Nice beach"); const values2 = {ID: 5, UID: "ABC123", Country: "es", PlaceID: "zz"}; diff --git a/internal/acl/resources.go b/internal/acl/resources.go index 272761d72..ca4538b95 100644 --- a/internal/acl/resources.go +++ b/internal/acl/resources.go @@ -17,7 +17,7 @@ const ( ResourceLabels Resource = "labels" ResourceLenses Resource = "lenses" ResourceLinks Resource = "links" - ResourceLocations Resource = "locations" + ResourceGeo Resource = "geo" ResourcePasswords Resource = "passwords" ResourcePeople Resource = "people" ResourcePhotos Resource = "photos" diff --git a/internal/classify/label.go b/internal/classify/label.go index a3780cf33..efaf48b71 100644 --- a/internal/classify/label.go +++ b/internal/classify/label.go @@ -15,7 +15,7 @@ type Label struct { Categories []string `json:"categories"` // List of similar labels } -// LocationLabel returns a new labels for a location and expects name, uncertainty and priority as arguments. +// LocationLabel returns a new location label. func LocationLabel(name string, uncertainty int, priority int) Label { if index := strings.Index(name, " / "); index > 1 { name = name[:index] diff --git a/internal/config/client.go b/internal/config/client.go index c78a42620..8a1686b2b 100644 --- a/internal/config/client.go +++ b/internal/config/client.go @@ -77,11 +77,11 @@ type CategoryLabel struct { } type ClientPosition struct { - PhotoUID string `json:"uid"` - LocationID string `json:"loc"` - TakenAt time.Time `json:"utc"` - PhotoLat float64 `json:"lat"` - PhotoLng float64 `json:"lng"` + PhotoUID string `json:"uid"` + GeoID string `json:"geo"` + TakenAt time.Time `json:"utc"` + PhotoLat float64 `json:"lat"` + PhotoLng float64 `json:"lng"` } // Flags returns config flags as string slice. @@ -220,7 +220,7 @@ func (c *Config) UserConfig() ClientConfig { } c.Db().Table("photos"). - Select("photo_uid, location_id, photo_lat, photo_lng, taken_at"). + Select("photo_uid, geo_id, photo_lat, photo_lng, taken_at"). Where("deleted_at IS NULL AND photo_lat != 0 AND photo_lng != 0"). Order("taken_at DESC"). Limit(1).Offset(0). diff --git a/internal/entity/entity.go b/internal/entity/entity.go index 7863aa464..89fa6f25a 100644 --- a/internal/entity/entity.go +++ b/internal/entity/entity.go @@ -39,7 +39,7 @@ var Entities = Types{ "photos": &Photo{}, "details": &Details{}, "places": &Place{}, - "locations": &Location{}, + "geo": &Geo{}, "cameras": &Camera{}, "lenses": &Lens{}, "countries": &Country{}, @@ -121,7 +121,7 @@ func (list Types) Drop() { func CreateDefaultFixtures() { CreateDefaultUsers() CreateUnknownPlace() - CreateUnknownLocation() + CreateUnknownGeo() CreateUnknownCountry() CreateUnknownCamera() CreateUnknownLens() diff --git a/internal/entity/fixtures.go b/internal/entity/fixtures.go index 5861eea2b..c9716aa24 100644 --- a/internal/entity/fixtures.go +++ b/internal/entity/fixtures.go @@ -19,7 +19,7 @@ func CreateTestFixtures() { CreateKeywordFixtures() CreatePhotoKeywordFixtures() CreateCategoryFixtures() - CreateLocationFixtures() + CreateGeoFixtures() CreatePlaceFixtures() CreateFileShareFixtures() CreateFileSyncFixtures() diff --git a/internal/entity/location.go b/internal/entity/geo.go similarity index 59% rename from internal/entity/location.go rename to internal/entity/geo.go index 9706be407..2c74df5ff 100644 --- a/internal/entity/location.go +++ b/internal/entity/geo.go @@ -10,36 +10,41 @@ import ( "github.com/photoprism/photoprism/pkg/txt" ) -// Location used to associate photos to location -type Location struct { +// Geo used to associate photos to location +type Geo struct { ID string `gorm:"type:varbinary(42);primary_key;auto_increment:false;" json:"ID" yaml:"ID"` PlaceID string `gorm:"type:varbinary(42);" json:"-" yaml:"PlaceID"` Place *Place `gorm:"PRELOAD:true" json:"Place" yaml:"-"` - LocName string `gorm:"type:varchar(255);" json:"Name" yaml:"Name,omitempty"` - LocCategory string `gorm:"type:varchar(64);" json:"Category" yaml:"Category,omitempty"` - LocSource string `gorm:"type:varbinary(16);" json:"Source" yaml:"Source,omitempty"` + GeoName string `gorm:"type:varchar(255);" json:"Name" yaml:"Name,omitempty"` + GeoCategory string `gorm:"type:varchar(64);" json:"Category" yaml:"Category,omitempty"` + GeoSource string `gorm:"type:varbinary(16);" json:"Source" yaml:"Source,omitempty"` CreatedAt time.Time `json:"CreatedAt" yaml:"-"` UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"` } -// UnknownLocation is PhotoPrism's default location. -var UnknownLocation = Location{ +// TableName return the database table name. +func (Geo) TableName() string { + return "geo" +} + +// UnknownGeo is PhotoPrism's default location. +var UnknownGeo = Geo{ ID: "zz", Place: &UnknownPlace, PlaceID: "zz", - LocName: "", - LocCategory: "", - LocSource: SrcAuto, + GeoName: "", + GeoCategory: "", + GeoSource: SrcAuto, } -// CreateUnknownLocation creates the default location if not exists. -func CreateUnknownLocation() { - FirstOrCreateLocation(&UnknownLocation) +// CreateUnknownGeo creates the default location if not exists. +func CreateUnknownGeo() { + FirstOrCreateGeo(&UnknownGeo) } -// NewLocation creates a location using a token extracted from coordinate -func NewLocation(lat, lng float32) *Location { - result := &Location{} +// NewGeo creates a location using a token extracted from coordinate +func NewGeo(lat, lng float32) *Geo { + result := &Geo{} result.ID = s2.PrefixedToken(float64(lat), float64(lng)) @@ -47,12 +52,12 @@ func NewLocation(lat, lng float32) *Location { } // Find retrieves location data from the database or an external api if not known already. -func (m *Location) Find(api string) error { +func (m *Geo) Find(api string) error { start := time.Now() db := Db() if err := db.Preload("Place").First(m, "id = ?", m.ID).Error; err == nil { - log.Infof("location: found %s (%+v)", m.ID, m) + log.Infof("geo: found %s (%+v)", m.ID, m) return nil } @@ -61,7 +66,7 @@ func (m *Location) Find(api string) error { } if err := l.QueryApi(api); err != nil { - log.Errorf("location: %s failed %s", m.ID, err) + log.Errorf("geo: %s failed %s", m.ID, err) return err } @@ -70,11 +75,11 @@ func (m *Location) Find(api string) error { } else { place := &Place{ ID: l.PrefixedToken(), - LocLabel: l.Label(), - LocCity: l.City(), - LocState: l.State(), - LocCountry: l.CountryCode(), - LocKeywords: l.KeywordString(), + GeoLabel: l.Label(), + GeoCity: l.City(), + GeoState: l.State(), + GeoCountry: l.CountryCode(), + GeoKeywords: l.KeywordString(), PhotoCount: 1, } @@ -95,41 +100,41 @@ func (m *Location) Find(api string) error { } m.PlaceID = m.Place.ID - m.LocName = l.Name() - m.LocCategory = l.Category() - m.LocSource = l.Source() + m.GeoName = l.Name() + m.GeoCategory = l.Category() + m.GeoSource = l.Source() if err := db.Create(m).Error; err == nil { - log.Infof("location: added %s [%s]", m.ID, time.Since(start)) + log.Infof("geo: added %s [%s]", m.ID, time.Since(start)) return nil } else if err := db.Preload("Place").First(m, "id = ?", m.ID).Error; err != nil { - log.Errorf("location: failed adding %s %s [%s]", m.ID, err.Error(), time.Since(start)) + log.Errorf("geo: failed adding %s %s [%s]", m.ID, err.Error(), time.Since(start)) return err } else { - log.Infof("location: found %s after second try [%s]", m.ID, time.Since(start)) + log.Infof("geo: found %s after second try [%s]", m.ID, time.Since(start)) } return nil } // Create inserts a new row to the database. -func (m *Location) Create() error { +func (m *Geo) Create() error { return Db().Create(m).Error } -// FirstOrCreateLocation fetches an existing row, inserts a new row or nil in case of errors. -func FirstOrCreateLocation(m *Location) *Location { +// FirstOrCreateGeo fetches an existing row, inserts a new row or nil in case of errors. +func FirstOrCreateGeo(m *Geo) *Geo { if m.ID == "" { - log.Errorf("location: id must not be empty") + log.Errorf("geo: id must not be empty") return nil } if m.PlaceID == "" { - log.Errorf("location: place_id must not be empty (first or create %s)", m.ID) + log.Errorf("geo: place_id must not be empty (first or create %s)", m.ID) return nil } - result := Location{} + result := Geo{} if findErr := Db().Where("id = ?", m.ID).First(&result).Error; findErr == nil { return &result @@ -138,16 +143,16 @@ func FirstOrCreateLocation(m *Location) *Location { } else if err := Db().Where("id = ?", m.ID).First(&result).Error; err == nil { return &result } else { - log.Errorf("location: %s (first or create %s)", createErr, m.ID) + log.Errorf("geo: %s (first or create %s)", createErr, m.ID) } return nil } // Keywords returns search keywords for a location. -func (m *Location) Keywords() (result []string) { +func (m *Geo) Keywords() (result []string) { if m.Place == nil { - log.Errorf("location: place for %s is nil - you might have found a bug", m.ID) + log.Errorf("geo: place for %s is nil - you might have found a bug", m.ID) return result } @@ -156,7 +161,7 @@ func (m *Location) Keywords() (result []string) { result = append(result, txt.Keywords(txt.ReplaceSpaces(m.CountryName(), "-"))...) result = append(result, txt.Keywords(m.Category())...) result = append(result, txt.Keywords(m.Name())...) - result = append(result, txt.Keywords(m.Place.LocKeywords)...) + result = append(result, txt.Keywords(m.Place.GeoKeywords)...) result = txt.UniqueWords(result) @@ -164,81 +169,81 @@ func (m *Location) Keywords() (result []string) { } // Unknown checks if the location has no id -func (m *Location) Unknown() bool { - return m.ID == "" || m.ID == UnknownLocation.ID +func (m *Geo) Unknown() bool { + return m.ID == "" || m.ID == UnknownGeo.ID } // Name returns name of location -func (m *Location) Name() string { - return m.LocName +func (m *Geo) Name() string { + return m.GeoName } // NoName checks if the location has no name -func (m *Location) NoName() bool { - return m.LocName == "" +func (m *Geo) NoName() bool { + return m.GeoName == "" } // Category returns the location category -func (m *Location) Category() string { - return m.LocCategory +func (m *Geo) Category() string { + return m.GeoCategory } // NoCategory checks id the location has no category -func (m *Location) NoCategory() bool { - return m.LocCategory == "" +func (m *Geo) NoCategory() bool { + return m.GeoCategory == "" } // Label returns the location place label -func (m *Location) Label() string { +func (m *Geo) Label() string { return m.Place.Label() } // City returns the location place city -func (m *Location) City() string { +func (m *Geo) City() string { return m.Place.City() } // LongCity checks if the city name is more than 16 char -func (m *Location) LongCity() bool { +func (m *Geo) LongCity() bool { return len(m.City()) > 16 } // NoCity checks if the location has no city -func (m *Location) NoCity() bool { +func (m *Geo) NoCity() bool { return m.City() == "" } // CityContains checks if the location city contains the text string -func (m *Location) CityContains(text string) bool { +func (m *Geo) CityContains(text string) bool { return strings.Contains(text, m.City()) } // State returns the location place state -func (m *Location) State() string { +func (m *Geo) State() string { return m.Place.State() } // NoState checks if the location place has no state -func (m *Location) NoState() bool { +func (m *Geo) NoState() bool { return m.Place.State() == "" } // CountryCode returns the location place country code -func (m *Location) CountryCode() string { +func (m *Geo) CountryCode() string { return m.Place.CountryCode() } // CountryName returns the location place country name -func (m *Location) CountryName() string { +func (m *Geo) CountryName() string { return m.Place.CountryName() } // Notes returns the locations place notes -func (m *Location) Notes() string { +func (m *Geo) Notes() string { return m.Place.Notes() } // Source returns the source of location information -func (m *Location) Source() string { - return m.LocSource +func (m *Geo) Source() string { + return m.GeoSource } diff --git a/internal/entity/location_fixtures.go b/internal/entity/geo_fixtures.go similarity index 63% rename from internal/entity/location_fixtures.go rename to internal/entity/geo_fixtures.go index 12ba98f2c..27b43db18 100644 --- a/internal/entity/location_fixtures.go +++ b/internal/entity/geo_fixtures.go @@ -4,32 +4,32 @@ import ( "github.com/photoprism/photoprism/pkg/s2" ) -type LocationMap map[string]Location +type GeoMap map[string]Geo -func (m LocationMap) Get(name string) Location { +func (m GeoMap) Get(name string) Geo { if result, ok := m[name]; ok { return result } - return UnknownLocation + return UnknownGeo } -func (m LocationMap) Pointer(name string) *Location { +func (m GeoMap) Pointer(name string) *Geo { if result, ok := m[name]; ok { return &result } - return &UnknownLocation + return &UnknownGeo } -var LocationFixtures = LocationMap{ +var GeoFixtures = GeoMap{ "mexico": { ID: s2.TokenPrefix + "85d1ea7d382c", PlaceID: PlaceFixtures.Get("mexico").ID, - LocName: "Adosada Platform", - LocCategory: "botanical garden", + GeoName: "Adosada Platform", + GeoCategory: "botanical garden", Place: PlaceFixtures.Pointer("mexico"), - LocSource: "places", + GeoSource: "places", CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, @@ -38,16 +38,16 @@ var LocationFixtures = LocationMap{ PlaceID: s2.TokenPrefix + "1ef75a71a36c", Place: &Place{ ID: s2.TokenPrefix + "1ef75a71a36", - LocLabel: "Mandeni, KwaZulu-Natal, South Africa", - LocCity: "Mandeni", - LocState: "KwaZulu-Natal", - LocCountry: "za", + GeoLabel: "Mandeni, KwaZulu-Natal, South Africa", + GeoCity: "Mandeni", + GeoState: "KwaZulu-Natal", + GeoCountry: "za", CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, - LocName: "Lobotes Caravan Park", - LocCategory: "camping", - LocSource: "manual", + GeoName: "Lobotes Caravan Park", + GeoCategory: "camping", + GeoSource: "manual", CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, @@ -55,9 +55,9 @@ var LocationFixtures = LocationMap{ ID: s2.TokenPrefix + "1ef744d1e28c", PlaceID: PlaceFixtures.Get("zinkwazi").ID, Place: PlaceFixtures.Pointer("zinkwazi"), - LocName: "Zinkwazi Beach", - LocCategory: "beach", - LocSource: "places", + GeoName: "Zinkwazi Beach", + GeoCategory: "beach", + GeoSource: "places", CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, @@ -65,9 +65,9 @@ var LocationFixtures = LocationMap{ ID: s2.TokenPrefix + "1ef744d1e280", PlaceID: PlaceFixtures.Get("holidaypark").ID, Place: PlaceFixtures.Pointer("holidaypark"), - LocName: "Holiday Park", - LocCategory: "park", - LocSource: "places", + GeoName: "Holiday Park", + GeoCategory: "park", + GeoSource: "places", CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, @@ -75,9 +75,9 @@ var LocationFixtures = LocationMap{ ID: s2.TokenPrefix + "1ef744d1e281", PlaceID: PlaceFixtures.Get("emptyNameLongCity").ID, Place: PlaceFixtures.Pointer("emptyNameLongCity"), - LocName: "", - LocCategory: "botanical garden", - LocSource: "places", + GeoName: "", + GeoCategory: "botanical garden", + GeoSource: "places", CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, @@ -85,9 +85,9 @@ var LocationFixtures = LocationMap{ ID: s2.TokenPrefix + "1ef744d1e282", PlaceID: PlaceFixtures.Get("emptyNameShortCity").ID, Place: PlaceFixtures.Pointer("emptyNameShortCity"), - LocName: "", - LocCategory: "botanical garden", - LocSource: "places", + GeoName: "", + GeoCategory: "botanical garden", + GeoSource: "places", CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, @@ -95,9 +95,9 @@ var LocationFixtures = LocationMap{ ID: s2.TokenPrefix + "1ef744d1e283", PlaceID: PlaceFixtures.Get("veryLongLocName").ID, Place: PlaceFixtures.Pointer("veryLongLocName"), - LocName: "longlonglonglonglonglonglonglonglonglonglonglonglongName", - LocCategory: "cape", - LocSource: "places", + GeoName: "longlonglonglonglonglonglonglonglonglonglonglonglongName", + GeoCategory: "cape", + GeoSource: "places", CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, @@ -105,17 +105,17 @@ var LocationFixtures = LocationMap{ ID: s2.TokenPrefix + "1ef744d1e283", PlaceID: PlaceFixtures.Get("mediumLongLocName").ID, Place: PlaceFixtures.Pointer("mediumLongLocName"), - LocName: "longlonglonglonglonglongName", - LocCategory: "botanical garden", - LocSource: "places", + GeoName: "longlonglonglonglonglongName", + GeoCategory: "botanical garden", + GeoSource: "places", CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, } -// CreateLocationFixtures inserts known entities into the database for testing. -func CreateLocationFixtures() { - for _, entity := range LocationFixtures { +// CreateGeoFixtures inserts known entities into the database for testing. +func CreateGeoFixtures() { + for _, entity := range GeoFixtures { Db().Create(&entity) } } diff --git a/internal/entity/location_fixtures_test.go b/internal/entity/geo_fixtures_test.go similarity index 58% rename from internal/entity/location_fixtures_test.go rename to internal/entity/geo_fixtures_test.go index 1bd0bebbc..3f479c1bc 100644 --- a/internal/entity/location_fixtures_test.go +++ b/internal/entity/geo_fixtures_test.go @@ -7,28 +7,28 @@ import ( func TestLocationMap_Get(t *testing.T) { t.Run("get existing location", func(t *testing.T) { - r := LocationFixtures.Get("mexico") - assert.Equal(t, "Adosada Platform", r.LocName) + r := GeoFixtures.Get("mexico") + assert.Equal(t, "Adosada Platform", r.GeoName) assert.Equal(t, "s2:85d1ea7d382c", r.ID) - assert.IsType(t, Location{}, r) + assert.IsType(t, Geo{}, r) }) t.Run("get not existing location", func(t *testing.T) { - r := LocationFixtures.Get("Fusion 3333") + r := GeoFixtures.Get("Fusion 3333") assert.Equal(t, "zz", r.ID) - assert.IsType(t, Location{}, r) + assert.IsType(t, Geo{}, r) }) } func TestLocationMap_Pointer(t *testing.T) { t.Run("get existing location pointer", func(t *testing.T) { - r := LocationFixtures.Pointer("mexico") - assert.Equal(t, "Adosada Platform", r.LocName) + r := GeoFixtures.Pointer("mexico") + assert.Equal(t, "Adosada Platform", r.GeoName) assert.Equal(t, "s2:85d1ea7d382c", r.ID) - assert.IsType(t, &Location{}, r) + assert.IsType(t, &Geo{}, r) }) t.Run("get not existing location pointer", func(t *testing.T) { - r := LocationFixtures.Pointer("Fusion 444") + r := GeoFixtures.Pointer("Fusion 444") assert.Equal(t, "zz", r.ID) - assert.IsType(t, &Location{}, r) + assert.IsType(t, &Geo{}, r) }) } diff --git a/internal/entity/location_test.go b/internal/entity/geo_test.go similarity index 80% rename from internal/entity/location_test.go rename to internal/entity/geo_test.go index 871355e23..39b5b9630 100644 --- a/internal/entity/location_test.go +++ b/internal/entity/geo_test.go @@ -8,11 +8,11 @@ import ( func TestNewLocation(t *testing.T) { t.Run("new label", func(t *testing.T) { - l := NewLocation(1, 1) - l.LocCategory = "restaurant" - l.LocName = "LocationName" + l := NewGeo(1, 1) + l.GeoCategory = "restaurant" + l.GeoName = "LocationName" l.Place = PlaceFixtures.Pointer("zinkwazi") - l.LocSource = "places" + l.GeoSource = "places" assert.Equal(t, "restaurant", l.Category()) assert.Equal(t, false, l.NoCategory()) @@ -35,17 +35,17 @@ func TestNewLocation(t *testing.T) { func TestLocation_Keywords(t *testing.T) { t.Run("mexico", func(t *testing.T) { - m := LocationFixtures["mexico"] + m := GeoFixtures["mexico"] r := m.Keywords() assert.Equal(t, []string{"adosada", "ancient", "botanical", "garden", "mexico", "platform", "pyramid", "state-of-mexico", "teotihuacán"}, r) }) t.Run("caravan park", func(t *testing.T) { - m := LocationFixtures["caravan park"] + m := GeoFixtures["caravan park"] r := m.Keywords() assert.Equal(t, []string{"camping", "caravan", "kwazulu-natal", "lobotes", "mandeni", "park", "south-africa"}, r) }) t.Run("place id empty", func(t *testing.T) { - m := &Location{} + m := &Geo{} r := m.Keywords() assert.Empty(t, r) }) @@ -53,12 +53,12 @@ func TestLocation_Keywords(t *testing.T) { func TestLocation_Find(t *testing.T) { t.Run("place in db", func(t *testing.T) { - m := LocationFixtures["mexico"] + m := GeoFixtures["mexico"] r := m.Find("") assert.Nil(t, r) }) t.Run("invalid api", func(t *testing.T) { - l := NewLocation(2, 1) + l := NewGeo(2, 1) err := l.Find("") if err == nil { @@ -71,19 +71,19 @@ func TestLocation_Find(t *testing.T) { func TestFirstOrCreateLocation(t *testing.T) { t.Run("id empty", func(t *testing.T) { - loc := &Location{} + loc := &Geo{} - assert.Nil(t, FirstOrCreateLocation(loc)) + assert.Nil(t, FirstOrCreateGeo(loc)) }) t.Run("place id empty", func(t *testing.T) { - loc := &Location{ID: "1234jhy"} + loc := &Geo{ID: "1234jhy"} - assert.Nil(t, FirstOrCreateLocation(loc)) + assert.Nil(t, FirstOrCreateGeo(loc)) }) t.Run("success", func(t *testing.T) { - loc := LocationFixtures.Pointer("caravan park") + loc := GeoFixtures.Pointer("caravan park") - result := FirstOrCreateLocation(loc) + result := FirstOrCreateGeo(loc) if result == nil { t.Fatal("result should not be nil") diff --git a/internal/entity/photo.go b/internal/entity/photo.go index b3ec7b769..9a4a48ef1 100644 --- a/internal/entity/photo.go +++ b/internal/entity/photo.go @@ -51,9 +51,9 @@ type Photo struct { PhotoScan bool `json:"Scan" yaml:"Scan,omitempty"` TimeZone string `gorm:"type:varbinary(64);" json:"TimeZone" yaml:"-"` PlaceID string `gorm:"type:varbinary(42);index;" json:"PlaceID" yaml:"-"` - LocationID string `gorm:"type:varbinary(42);index;" json:"LocationID" yaml:"-"` - LocationSrc string `gorm:"type:varbinary(8);" json:"LocationSrc" yaml:"LocationSrc,omitempty"` - GPSAccuracy int `gorm:"column:gps_accuracy" json:"GPSAccuracy" yaml:"GPSAccuracy,omitempty"` + GeoID string `gorm:"type:varbinary(42);index;" json:"GeoID" yaml:"-"` + GeoSrc string `gorm:"type:varbinary(8);" json:"GeoSrc" yaml:"GeoSrc,omitempty"` + GeoAccuracy int `json:"GeoAccuracy" yaml:"GeoAccuracy,omitempty"` PhotoAltitude int `json:"Altitude" yaml:"Altitude,omitempty"` PhotoLat float32 `gorm:"type:FLOAT;index;" json:"Lat" yaml:"Lat,omitempty"` PhotoLng float32 `gorm:"type:FLOAT;index;" json:"Lng" yaml:"Lng,omitempty"` @@ -74,7 +74,7 @@ type Photo struct { Details *Details `gorm:"association_autoupdate:false;association_autocreate:false;association_save_reference:false" json:"Details" yaml:"Details"` Camera *Camera `gorm:"association_autoupdate:false;association_autocreate:false;association_save_reference:false" json:"Camera" yaml:"-"` Lens *Lens `gorm:"association_autoupdate:false;association_autocreate:false;association_save_reference:false" json:"Lens" yaml:"-"` - Location *Location `gorm:"association_autoupdate:false;association_autocreate:false;association_save_reference:false" json:"Location" yaml:"-"` + Geo *Geo `gorm:"association_autoupdate:false;association_autocreate:false;association_save_reference:false" json:"Geo" yaml:"-"` Place *Place `gorm:"association_autoupdate:false;association_autocreate:false;association_save_reference:false" json:"Place" yaml:"-"` Keywords []Keyword `json:"-" yaml:"-"` Albums []Album `json:"-" yaml:"-"` @@ -94,11 +94,11 @@ func NewPhoto() Photo { PhotoCountry: UnknownCountry.ID, CameraID: UnknownCamera.ID, LensID: UnknownLens.ID, - LocationID: UnknownLocation.ID, + GeoID: UnknownGeo.ID, PlaceID: UnknownPlace.ID, Camera: &UnknownCamera, Lens: &UnknownLens, - Location: &UnknownLocation, + Geo: &UnknownGeo, Place: &UnknownPlace, } } @@ -127,7 +127,7 @@ func SavePhotoForm(model Photo, form form.Photo, geoApi string) error { details.Keywords = strings.Join(txt.UniqueWords(txt.Words(details.Keywords)), ", ") } - if locChanged && model.LocationSrc == SrcManual { + if locChanged && model.GeoSrc == SrcManual { locKeywords, labels := model.UpdateLocation(geoApi) model.AddLabels(labels) @@ -238,8 +238,8 @@ func (m *Photo) Find() error { Preload("Lens"). Preload("Details"). Preload("Place"). - Preload("Location"). - Preload("Location.Place") + Preload("Geo"). + Preload("Geo.Place") if rnd.IsPPID(m.PhotoUID, 'p') { if err := q.First(m, "photo_uid = ?", m.PhotoUID).Error; err != nil { @@ -469,9 +469,9 @@ func (m *Photo) HasID() bool { return m.ID > 0 && m.PhotoUID != "" } -// UnknownLocation checks if the photo has an unknown location. +// UnknownGeo checks if the photo has an unknown location. func (m *Photo) UnknownLocation() bool { - return m.LocationID == "" || m.LocationID == UnknownLocation.ID + return m.GeoID == "" || m.GeoID == UnknownGeo.ID } // HasLocation checks if the photo has a known location. @@ -481,15 +481,15 @@ func (m *Photo) HasLocation() bool { // LocationLoaded checks if the photo has a known location that is currently loaded. func (m *Photo) LocationLoaded() bool { - if m.Location == nil { + if m.Geo == nil { return false } - if m.Location.Place == nil { + if m.Geo.Place == nil { return false } - return !m.Location.Unknown() && m.Location.ID == m.LocationID + return !m.Geo.Unknown() && m.Geo.ID == m.GeoID } // LoadLocation loads the photo location from the database if not done already. @@ -502,9 +502,9 @@ func (m *Photo) LoadLocation() error { return fmt.Errorf("photo: unknown location (%s)", m) } - var location Location + var location Geo - err := Db().Preload("Place").First(&location, "id = ?", m.LocationID).Error + err := Db().Preload("Place").First(&location, "id = ?", m.GeoID).Error if err != nil { return err @@ -515,7 +515,7 @@ func (m *Photo) LoadLocation() error { location.PlaceID = UnknownPlace.ID } - m.Location = &location + m.Geo = &location return nil } @@ -670,7 +670,7 @@ func (m *Photo) UpdateTitle(labels classify.Labels) error { if m.LocationLoaded() { knownLocation = true - loc := m.Location + loc := m.Geo // TODO: User defined title format if title := labels.Title(loc.Name()); title != "" { @@ -865,14 +865,14 @@ func (m *Photo) SetCoordinates(lat, lng float32, altitude int, source string) { return } - if m.LocationSrc != SrcAuto && m.LocationSrc != source && source != SrcManual { + if m.GeoSrc != SrcAuto && m.GeoSrc != source && source != SrcManual { return } m.PhotoLat = lat m.PhotoLng = lng m.PhotoAltitude = altitude - m.LocationSrc = source + m.GeoSrc = source } // AllFilesMissing returns true, if all files for this photo are missing. diff --git a/internal/entity/photo_fixtures.go b/internal/entity/photo_fixtures.go index 82d69de3f..283ce0162 100644 --- a/internal/entity/photo_fixtures.go +++ b/internal/entity/photo_fixtures.go @@ -54,14 +54,14 @@ var PhotoFixtures = PhotoMap{ LensID: LensFixtures.Pointer("lens-f-380").ID, CameraSerial: "", CameraSrc: "", - LocationSrc: "", + GeoSrc: "", TimeZone: "", PhotoYear: 2790, PhotoMonth: 2, Details: DetailsFixtures.Pointer("lake", 1000000), DescriptionSrc: "", - LocationID: UnknownLocation.ID, - Location: &UnknownLocation, + GeoID: UnknownGeo.ID, + Geo: &UnknownGeo, PlaceID: UnknownPlace.ID, Place: &UnknownPlace, PhotoCountry: UnknownPlace.CountryCode(), @@ -111,9 +111,9 @@ var PhotoFixtures = PhotoMap{ CameraSrc: "", Place: &UnknownPlace, PlaceID: UnknownPlace.ID, - Location: &UnknownLocation, - LocationID: UnknownLocation.ID, - LocationSrc: "", + Geo: &UnknownGeo, + GeoID: UnknownGeo.ID, + GeoSrc: "", TimeZone: "", PhotoCountry: UnknownPlace.CountryCode(), PhotoYear: 2790, @@ -154,7 +154,7 @@ var PhotoFixtures = PhotoMap{ PhotoExposure: "", CameraSerial: "", CameraSrc: "", - LocationSrc: "", + GeoSrc: "", TimeZone: "", PhotoCountry: UnknownPlace.CountryCode(), PhotoYear: 1990, @@ -165,8 +165,8 @@ var PhotoFixtures = PhotoMap{ CameraID: CameraFixtures.Pointer("canon-eos-6d").ID, Lens: LensFixtures.Pointer("lens-f-380"), LensID: LensFixtures.Pointer("lens-f-380").ID, - Location: &UnknownLocation, - LocationID: UnknownLocation.ID, + Geo: &UnknownGeo, + GeoID: UnknownGeo.ID, Place: &UnknownPlace, PlaceID: UnknownPlace.ID, Keywords: []Keyword{}, @@ -202,13 +202,13 @@ var PhotoFixtures = PhotoMap{ PhotoExposure: "", CameraSerial: "", CameraSrc: "", - Place: LocationFixtures.Pointer("caravan park").Place, - PlaceID: LocationFixtures.Pointer("caravan park").Place.ID, - Location: LocationFixtures.Pointer("caravan park"), - LocationID: LocationFixtures.Pointer("caravan park").ID, - LocationSrc: "", + Place: GeoFixtures.Pointer("caravan park").Place, + PlaceID: GeoFixtures.Pointer("caravan park").Place.ID, + Geo: GeoFixtures.Pointer("caravan park"), + GeoID: GeoFixtures.Pointer("caravan park").ID, + GeoSrc: "", TimeZone: "", - PhotoCountry: LocationFixtures.Pointer("caravan park").Place.CountryCode(), + PhotoCountry: GeoFixtures.Pointer("caravan park").Place.CountryCode(), PhotoYear: 1990, PhotoMonth: 4, Details: DetailsFixtures.Pointer("bridge", 1000003), @@ -256,9 +256,9 @@ var PhotoFixtures = PhotoMap{ CameraSrc: "", Place: PlaceFixtures.Pointer("mexico"), PlaceID: PlaceFixtures.Pointer("mexico").ID, - Location: LocationFixtures.Pointer("mexico"), - LocationID: LocationFixtures.Pointer("mexico").ID, - LocationSrc: "", + Geo: GeoFixtures.Pointer("mexico"), + GeoID: GeoFixtures.Pointer("mexico").ID, + GeoSrc: "", TimeZone: "", PhotoCountry: PlaceFixtures.Pointer("mexico").CountryCode(), PhotoYear: 2014, @@ -306,9 +306,9 @@ var PhotoFixtures = PhotoMap{ PhotoExposure: "", CameraSerial: "123", CameraSrc: "", - Location: LocationFixtures.Pointer("mexico"), - LocationID: LocationFixtures.Pointer("mexico").ID, - LocationSrc: "", + Geo: GeoFixtures.Pointer("mexico"), + GeoID: GeoFixtures.Pointer("mexico").ID, + GeoSrc: "", Place: PlaceFixtures.Pointer("mexico"), PlaceID: PlaceFixtures.Pointer("mexico").ID, TimeZone: "", @@ -354,9 +354,9 @@ var PhotoFixtures = PhotoMap{ PhotoExposure: "", CameraSerial: "", CameraSrc: "", - Location: &UnknownLocation, - LocationID: UnknownLocation.ID, - LocationSrc: "", + Geo: &UnknownGeo, + GeoID: UnknownGeo.ID, + GeoSrc: "", Place: &UnknownPlace, PlaceID: UnknownPlace.ID, TimeZone: "", @@ -402,9 +402,9 @@ var PhotoFixtures = PhotoMap{ PhotoExposure: "", CameraSerial: "", CameraSrc: "", - Location: &UnknownLocation, - LocationID: UnknownLocation.ID, - LocationSrc: "", + Geo: &UnknownGeo, + GeoID: UnknownGeo.ID, + GeoSrc: "", Place: &UnknownPlace, PlaceID: UnknownPlace.ID, TimeZone: "", @@ -460,9 +460,9 @@ var PhotoFixtures = PhotoMap{ CameraID: CameraFixtures.Pointer("canon-eos-6d").ID, Lens: LensFixtures.Pointer("lens-f-380"), LensID: LensFixtures.Pointer("lens-f-380").ID, - Location: LocationFixtures.Pointer("mexico"), - LocationID: LocationFixtures.Pointer("mexico").ID, - LocationSrc: "manual", + Geo: GeoFixtures.Pointer("mexico"), + GeoID: GeoFixtures.Pointer("mexico").ID, + GeoSrc: "manual", Place: PlaceFixtures.Pointer("mexico"), PlaceID: PlaceFixtures.Pointer("mexico").ID, Keywords: []Keyword{}, @@ -508,9 +508,9 @@ var PhotoFixtures = PhotoMap{ CameraID: CameraFixtures.Pointer("canon-eos-6d").ID, Lens: LensFixtures.Pointer("lens-f-380"), LensID: LensFixtures.Pointer("lens-f-380").ID, - Location: LocationFixtures.Pointer("mexico"), - LocationID: LocationFixtures.Pointer("mexico").ID, - LocationSrc: "", + Geo: GeoFixtures.Pointer("mexico"), + GeoID: GeoFixtures.Pointer("mexico").ID, + GeoSrc: "", Place: PlaceFixtures.Pointer("mexico"), PlaceID: PlaceFixtures.Pointer("mexico").ID, Keywords: []Keyword{}, @@ -556,9 +556,9 @@ var PhotoFixtures = PhotoMap{ CameraID: CameraFixtures.Pointer("canon-eos-6d").ID, Lens: LensFixtures.Pointer("lens-f-380"), LensID: LensFixtures.Pointer("lens-f-380").ID, - Location: LocationFixtures.Pointer("hassloch"), - LocationID: LocationFixtures.Pointer("hassloch").ID, - LocationSrc: "", + Geo: GeoFixtures.Pointer("hassloch"), + GeoID: GeoFixtures.Pointer("hassloch").ID, + GeoSrc: "", Place: PlaceFixtures.Pointer("holidaypark"), PlaceID: PlaceFixtures.Pointer("holidaypark").ID, Keywords: []Keyword{}, @@ -604,9 +604,9 @@ var PhotoFixtures = PhotoMap{ CameraID: CameraFixtures.Pointer("canon-eos-6d").ID, Lens: LensFixtures.Pointer("lens-f-380"), LensID: LensFixtures.Pointer("lens-f-380").ID, - Location: LocationFixtures.Pointer("emptyNameLongCity"), - LocationID: LocationFixtures.Pointer("emptyNameLongCity").ID, - LocationSrc: "", + Geo: GeoFixtures.Pointer("emptyNameLongCity"), + GeoID: GeoFixtures.Pointer("emptyNameLongCity").ID, + GeoSrc: "", Place: PlaceFixtures.Pointer("emptyNameLongCity"), PlaceID: PlaceFixtures.Pointer("emptyNameLongCity").ID, Keywords: []Keyword{}, @@ -646,9 +646,9 @@ var PhotoFixtures = PhotoMap{ LensID: LensFixtures.Pointer("lens-f-380").ID, CameraSerial: "", CameraSrc: "", - Location: LocationFixtures.Pointer("emptyNameShortCity"), - LocationID: LocationFixtures.Pointer("emptyNameShortCity").ID, - LocationSrc: "", + Geo: GeoFixtures.Pointer("emptyNameShortCity"), + GeoID: GeoFixtures.Pointer("emptyNameShortCity").ID, + GeoSrc: "", Place: PlaceFixtures.Pointer("emptyNameShortCity"), PlaceID: PlaceFixtures.Pointer("emptyNameShortCity").ID, TimeZone: "", @@ -690,9 +690,9 @@ var PhotoFixtures = PhotoMap{ PhotoExposure: "", CameraSerial: "", CameraSrc: "", - Location: LocationFixtures.Pointer("veryLongLocName"), - LocationID: LocationFixtures.Pointer("veryLongLocName").ID, - LocationSrc: "", + Geo: GeoFixtures.Pointer("veryLongLocName"), + GeoID: GeoFixtures.Pointer("veryLongLocName").ID, + GeoSrc: "", Place: PlaceFixtures.Pointer("veryLongLocName"), PlaceID: PlaceFixtures.Pointer("veryLongLocName").ID, TimeZone: "", @@ -748,9 +748,9 @@ var PhotoFixtures = PhotoMap{ CameraID: CameraFixtures.Pointer("canon-eos-6d").ID, Lens: LensFixtures.Pointer("lens-f-380"), LensID: LensFixtures.Pointer("lens-f-380").ID, - Location: LocationFixtures.Pointer("mediumLongLocName"), - LocationID: LocationFixtures.Pointer("mediumLongLocName").ID, - LocationSrc: "", + Geo: GeoFixtures.Pointer("mediumLongLocName"), + GeoID: GeoFixtures.Pointer("mediumLongLocName").ID, + GeoSrc: "", Place: PlaceFixtures.Pointer("mediumLongLocName"), PlaceID: PlaceFixtures.Pointer("mediumLongLocName").ID, Keywords: []Keyword{}, @@ -788,10 +788,10 @@ var PhotoFixtures = PhotoMap{ CameraSerial: "", CameraSrc: "", Place: &UnknownPlace, - Location: &UnknownLocation, + Geo: &UnknownGeo, PlaceID: UnknownPlace.ID, - LocationID: UnknownLocation.ID, - LocationSrc: "location", + GeoID: UnknownGeo.ID, + GeoSrc: "location", TimeZone: "", PhotoCountry: UnknownCountry.ID, PhotoYear: 0, @@ -840,10 +840,10 @@ var PhotoFixtures = PhotoMap{ CameraSerial: "", CameraSrc: "", Place: &UnknownPlace, - Location: &UnknownLocation, + Geo: &UnknownGeo, PlaceID: UnknownPlace.ID, - LocationID: UnknownLocation.ID, - LocationSrc: "location", + GeoID: UnknownGeo.ID, + GeoSrc: "location", TimeZone: "", PhotoCountry: UnknownCountry.ID, PhotoYear: 0, @@ -887,9 +887,9 @@ var PhotoFixtures = PhotoMap{ CameraID: CameraFixtures.Pointer("canon-eos-6d").ID, Lens: LensFixtures.Pointer("lens-f-380"), LensID: LensFixtures.Pointer("lens-f-380").ID, - Location: LocationFixtures.Pointer("mexico"), - LocationID: LocationFixtures.Pointer("mexico").ID, - LocationSrc: "location", + Geo: GeoFixtures.Pointer("mexico"), + GeoID: GeoFixtures.Pointer("mexico").ID, + GeoSrc: "location", Place: PlaceFixtures.Pointer("mexico"), PlaceID: PlaceFixtures.Pointer("mexico").ID, TimeZone: "", @@ -937,9 +937,9 @@ var PhotoFixtures = PhotoMap{ CameraID: CameraFixtures.Pointer("canon-eos-6d").ID, Lens: LensFixtures.Pointer("lens-f-380"), LensID: LensFixtures.Pointer("lens-f-380").ID, - Location: LocationFixtures.Pointer("mexico"), - LocationID: LocationFixtures.Pointer("mexico").ID, - LocationSrc: "location", + Geo: GeoFixtures.Pointer("mexico"), + GeoID: GeoFixtures.Pointer("mexico").ID, + GeoSrc: "location", Place: PlaceFixtures.Pointer("mexico"), PlaceID: PlaceFixtures.Pointer("mexico").ID, TimeZone: "", @@ -984,10 +984,10 @@ var PhotoFixtures = PhotoMap{ CameraSerial: "", CameraSrc: "", Place: &UnknownPlace, - Location: &UnknownLocation, + Geo: &UnknownGeo, PlaceID: UnknownPlace.ID, - LocationID: UnknownLocation.ID, - LocationSrc: "", + GeoID: UnknownGeo.ID, + GeoSrc: "", TimeZone: "", PhotoCountry: UnknownPlace.CountryCode(), PhotoYear: 1990, diff --git a/internal/entity/photo_location.go b/internal/entity/photo_location.go index 0308ca611..e80aa201f 100644 --- a/internal/entity/photo_location.go +++ b/internal/entity/photo_location.go @@ -62,7 +62,7 @@ func (m *Photo) GetTakenAt() time.Time { // UpdateLocation updates location and labels based on latitude and longitude. func (m *Photo) UpdateLocation(geoApi string) (keywords []string, labels classify.Labels) { if m.HasLatLng() { - var location = NewLocation(m.PhotoLat, m.PhotoLng) + var location = NewGeo(m.PhotoLat, m.PhotoLng) err := location.Find(geoApi) @@ -70,9 +70,9 @@ func (m *Photo) UpdateLocation(geoApi string) (keywords []string, labels classif log.Warnf("photo: location place is nil (uid %s, location %s) - bug?", m.PhotoUID, location.ID) } - if err == nil && location.Place != nil && location.ID != UnknownLocation.ID { - m.Location = location - m.LocationID = location.ID + if err == nil && location.Place != nil && location.ID != UnknownGeo.ID { + m.Geo = location + m.GeoID = location.ID m.Place = location.Place m.PlaceID = location.PlaceID m.PhotoCountry = location.CountryCode() @@ -100,11 +100,11 @@ func (m *Photo) UpdateLocation(geoApi string) (keywords []string, labels classif labels = classify.Labels{} if m.UnknownLocation() { - m.Location = &UnknownLocation - m.LocationID = UnknownLocation.ID + m.Geo = &UnknownGeo + m.GeoID = UnknownGeo.ID } else if err := m.LoadLocation(); err == nil { - m.Place = m.Location.Place - m.PlaceID = m.Location.PlaceID + m.Place = m.Geo.Place + m.PlaceID = m.Geo.PlaceID } else { log.Warn(err) } diff --git a/internal/entity/photo_optimize.go b/internal/entity/photo_optimize.go index ec7937b6c..d92421684 100644 --- a/internal/entity/photo_optimize.go +++ b/internal/entity/photo_optimize.go @@ -13,7 +13,7 @@ import ( // EstimateCountry updates the photo with an estimated country if possible. func (m *Photo) EstimateCountry() { - if m.HasLatLng() || m.HasLocation() || m.HasPlace() || m.HasCountry() && m.LocationSrc != SrcAuto && m.LocationSrc != SrcEstimate { + if m.HasLatLng() || m.HasLocation() || m.HasPlace() || m.HasCountry() && m.GeoSrc != SrcAuto && m.GeoSrc != SrcEstimate { // Do nothing. return } @@ -41,14 +41,14 @@ func (m *Photo) EstimateCountry() { if countryCode != unknown { m.PhotoCountry = countryCode - m.LocationSrc = SrcEstimate + m.GeoSrc = SrcEstimate log.Debugf("photo: probable country for %s is %s", m, txt.Quote(m.CountryName())) } } // EstimatePlace updates the photo with an estimated place and country if possible. func (m *Photo) EstimatePlace() { - if m.HasLatLng() || m.HasLocation() || m.HasPlace() && m.LocationSrc != SrcAuto && m.LocationSrc != SrcEstimate { + if m.HasLatLng() || m.HasLocation() || m.HasPlace() && m.GeoSrc != SrcAuto && m.GeoSrc != SrcEstimate { // Do nothing. return } @@ -79,11 +79,11 @@ func (m *Photo) EstimatePlace() { m.Place = recentPhoto.Place m.PlaceID = recentPhoto.PlaceID m.PhotoCountry = recentPhoto.PhotoCountry - m.LocationSrc = SrcEstimate + m.GeoSrc = SrcEstimate log.Debugf("photo: approximate position of %s is %s (id %s)", m, txt.Quote(m.CountryName()), recentPhoto.PlaceID) } else if recentPhoto.HasCountry() { m.PhotoCountry = recentPhoto.PhotoCountry - m.LocationSrc = SrcEstimate + m.GeoSrc = SrcEstimate log.Debugf("photo: probable country for %s is %s", m, txt.Quote(m.CountryName())) } else { m.EstimateCountry() diff --git a/internal/entity/photo_test.go b/internal/entity/photo_test.go index 7bfa3543a..599c9ef51 100644 --- a/internal/entity/photo_test.go +++ b/internal/entity/photo_test.go @@ -31,8 +31,8 @@ func TestSavePhotoForm(t *testing.T) { CameraID: uint(3), CameraSrc: "meta", LensID: uint(6), - LocationID: "1234", - LocationSrc: "manual", + GeoID: "1234", + GeoSrc: "manual", PlaceID: "765", PhotoCountry: "de", Details: form.Details{ @@ -93,8 +93,8 @@ func TestPhoto_SaveLabels(t *testing.T) { CameraID: uint(3), CameraSrc: "meta", LensID: uint(6), - LocationID: "1234", - LocationSrc: "geo", + GeoID: "1234", + GeoSrc: "geo", PlaceID: "765", PhotoCountry: "de", Keywords: []Keyword{}, @@ -748,8 +748,8 @@ func TestPhoto_LocationLoaded(t *testing.T) { assert.False(t, photo.LocationLoaded()) }) t.Run("false", func(t *testing.T) { - location := &Location{Place: nil} - photo := Photo{PhotoName: "Holiday", Location: location} + location := &Geo{Place: nil} + photo := Photo{PhotoName: "Holiday", Geo: location} assert.False(t, photo.LocationLoaded()) }) } @@ -763,8 +763,8 @@ func TestPhoto_LoadLocation(t *testing.T) { } }) t.Run("unknown location", func(t *testing.T) { - location := &Location{Place: nil} - photo := Photo{PhotoName: "Holiday", Location: location} + location := &Geo{Place: nil} + photo := Photo{PhotoName: "Holiday", Geo: location} assert.Error(t, photo.LoadLocation()) }) } @@ -785,8 +785,8 @@ func TestPhoto_LoadPlace(t *testing.T) { } }) t.Run("unknown location", func(t *testing.T) { - location := &Location{Place: nil} - photo := Photo{PhotoName: "Holiday", Location: location} + location := &Geo{Place: nil} + photo := Photo{PhotoName: "Holiday", Geo: location} assert.Error(t, photo.LoadPlace()) }) } diff --git a/internal/entity/photo_yaml_test.go b/internal/entity/photo_yaml_test.go index 2a2923b32..c6f8033a2 100644 --- a/internal/entity/photo_yaml_test.go +++ b/internal/entity/photo_yaml_test.go @@ -2,6 +2,8 @@ package entity import ( "github.com/stretchr/testify/assert" + "os" + "path/filepath" "testing" ) @@ -23,25 +25,20 @@ func TestPhoto_SaveAsYaml(t *testing.T) { t.Run("create from fixture", func(t *testing.T) { m := PhotoFixtures.Get("Photo01") m.PreloadFiles() - err := m.SaveAsYaml("test") - if err != nil { + fileName := filepath.Join(os.TempDir(), ".photoprism_test.yml") + + if err := m.SaveAsYaml(fileName); err != nil { t.Fatal(err) } - }) -} - -func TestPhoto_LoadFromYaml(t *testing.T) { - t.Run("create from fixture", func(t *testing.T) { - m := PhotoFixtures.Get("Photo01") - m.PreloadFiles() - err := m.LoadFromYaml("test") - - if err != nil { + if err := m.LoadFromYaml(fileName); err != nil { t.Fatal(err) } + if err := os.Remove(fileName); err != nil { + t.Fatal(err) + } }) } diff --git a/internal/entity/place.go b/internal/entity/place.go index eb7b8596a..d353bfaa4 100644 --- a/internal/entity/place.go +++ b/internal/entity/place.go @@ -12,13 +12,13 @@ import ( // Place used to associate photos to places type Place struct { ID string `gorm:"type:varbinary(42);primary_key;auto_increment:false;" json:"PlaceID" yaml:"PlaceID"` - LocLabel string `gorm:"type:varbinary(768);unique_index;" json:"Label" yaml:"Label"` - LocCity string `gorm:"type:varchar(255);" json:"City" yaml:"City,omitempty"` - LocState string `gorm:"type:varchar(255);" json:"State" yaml:"State,omitempty"` - LocCountry string `gorm:"type:varbinary(2);" json:"Country" yaml:"Country,omitempty"` - LocKeywords string `gorm:"type:varchar(255);" json:"Keywords" yaml:"Keywords,omitempty"` - LocNotes string `gorm:"type:text;" json:"Notes" yaml:"Notes,omitempty"` - LocFavorite bool `json:"Favorite" yaml:"Favorite,omitempty"` + GeoLabel string `gorm:"type:varbinary(768);unique_index;" json:"Label" yaml:"Label"` + GeoCity string `gorm:"type:varchar(255);" json:"City" yaml:"City,omitempty"` + GeoState string `gorm:"type:varchar(255);" json:"State" yaml:"State,omitempty"` + GeoCountry string `gorm:"type:varbinary(2);" json:"Country" yaml:"Country,omitempty"` + GeoKeywords string `gorm:"type:varchar(255);" json:"Keywords" yaml:"Keywords,omitempty"` + GeoNotes string `gorm:"type:text;" json:"Notes" yaml:"Notes,omitempty"` + GeoFavorite bool `json:"Favorite" yaml:"Favorite,omitempty"` PhotoCount int `gorm:"default:1" json:"PhotoCount" yaml:"-"` CreatedAt time.Time `json:"CreatedAt" yaml:"-"` UpdatedAt time.Time `json:"UpdatedAt" yaml:"-"` @@ -28,13 +28,13 @@ type Place struct { // UnknownPlace is PhotoPrism's default place. var UnknownPlace = Place{ ID: "zz", - LocLabel: "Unknown", - LocCity: "Unknown", - LocState: "Unknown", - LocCountry: "zz", - LocKeywords: "", - LocNotes: "", - LocFavorite: false, + GeoLabel: "Unknown", + GeoCity: "Unknown", + GeoState: "Unknown", + GeoCountry: "zz", + GeoKeywords: "", + GeoNotes: "", + GeoFavorite: false, PhotoCount: -1, } @@ -58,7 +58,7 @@ func FindPlace(id string, label string) *Place { log.Debugf("place: %s for id %s", err.Error(), id) return nil } - } else if err := Db().First(place, "id = ? OR loc_label = ?", id, label).Error; err != nil { + } else if err := Db().First(place, "id = ? OR geo_label = ?", id, label).Error; err != nil { log.Debugf("place: %s for id %s / label %s", err.Error(), id, txt.Quote(label)) return nil } @@ -87,18 +87,18 @@ func FirstOrCreatePlace(m *Place) *Place { return nil } - if m.LocLabel == "" { + if m.GeoLabel == "" { log.Errorf("place: label must not be empty (first or create %s)", m.ID) return nil } result := Place{} - if findErr := Db().Where("id = ? OR loc_label = ?", m.ID, m.LocLabel).First(&result).Error; findErr == nil { + if findErr := Db().Where("id = ? OR geo_label = ?", m.ID, m.GeoLabel).First(&result).Error; findErr == nil { return &result } else if createErr := m.Create(); createErr == nil { return m - } else if err := Db().Where("id = ? OR loc_label = ?", m.ID, m.LocLabel).First(&result).Error; err == nil { + } else if err := Db().Where("id = ? OR geo_label = ?", m.ID, m.GeoLabel).First(&result).Error; err == nil { return &result } else { log.Errorf("place: %s (first or create %s)", createErr, m.ID) @@ -114,45 +114,45 @@ func (m Place) Unknown() bool { // Label returns place label func (m Place) Label() string { - return m.LocLabel + return m.GeoLabel } // City returns place City func (m Place) City() string { - return m.LocCity + return m.GeoCity } // LongCity checks if the city name is more than 16 char. func (m Place) LongCity() bool { - return len(m.LocCity) > 16 + return len(m.GeoCity) > 16 } // NoCity checks if the location has no city func (m Place) NoCity() bool { - return m.LocCity == "" + return m.GeoCity == "" } // CityContains checks if the location city contains the text string func (m Place) CityContains(text string) bool { - return strings.Contains(text, m.LocCity) + return strings.Contains(text, m.GeoCity) } // State returns place State func (m Place) State() string { - return m.LocState + return m.GeoState } // CountryCode returns place CountryCode func (m Place) CountryCode() string { - return m.LocCountry + return m.GeoCountry } // CountryName returns place CountryName func (m Place) CountryName() string { - return maps.CountryNames[m.LocCountry] + return maps.CountryNames[m.GeoCountry] } // Notes returns place Notes func (m Place) Notes() string { - return m.LocNotes + return m.GeoNotes } diff --git a/internal/entity/place_fixtures.go b/internal/entity/place_fixtures.go index 600930b71..45cc307fd 100644 --- a/internal/entity/place_fixtures.go +++ b/internal/entity/place_fixtures.go @@ -25,91 +25,91 @@ func (m PlacesMap) Pointer(name string) *Place { var PlaceFixtures = PlacesMap{ "mexico": { ID: s2.TokenPrefix + "85d1ea7d3278", - LocLabel: "Teotihuacán, Mexico, Mexico", - LocCity: "Teotihuacán", - LocState: "State of Mexico", - LocCountry: "mx", - LocKeywords: "ancient, pyramid", - LocNotes: "", - LocFavorite: false, + GeoLabel: "Teotihuacán, Mexico, Mexico", + GeoCity: "Teotihuacán", + GeoState: "State of Mexico", + GeoCountry: "mx", + GeoKeywords: "ancient, pyramid", + GeoNotes: "", + GeoFavorite: false, PhotoCount: 1, CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, "zinkwazi": { ID: s2.TokenPrefix + "1ef744d1e279", - LocLabel: "KwaDukuza, KwaZulu-Natal, South Africa", - LocCity: "KwaDukuza", - LocState: "KwaZulu-Natal", - LocCountry: "za", - LocKeywords: "", - LocNotes: "africa", - LocFavorite: true, + GeoLabel: "KwaDukuza, KwaZulu-Natal, South Africa", + GeoCity: "KwaDukuza", + GeoState: "KwaZulu-Natal", + GeoCountry: "za", + GeoKeywords: "", + GeoNotes: "africa", + GeoFavorite: true, PhotoCount: 2, CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, "holidaypark": { ID: s2.TokenPrefix + "1ef744d1e280", - LocLabel: "Holiday Park, Amusement", - LocCity: "", - LocState: "Rheinland-Pfalz", - LocCountry: "de", - LocKeywords: "", - LocNotes: "germany", - LocFavorite: true, + GeoLabel: "Holiday Park, Amusement", + GeoCity: "", + GeoState: "Rheinland-Pfalz", + GeoCountry: "de", + GeoKeywords: "", + GeoNotes: "germany", + GeoFavorite: true, PhotoCount: 2, CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, "emptyNameLongCity": { ID: s2.TokenPrefix + "1ef744d1e281", - LocLabel: "labelEmptyNameLongCity", - LocCity: "longlonglonglonglongcity", - LocState: "Rheinland-Pfalz", - LocCountry: "de", - LocKeywords: "", - LocNotes: "germany", - LocFavorite: true, + GeoLabel: "labelEmptyNameLongCity", + GeoCity: "longlonglonglonglongcity", + GeoState: "Rheinland-Pfalz", + GeoCountry: "de", + GeoKeywords: "", + GeoNotes: "germany", + GeoFavorite: true, PhotoCount: 2, CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, "emptyNameShortCity": { ID: s2.TokenPrefix + "1ef744d1e282", - LocLabel: "labelEmptyNameShortCity", - LocCity: "shortcity", - LocState: "Rheinland-Pfalz", - LocCountry: "de", - LocKeywords: "", - LocNotes: "germany", - LocFavorite: true, + GeoLabel: "labelEmptyNameShortCity", + GeoCity: "shortcity", + GeoState: "Rheinland-Pfalz", + GeoCountry: "de", + GeoKeywords: "", + GeoNotes: "germany", + GeoFavorite: true, PhotoCount: 2, CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, "veryLongLocName": { ID: s2.TokenPrefix + "1ef744d1e283", - LocLabel: "labelVeryLongLocName", - LocCity: "Mainz", - LocState: "Rheinland-Pfalz", - LocCountry: "de", - LocKeywords: "", - LocNotes: "germany", - LocFavorite: true, + GeoLabel: "labelVeryLongLocName", + GeoCity: "Mainz", + GeoState: "Rheinland-Pfalz", + GeoCountry: "de", + GeoKeywords: "", + GeoNotes: "germany", + GeoFavorite: true, PhotoCount: 2, CreatedAt: Timestamp(), UpdatedAt: Timestamp(), }, "mediumLongLocName": { ID: s2.TokenPrefix + "1ef744d1e284", - LocLabel: "labelMediumLongLocName", - LocCity: "New york", - LocState: "New york", - LocCountry: "us", - LocKeywords: "", - LocNotes: "", - LocFavorite: true, + GeoLabel: "labelMediumLongLocName", + GeoCity: "New york", + GeoState: "New york", + GeoCountry: "us", + GeoKeywords: "", + GeoNotes: "", + GeoFavorite: true, PhotoCount: 2, CreatedAt: Timestamp(), UpdatedAt: Timestamp(), diff --git a/internal/entity/place_fixtures_test.go b/internal/entity/place_fixtures_test.go index 612afa6bd..9ddc15ae5 100644 --- a/internal/entity/place_fixtures_test.go +++ b/internal/entity/place_fixtures_test.go @@ -8,14 +8,14 @@ import ( func TestPlaceMap_Get(t *testing.T) { t.Run("get existing place", func(t *testing.T) { r := PlaceFixtures.Get("mexico") - assert.Equal(t, "Teotihuacán", r.LocCity) - assert.Equal(t, "State of Mexico", r.LocState) + assert.Equal(t, "Teotihuacán", r.GeoCity) + assert.Equal(t, "State of Mexico", r.GeoState) assert.IsType(t, Place{}, r) }) t.Run("get not existing place", func(t *testing.T) { r := PlaceFixtures.Get("xxx") - assert.Equal(t, "Unknown", r.LocCity) - assert.Equal(t, "Unknown", r.LocState) + assert.Equal(t, "Unknown", r.GeoCity) + assert.Equal(t, "Unknown", r.GeoState) assert.IsType(t, Place{}, r) }) } @@ -23,14 +23,14 @@ func TestPlaceMap_Get(t *testing.T) { func TestPlaceMap_Pointer(t *testing.T) { t.Run("get existing place pointer", func(t *testing.T) { r := PlaceFixtures.Pointer("mexico") - assert.Equal(t, "Teotihuacán", r.LocCity) - assert.Equal(t, "State of Mexico", r.LocState) + assert.Equal(t, "Teotihuacán", r.GeoCity) + assert.Equal(t, "State of Mexico", r.GeoState) assert.IsType(t, &Place{}, r) }) t.Run("get not existing place pointer", func(t *testing.T) { r := PlaceFixtures.Pointer("xxx") - assert.Equal(t, "Unknown", r.LocCity) - assert.Equal(t, "Unknown", r.LocState) + assert.Equal(t, "Unknown", r.GeoCity) + assert.Equal(t, "Unknown", r.GeoState) assert.IsType(t, &Place{}, r) }) } diff --git a/internal/entity/place_test.go b/internal/entity/place_test.go index f6fee9550..36571fb7d 100644 --- a/internal/entity/place_test.go +++ b/internal/entity/place_test.go @@ -20,7 +20,7 @@ func TestFindPlaceByLabel(t *testing.T) { t.Fatal("result should not be nil") } - assert.Equal(t, "de", r.LocCountry) + assert.Equal(t, "de", r.GeoCountry) }) t.Run("find by id", func(t *testing.T) { r := FindPlace(s2.TokenPrefix+"85d1ea7d3278", "") @@ -28,7 +28,7 @@ func TestFindPlaceByLabel(t *testing.T) { if r == nil { t.Fatal("result should not be nil") } - assert.Equal(t, "mx", r.LocCountry) + assert.Equal(t, "mx", r.GeoCountry) }) t.Run("find by label", func(t *testing.T) { r := FindPlace("", "KwaDukuza, KwaZulu-Natal, South Africa") @@ -37,7 +37,7 @@ func TestFindPlaceByLabel(t *testing.T) { t.Fatal("result should not be nil") } - assert.Equal(t, "za", r.LocCountry) + assert.Equal(t, "za", r.GeoCountry) }) t.Run("not matching", func(t *testing.T) { r := FindPlace("111", "xxx") @@ -65,13 +65,13 @@ func TestPlace_Find(t *testing.T) { t.Run("record does not exist", func(t *testing.T) { place := &Place{ ID: s2.TokenPrefix + "1110", - LocLabel: "test", - LocCity: "testCity", - LocState: "", - LocCountry: "", - LocKeywords: "", - LocNotes: "", - LocFavorite: false, + GeoLabel: "test", + GeoCity: "testCity", + GeoState: "", + GeoCountry: "", + GeoKeywords: "", + GeoNotes: "", + GeoFavorite: false, PhotoCount: 0, CreatedAt: Timestamp(), UpdatedAt: Timestamp(), @@ -86,47 +86,47 @@ func TestFirstOrCreatePlace(t *testing.T) { t.Run("existing place", func(t *testing.T) { m := PlaceFixtures.Pointer("zinkwazi") r := FirstOrCreatePlace(m) - assert.Equal(t, "KwaDukuza, KwaZulu-Natal, South Africa", r.LocLabel) + assert.Equal(t, "KwaDukuza, KwaZulu-Natal, South Africa", r.GeoLabel) }) t.Run("ID empty", func(t *testing.T) { p := &Place{ID: ""} assert.Nil(t, FirstOrCreatePlace(p)) }) - t.Run("LocLabel empty", func(t *testing.T) { - p := &Place{ID: "abcde44", LocLabel: ""} + t.Run("GeoLabel empty", func(t *testing.T) { + p := &Place{ID: "abcde44", GeoLabel: ""} assert.Nil(t, FirstOrCreatePlace(p)) }) } func TestPlace_LongCity(t *testing.T) { t.Run("true", func(t *testing.T) { - p := Place{LocCity: "veryveryveryverylongcity"} + p := Place{GeoCity: "veryveryveryverylongcity"} assert.True(t, p.LongCity()) }) t.Run("false", func(t *testing.T) { - p := Place{LocCity: "short"} + p := Place{GeoCity: "short"} assert.False(t, p.LongCity()) }) } func TestPlace_NoCity(t *testing.T) { t.Run("true", func(t *testing.T) { - p := Place{LocCity: ""} + p := Place{GeoCity: ""} assert.True(t, p.NoCity()) }) t.Run("false", func(t *testing.T) { - p := Place{LocCity: "short"} + p := Place{GeoCity: "short"} assert.False(t, p.NoCity()) }) } func TestPlace_CityContains(t *testing.T) { t.Run("true", func(t *testing.T) { - p := Place{LocCity: "Munich"} + p := Place{GeoCity: "Munich"} assert.True(t, p.CityContains("Munich")) }) t.Run("false", func(t *testing.T) { - p := Place{LocCity: "short"} + p := Place{GeoCity: "short"} assert.False(t, p.CityContains("ich")) }) } diff --git a/internal/form/photo.go b/internal/form/photo.go index dfa874a0d..7015732bc 100644 --- a/internal/form/photo.go +++ b/internal/form/photo.go @@ -35,9 +35,9 @@ type Photo struct { PhotoPrivate bool `json:"Private"` PhotoReview bool `json:"Review"` PhotoScan bool `json:"Scan"` - LocationID string `json:"LocationID"` - LocationSrc string `json:"LocationSrc"` - GPSAccuracy int `json:"GPSAccuracy"` + GeoID string `json:"GeoID"` + GeoSrc string `json:"GeoSrc"` + GeoAccuracy int `json:"GeoAccuracy"` PhotoAltitude int `json:"Altitude"` PhotoLat float32 `json:"Lat"` PhotoLng float32 `json:"Lng"` diff --git a/internal/form/photo_search.go b/internal/form/photo_search.go index fb8b60e88..2613c83a8 100644 --- a/internal/form/photo_search.go +++ b/internal/form/photo_search.go @@ -38,7 +38,7 @@ type PhotoSearch struct { Diff uint32 `form:"diff"` Mono bool `form:"mono"` Portrait bool `form:"portrait"` - Location bool `form:"location"` + Geo bool `form:"geo"` Album string `form:"album"` Label string `form:"label"` Category string `form:"category"` // Moments diff --git a/internal/form/photo_test.go b/internal/form/photo_test.go index 4f263bcac..df8cd9c2a 100644 --- a/internal/form/photo_test.go +++ b/internal/form/photo_test.go @@ -29,8 +29,8 @@ func TestNewPhoto(t *testing.T) { CameraID: uint(3), CameraSrc: "meta", LensID: uint(6), - LocationID: "1234", - LocationSrc: "geo", + GeoID: "1234", + GeoSrc: "geo", PlaceID: "765", PhotoCountry: "de"} @@ -60,8 +60,8 @@ func TestNewPhoto(t *testing.T) { assert.Equal(t, uint(3), r.CameraID) assert.Equal(t, "meta", r.CameraSrc) assert.Equal(t, uint(6), r.LensID) - assert.Equal(t, "1234", r.LocationID) - assert.Equal(t, "geo", r.LocationSrc) + assert.Equal(t, "1234", r.GeoID) + assert.Equal(t, "geo", r.GeoSrc) assert.Equal(t, "765", r.PlaceID) assert.Equal(t, "de", r.PhotoCountry) }) diff --git a/internal/maps/location.go b/internal/maps/location.go index 0f9b7bcc1..9bd9f8570 100644 --- a/internal/maps/location.go +++ b/internal/maps/location.go @@ -9,20 +9,6 @@ import ( "github.com/photoprism/photoprism/pkg/s2" ) -/* TODO - -(SELECT pl.loc_label as album_name, pl.loc_country, YEAR(ph.taken_at) as taken_year, round(count(ph.id)) as photo_count FROM photos ph - JOIN places pl ON ph.place_id = pl.id AND pl.id <> 1 - GROUP BY album_name, taken_year HAVING photo_count > 5) UNION ( - SELECT c.country_name AS album_name, pl.loc_country, YEAR(ph.taken_at) as taken_year, round(count(ph.id)) as photo_count FROM photos ph - JOIN places pl ON ph.place_id = pl.id AND pl.id <> 1 - JOIN countries c ON c.id = pl.loc_country - GROUP BY album_name, taken_year - HAVING photo_count > 10) -ORDER BY loc_country, album_name, taken_year; - -*/ - // Photo location type Location struct { ID string diff --git a/internal/maps/location_test.go b/internal/maps/location_test.go index b8b27628a..95b6ef8f4 100644 --- a/internal/maps/location_test.go +++ b/internal/maps/location_test.go @@ -195,7 +195,7 @@ func TestLocation_Assign(t *testing.T) { assert.Equal(t, "", l.LocCategory) assert.Equal(t, "Unknown", l.LocCity) // TODO: Should be zz for international waters, fixed in places server - // assert.Equal(t, "", l.LocCountry) + // assert.Equal(t, "", l.GeoCountry) }) } diff --git a/internal/photoprism/index_location.go b/internal/photoprism/index_location.go index 817444dad..561bc4cc9 100644 --- a/internal/photoprism/index_location.go +++ b/internal/photoprism/index_location.go @@ -12,8 +12,8 @@ func (ind *Index) estimateLocation(photo *entity.Photo) { if result := ind.db.Unscoped().Order(gorm.Expr("ABS(DATEDIFF(taken_at, ?)) ASC", photo.TakenAt)).Preload("Place").First(&recentPhoto); result.Error == nil { if recentPhoto.HasPlace() { photo.Place = recentPhoto.Place - photo.PhotoCountry = photo.Place.LocCountry - photo.LocationSrc = entity.SrcAuto + photo.PhotoCountry = photo.Place.GeoCountry + photo.GeoSrc = entity.SrcAuto log.Debugf("index: approximate location is %s", txt.Quote(recentPhoto.Place.Label())) } } diff --git a/internal/photoprism/index_mediafile.go b/internal/photoprism/index_mediafile.go index 65d9f740e..38e1b011a 100644 --- a/internal/photoprism/index_mediafile.go +++ b/internal/photoprism/index_mediafile.go @@ -479,8 +479,8 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) ( } if photo.UnknownLocation() { - photo.Location = &entity.UnknownLocation - photo.LocationID = entity.UnknownLocation.ID + photo.Geo = &entity.UnknownGeo + photo.GeoID = entity.UnknownGeo.ID } if photo.UnknownPlace() { diff --git a/internal/photoprism/location.go b/internal/photoprism/location.go index 4a30ea1d5..40ea1bc82 100644 --- a/internal/photoprism/location.go +++ b/internal/photoprism/location.go @@ -6,8 +6,8 @@ import ( "github.com/photoprism/photoprism/internal/entity" ) -// Location returns the Location of a MediaFile. -func (m *MediaFile) Location() (*entity.Location, error) { +// Geo returns the Geo of a MediaFile. +func (m *MediaFile) Location() (*entity.Geo, error) { if m.location != nil { return m.location, nil } @@ -18,7 +18,7 @@ func (m *MediaFile) Location() (*entity.Location, error) { return nil, errors.New("mediafile: no latitude and longitude in metadata") } - m.location = entity.NewLocation(data.Lat, data.Lng) + m.location = entity.NewGeo(data.Lat, data.Lng) return m.location, nil } diff --git a/internal/photoprism/mediafile.go b/internal/photoprism/mediafile.go index 94ce2b6e0..5f3741d7c 100644 --- a/internal/photoprism/mediafile.go +++ b/internal/photoprism/mediafile.go @@ -36,7 +36,7 @@ type MediaFile struct { height int metaData meta.Data metaDataOnce sync.Once - location *entity.Location + location *entity.Geo } // NewMediaFile returns a new media file. diff --git a/internal/query/geo.go b/internal/query/geo.go index 816d53d5d..4346e1560 100644 --- a/internal/query/geo.go +++ b/internal/query/geo.go @@ -165,10 +165,10 @@ func Geo(f form.GeoSearch) (results GeoResults, err error) { if f.S2 != "" { s2Min, s2Max := s2.PrefixedRange(f.S2, 7) - s = s.Where("photos.location_id BETWEEN ? AND ?", s2Min, s2Max) + s = s.Where("photos.geo_id BETWEEN ? AND ?", s2Min, s2Max) } else if f.Olc != "" { s2Min, s2Max := s2.PrefixedRange(pluscode.S2(f.Olc), 7) - s = s.Where("photos.location_id BETWEEN ? AND ?", s2Min, s2Max) + s = s.Where("photos.geo_id BETWEEN ? AND ?", s2Min, s2Max) } else { // Inaccurate distance search, but probably 'good enough' for now if f.Lat > 0 { diff --git a/internal/query/moments.go b/internal/query/moments.go index 471c41ac1..c7e4582b5 100644 --- a/internal/query/moments.go +++ b/internal/query/moments.go @@ -119,10 +119,10 @@ func MomentsCountries(threshold int) (results Moments, err error) { // MomentsStates returns the most popular states and countries by year. func MomentsStates(threshold int) (results Moments, err error) { db := UnscopedDb().Table("photos"). - Select("p.loc_country AS country, p.loc_state AS state, COUNT(*) AS photo_count"). + Select("p.geo_country AS country, p.geo_state AS state, COUNT(*) AS photo_count"). Joins("JOIN places p ON p.id = photos.place_id"). - Where("photos.photo_quality >= 3 AND photos.deleted_at IS NULL AND photo_private = 0 AND p.loc_state <> '' AND p.loc_country <> 'zz'"). - Group("p.loc_country, p.loc_state"). + Where("photos.photo_quality >= 3 AND photos.deleted_at IS NULL AND photo_private = 0 AND p.geo_state <> '' AND p.geo_country <> 'zz'"). + Group("p.geo_country, p.geo_state"). Having("photo_count >= ?", threshold) if err := db.Scan(&results).Error; err != nil { diff --git a/internal/query/photo.go b/internal/query/photo.go index 4d778c4b6..d71b711a7 100644 --- a/internal/query/photo.go +++ b/internal/query/photo.go @@ -18,8 +18,8 @@ func PhotoByID(photoID uint64) (photo entity.Photo, err error) { Preload("Lens"). Preload("Details"). Preload("Place"). - Preload("Location"). - Preload("Location.Place"). + Preload("Geo"). + Preload("Geo.Place"). First(&photo).Error; err != nil { return photo, err } @@ -38,8 +38,8 @@ func PhotoByUID(photoUID string) (photo entity.Photo, err error) { Preload("Lens"). Preload("Details"). Preload("Place"). - Preload("Location"). - Preload("Location.Place"). + Preload("Geo"). + Preload("Geo.Place"). First(&photo).Error; err != nil { return photo, err } @@ -58,8 +58,8 @@ func PhotoPreloadByUID(photoUID string) (photo entity.Photo, err error) { Preload("Lens"). Preload("Details"). Preload("Place"). - Preload("Location"). - Preload("Location.Place"). + Preload("Geo"). + Preload("Geo.Place"). First(&photo).Error; err != nil { return photo, err } @@ -101,8 +101,8 @@ func PhotosCheck(limit int, offset int) (entities entity.Photos, err error) { Preload("Lens"). Preload("Details"). Preload("Place"). - Preload("Location"). - Preload("Location.Place"). + Preload("Geo"). + Preload("Geo.Place"). Where("checked_at IS NULL OR checked_at < ?", time.Now().Add(-1*time.Hour*24*3)). Where("updated_at < ?", time.Now().Add(-1*time.Minute*10)). Limit(limit).Offset(offset).Find(&entities).Error diff --git a/internal/query/photo_results.go b/internal/query/photo_results.go index 626e27337..d9b21e298 100644 --- a/internal/query/photo_results.go +++ b/internal/query/photo_results.go @@ -48,16 +48,16 @@ type PhotoResult struct { LensModel string `json:"LensModel"` LensMake string `json:"LensMake"` PlaceID string `json:"PlaceID"` - LocationID string `json:"LocationID"` // Location - LocationSrc string `json:"LocationSrc"` - GPSAccuracy int `json:"GPSAccuracy,omitempty"` + GeoID string `json:"GeoID"` // Geo + GeoSrc string `json:"GeoSrc"` + GeoAccuracy int `json:"GeoAccuracy,omitempty"` PhotoAltitude int `json:"Altitude,omitempty"` PhotoLat float32 `json:"Lat"` PhotoLng float32 `json:"Lng"` - LocLabel string `json:"LocLabel"` - LocCity string `json:"LocCity"` - LocState string `json:"LocState"` - LocCountry string `json:"LocCountry"` + GeoLabel string `json:"GeoLabel"` + GeoCity string `json:"GeoCity"` + GeoState string `json:"GeoState"` + GeoCountry string `json:"GeoCountry"` FileID uint `json:"-"` // File FileUID string `json:"FileUID"` FileRoot string `json:"FileRoot"` diff --git a/internal/query/photo_results_test.go b/internal/query/photo_results_test.go index db792561d..293c68a3f 100644 --- a/internal/query/photo_results_test.go +++ b/internal/query/photo_results_test.go @@ -41,12 +41,12 @@ func TestPhotosResults_Merged(t *testing.T) { LensID: 0, LensModel: "", LensMake: "", - LocationID: "", + GeoID: "", PlaceID: "", - LocLabel: "", - LocCity: "", - LocState: "", - LocCountry: "", + GeoLabel: "", + GeoCity: "", + GeoState: "", + GeoCountry: "", FileID: 0, FileUID: "", FilePrimary: false, @@ -100,12 +100,12 @@ func TestPhotosResults_Merged(t *testing.T) { LensID: 0, LensModel: "", LensMake: "", - LocationID: "", + GeoID: "", PlaceID: "", - LocLabel: "", - LocCity: "", - LocState: "", - LocCountry: "", + GeoLabel: "", + GeoCity: "", + GeoState: "", + GeoCountry: "", FileID: 0, FileUID: "", FilePrimary: false, @@ -172,12 +172,12 @@ func TestPhotosResult_ShareFileName(t *testing.T) { LensID: 0, LensModel: "", LensMake: "", - LocationID: "", + GeoID: "", PlaceID: "", - LocLabel: "", - LocCity: "", - LocState: "", - LocCountry: "", + GeoLabel: "", + GeoCity: "", + GeoState: "", + GeoCountry: "", FileID: 0, FileUID: "", FilePrimary: false, @@ -235,12 +235,12 @@ func TestPhotosResult_ShareFileName(t *testing.T) { LensID: 0, LensModel: "", LensMake: "", - LocationID: "", + GeoID: "", PlaceID: "", - LocLabel: "", - LocCity: "", - LocState: "", - LocCountry: "", + GeoLabel: "", + GeoCity: "", + GeoState: "", + GeoCountry: "", FileID: 0, FileUID: "", FilePrimary: false, diff --git a/internal/query/photo_search.go b/internal/query/photo_search.go index a65995f84..8ccb11880 100644 --- a/internal/query/photo_search.go +++ b/internal/query/photo_search.go @@ -33,7 +33,7 @@ func PhotoSearch(f form.PhotoSearch) (results PhotoResults, count int, err error files.file_diff, files.file_video, files.file_duration, files.file_size, cameras.camera_make, cameras.camera_model, lenses.lens_make, lenses.lens_model, - places.loc_label, places.loc_city, places.loc_state, places.loc_country`). + places.geo_label, places.geo_city, places.geo_state, places.geo_country`). Joins("JOIN files ON photos.id = files.photo_id AND files.file_missing = 0 AND files.deleted_at IS NULL"). Joins("JOIN cameras ON photos.camera_id = cameras.id"). Joins("JOIN lenses ON photos.lens_id = lenses.id"). @@ -100,8 +100,8 @@ func PhotoSearch(f form.PhotoSearch) (results PhotoResults, count int, err error } // Filter by location. - if f.Location == true { - s = s.Where("location_id <> ''") + if f.Geo == true { + s = s.Where("geo_id <> ''") if likeAny := LikeAny("k.keyword", f.Query); likeAny != "" { s = s.Where("photos.id IN (SELECT pk.photo_id FROM keywords k JOIN photos_keywords pk ON k.id = pk.keyword_id WHERE (?))", gorm.Expr(likeAny)) @@ -199,12 +199,12 @@ func PhotoSearch(f form.PhotoSearch) (results PhotoResults, count int, err error } if f.State != "" { - s = s.Where("places.loc_state IN (?)", strings.Split(f.State, ",")) + s = s.Where("places.geo_state IN (?)", strings.Split(f.State, ",")) } if f.Category != "" { - s = s.Joins("JOIN locations ON photos.location_id = locations.id"). - Where("locations.loc_category IN (?)", strings.Split(strings.ToLower(f.Category), ",")) + s = s.Joins("JOIN geo ON photos.geo_id = geo.id"). + Where("geo.geo_category IN (?)", strings.Split(strings.ToLower(f.Category), ",")) } // Filter by media type. @@ -335,7 +335,7 @@ func PhotoSearch(f form.PhotoSearch) (results PhotoResults, count int, err error s = s.Order("photos.id DESC, files.file_primary DESC") case entity.SortOrderSimilar: s = s.Where("files.file_diff > 0") - s = s.Order("files.file_main_color, photos.location_id, files.file_diff, taken_at DESC, files.file_primary DESC") + s = s.Order("files.file_main_color, photos.geo_id, files.file_diff, taken_at DESC, files.file_primary DESC") case entity.SortOrderName: s = s.Order("photos.photo_path, photos.photo_name, files.file_primary DESC") default: diff --git a/internal/query/photo_search_test.go b/internal/query/photo_search_test.go index 0528bfd47..b254f2322 100644 --- a/internal/query/photo_search_test.go +++ b/internal/query/photo_search_test.go @@ -110,7 +110,7 @@ func TestPhotoSearch(t *testing.T) { f.Query = "" f.Count = 10 f.Offset = 0 - f.Location = true + f.Geo = true photos, _, err := PhotoSearch(f) @@ -125,7 +125,7 @@ func TestPhotoSearch(t *testing.T) { f.Query = "bridge" f.Count = 10 f.Offset = 0 - f.Location = true + f.Geo = true f.Error = false photos, _, err := PhotoSearch(f) @@ -141,7 +141,7 @@ func TestPhotoSearch(t *testing.T) { f.Query = "a" f.Count = 5000 f.Offset = 0 - f.Location = false + f.Geo = false photos, _, err := PhotoSearch(f)