Add favorite places

Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
Michael Mayer 2020-06-08 18:32:51 +02:00
parent f9c55f22a6
commit 8fa1cb9392
12 changed files with 157 additions and 96 deletions

View file

@ -70,55 +70,58 @@ class Config {
const type = ev.split(".")[1];
switch (type) {
case "cameras":
this.values.count.cameras += data.count;
this.update();
break;
case "lenses":
this.values.count.lenses += data.count;
break;
case "countries":
this.values.count.countries += data.count;
this.update();
break;
case "places":
this.values.count.places += data.count;
break;
case "labels":
this.values.count.labels += data.count;
break;
case "videos":
this.values.count.videos += data.count;
break;
case "albums":
this.values.count.albums += data.count;
break;
case "moments":
this.values.count.moments += data.count;
break;
case "months":
this.values.count.months += data.count;
break;
case "folders":
this.values.count.folders += data.count;
break;
case "files":
this.values.count.files += data.count;
break;
case "favorites":
this.values.count.favorites += data.count;
break;
case "review":
this.values.count.review += data.count;
break;
case "private":
this.values.count.private += data.count;
break;
case "photos":
this.values.count.photos += data.count;
break;
default:
console.warn("unknown count type", ev, data);
case "cameras":
this.values.count.cameras += data.count;
this.update();
break;
case "lenses":
this.values.count.lenses += data.count;
break;
case "countries":
this.values.count.countries += data.count;
this.update();
break;
case "states":
this.values.count.states += data.count;
break;
case "places":
this.values.count.places += data.count;
break;
case "labels":
this.values.count.labels += data.count;
break;
case "videos":
this.values.count.videos += data.count;
break;
case "albums":
this.values.count.albums += data.count;
break;
case "moments":
this.values.count.moments += data.count;
break;
case "months":
this.values.count.months += data.count;
break;
case "folders":
this.values.count.folders += data.count;
break;
case "files":
this.values.count.files += data.count;
break;
case "favorites":
this.values.count.favorites += data.count;
break;
case "review":
this.values.count.review += data.count;
break;
case "private":
this.values.count.private += data.count;
break;
case "photos":
this.values.count.photos += data.count;
break;
default:
console.warn("unknown count type", ev, data);
}
this.values.count;

View file

@ -200,7 +200,7 @@
</v-list-tile-content>
</v-list-tile -->
<v-list-tile :to="{ name: 'places' }" @click="" class="p-navigation-places"
<v-list-tile v-if="mini" :to="{ name: 'places' }" @click="" class="p-navigation-places"
v-show="$config.feature('places')">
<v-list-tile-action>
<v-icon>place</v-icon>
@ -209,12 +209,31 @@
<v-list-tile-content>
<v-list-tile-title>
<translate key="Places">Places</translate>
<span v-show="config.count.places > 0"
class="p-navigation-count">{{ config.count.places }}</span>
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-group v-if="!mini" prepend-icon="place" no-action v-show="$config.feature('places')">
<v-list-tile slot="activator" :to="{ name: 'places' }" @click.stop="" class="p-navigation-places">
<v-list-tile-content>
<v-list-tile-title>
<translate key="Places">Places</translate>
<span v-show="config.count.places > 0"
class="p-navigation-count">{{ config.count.places }}</span>
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile :to="{ name: 'states' }" @click="" class="p-navigation-states">
<v-list-tile-content>
<v-list-tile-title>
<translate key="Favorites">Favorites</translate>
<span v-show="config.count.states > 0" class="p-navigation-count">{{ config.count.states }}</span>
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list-group>
<!-- v-list-tile to="/discover" @click="" class="p-navigation-discover" v-show="config.experimental">
<v-list-tile-action>
<v-icon>color_lens</v-icon>

View file

@ -130,6 +130,19 @@ export default [
component: Places,
meta: {title: "Places", auth: true},
},
{
name: "states",
path: "/places/favorites",
component: Albums,
meta: {title: "Places", auth: true},
props: {view: "state", staticFilter: {type: "state"}},
},
{
name: "state",
path: "/places/favorites/:uid/:slug",
component: AlbumPhotos,
meta: {title: "Places", auth: true},
},
{
name: "files",
path: "/library/files*",

View file

@ -89,7 +89,7 @@ func CreateAlbum(router *gin.RouterGroup, conf *config.Config) {
return
}
m := entity.NewAlbum(f.AlbumTitle, entity.TypeAlbum)
m := entity.NewAlbum(f.AlbumTitle, entity.AlbumDefault)
m.AlbumFavorite = f.AlbumFavorite
log.Debugf("create album: %+v %+v", f, m)

View file

@ -65,6 +65,7 @@ type ClientCounts struct {
Folders int `json:"folders"`
Files int `json:"files"`
Places int `json:"places"`
States int `json:"states"`
Labels int `json:"labels"`
LabelMaxPhotos int `json:"labelMaxPhotos"`
}
@ -205,7 +206,7 @@ func (c *Config) ClientConfig() ClientConfig {
Take(&result.Count)
c.Db().Table("albums").
Select("SUM(album_type = ?) AS albums, SUM(album_type = ?) AS moments, SUM(album_type = ?) AS months, SUM(album_type = ?) AS folders", entity.TypeAlbum, entity.TypeMoment, entity.TypeMonth, entity.TypeFolder).
Select("SUM(album_type = ?) AS albums, SUM(album_type = ?) AS moments, SUM(album_type = ?) AS months, SUM(album_type = ?) AS states, SUM(album_type = ?) AS folders", entity.AlbumDefault, entity.AlbumMoment, entity.AlbumMonth, entity.AlbumState, entity.AlbumFolder).
Where("deleted_at IS NULL").
Take(&result.Count)

View file

@ -14,6 +14,14 @@ import (
"github.com/ulule/deepcopier"
)
const (
AlbumDefault = "album"
AlbumFolder = "folder"
AlbumMoment = "moment"
AlbumMonth = "month"
AlbumState = "state"
)
type Albums []Album
// Album represents a photo album
@ -65,7 +73,7 @@ func AddPhotoToAlbums(photo string, albums []string) (err error) {
if rnd.IsPPID(album, 'a') {
aUID = album
} else {
a := NewAlbum(album, TypeAlbum)
a := NewAlbum(album, AlbumDefault)
if err = a.Find(); err == nil {
aUID = a.AlbumUID
@ -93,7 +101,7 @@ func NewAlbum(albumTitle, albumType string) *Album {
now := time.Now().UTC()
if albumType == "" {
albumType = TypeAlbum
albumType = AlbumDefault
}
result := &Album{
@ -118,7 +126,7 @@ func NewFolderAlbum(albumTitle, albumSlug, albumFilter string) *Album {
result := &Album{
AlbumOrder: SortOrderOldest,
AlbumType: TypeFolder,
AlbumType: AlbumFolder,
AlbumTitle: albumTitle,
AlbumSlug: albumSlug,
AlbumFilter: albumFilter,
@ -139,7 +147,28 @@ func NewMomentsAlbum(albumTitle, albumSlug, albumFilter string) *Album {
result := &Album{
AlbumOrder: SortOrderOldest,
AlbumType: TypeMoment,
AlbumType: AlbumMoment,
AlbumTitle: albumTitle,
AlbumSlug: albumSlug,
AlbumFilter: albumFilter,
CreatedAt: now,
UpdatedAt: now,
}
return result
}
// NewStateAlbum creates a new moment.
func NewStateAlbum(albumTitle, albumSlug, albumFilter string) *Album {
if albumTitle == "" || albumSlug == "" || albumFilter == "" {
return nil
}
now := time.Now().UTC()
result := &Album{
AlbumOrder: SortOrderOldest,
AlbumType: AlbumState,
AlbumTitle: albumTitle,
AlbumSlug: albumSlug,
AlbumFilter: albumFilter,
@ -166,7 +195,7 @@ func NewMonthAlbum(albumTitle, albumSlug string, year, month int) *Album {
result := &Album{
AlbumOrder: SortOrderOldest,
AlbumType: TypeMonth,
AlbumType: AlbumMonth,
AlbumTitle: albumTitle,
AlbumSlug: albumSlug,
AlbumFilter: f.Serialize(),
@ -234,7 +263,7 @@ func (m *Album) String() string {
// Checks if the album is of type moment.
func (m *Album) IsMoment() bool {
return m.AlbumType == TypeMoment
return m.AlbumType == AlbumMoment
}
// SetTitle changes the album name.
@ -247,7 +276,7 @@ func (m *Album) SetTitle(title string) {
m.AlbumTitle = txt.Clip(title, txt.ClipDefault)
if m.AlbumType == TypeAlbum {
if m.AlbumType == AlbumDefault {
if len(m.AlbumTitle) < txt.ClipSlug {
m.AlbumSlug = slug.Make(m.AlbumTitle)
} else {
@ -290,13 +319,13 @@ func (m *Album) Create() error {
}
switch m.AlbumType {
case TypeAlbum:
case AlbumDefault:
event.Publish("count.albums", event.Data{"count": 1})
case TypeMoment:
case AlbumMoment:
event.Publish("count.moments", event.Data{"count": 1})
case TypeMonth:
case AlbumMonth:
event.Publish("count.months", event.Data{"count": 1})
case TypeFolder:
case AlbumFolder:
event.Publish("count.folders", event.Data{"count": 1})
}
return nil

View file

@ -11,7 +11,7 @@ func (m AlbumMap) Get(name string) Album {
return result
}
return *NewAlbum(name, TypeAlbum)
return *NewAlbum(name, AlbumDefault)
}
func (m AlbumMap) Pointer(name string) *Album {
@ -19,7 +19,7 @@ func (m AlbumMap) Pointer(name string) *Album {
return &result
}
return NewAlbum(name, TypeAlbum)
return NewAlbum(name, AlbumDefault)
}
var AlbumFixtures = AlbumMap{
@ -28,7 +28,7 @@ var AlbumFixtures = AlbumMap{
CoverUID: "",
AlbumUID: "at9lxuqxpogaaba7",
AlbumSlug: "christmas2030",
AlbumType: TypeAlbum,
AlbumType: AlbumDefault,
AlbumTitle: "Christmas2030",
AlbumDescription: "Wonderful christmas",
AlbumNotes: "",
@ -45,7 +45,7 @@ var AlbumFixtures = AlbumMap{
CoverUID: "",
AlbumUID: "at9lxuqxpogaaba8",
AlbumSlug: "holiday-2030",
AlbumType: TypeAlbum,
AlbumType: AlbumDefault,
AlbumTitle: "Holiday2030",
AlbumDescription: "Wonderful christmas",
AlbumNotes: "",
@ -62,7 +62,7 @@ var AlbumFixtures = AlbumMap{
CoverUID: "",
AlbumUID: "at9lxuqxpogaaba9",
AlbumSlug: "berlin-2019",
AlbumType: TypeAlbum,
AlbumType: AlbumDefault,
AlbumTitle: "Berlin2019",
AlbumDescription: "Wonderful christmas",
AlbumNotes: "",
@ -79,7 +79,7 @@ var AlbumFixtures = AlbumMap{
CoverUID: "",
AlbumUID: "at1lxuqipogaaba1",
AlbumSlug: "april-1990",
AlbumType: TypeFolder,
AlbumType: AlbumFolder,
AlbumTitle: "April 1990",
AlbumDescription: "Spring is the time of year when many things change.",
AlbumNotes: "Thunderstorms cause most of the severe spring weather.",
@ -97,7 +97,7 @@ var AlbumFixtures = AlbumMap{
CoverUID: "",
AlbumUID: "at6axuzitogaaiax",
AlbumSlug: "import",
AlbumType: TypeAlbum,
AlbumType: AlbumDefault,
AlbumTitle: "Import Album",
AlbumDescription: "",
AlbumNotes: "",

View file

@ -12,12 +12,12 @@ import (
func TestNewAlbum(t *testing.T) {
t.Run("name Christmas 2018", func(t *testing.T) {
album := NewAlbum("Christmas 2018", TypeAlbum)
album := NewAlbum("Christmas 2018", AlbumDefault)
assert.Equal(t, "Christmas 2018", album.AlbumTitle)
assert.Equal(t, "christmas-2018", album.AlbumSlug)
})
t.Run("name empty", func(t *testing.T) {
album := NewAlbum("", TypeAlbum)
album := NewAlbum("", AlbumDefault)
defaultName := time.Now().Format("January 2006")
defaultSlug := slug.Make(defaultName)
@ -29,7 +29,7 @@ func TestNewAlbum(t *testing.T) {
func TestAlbum_SetName(t *testing.T) {
t.Run("valid name", func(t *testing.T) {
album := NewAlbum("initial name", TypeAlbum)
album := NewAlbum("initial name", AlbumDefault)
assert.Equal(t, "initial name", album.AlbumTitle)
assert.Equal(t, "initial-name", album.AlbumSlug)
album.SetTitle("New Album Name")
@ -37,7 +37,7 @@ func TestAlbum_SetName(t *testing.T) {
assert.Equal(t, "new-album-name", album.AlbumSlug)
})
t.Run("empty name", func(t *testing.T) {
album := NewAlbum("initial name", TypeAlbum)
album := NewAlbum("initial name", AlbumDefault)
assert.Equal(t, "initial name", album.AlbumTitle)
assert.Equal(t, "initial-name", album.AlbumSlug)
@ -57,7 +57,7 @@ The discrepancy of 1 second meridian arc length between equator and pole is abou
is an oblate spheroid.`
expected := txt.Clip(longName, txt.ClipDefault)
slugExpected := txt.Clip(longName, txt.ClipSlug)
album := NewAlbum(longName, TypeAlbum)
album := NewAlbum(longName, AlbumDefault)
assert.Equal(t, expected, album.AlbumTitle)
assert.Contains(t, album.AlbumSlug, slug.Make(slugExpected))
})
@ -65,7 +65,7 @@ is an oblate spheroid.`
func TestAlbum_Save(t *testing.T) {
t.Run("success", func(t *testing.T) {
album := NewAlbum("Old Name", TypeAlbum)
album := NewAlbum("Old Name", AlbumDefault)
assert.Equal(t, "Old Name", album.AlbumTitle)
assert.Equal(t, "old-name", album.AlbumSlug)

View file

@ -27,16 +27,12 @@ const (
MonthUnknown = -1
TitleUnknown = "Unknown"
TypeDefault = ""
TypeAlbum = "album"
TypeFolder = "folder"
TypeMoment = "moment"
TypeMonth = "month"
TypeImage = "image"
TypeLive = "live"
TypeVideo = "video"
TypeRaw = "raw"
TypeText = "text"
TypeDefault = ""
TypeImage = "image"
TypeLive = "live"
TypeVideo = "video"
TypeRaw = "raw"
TypeText = "text"
RootOriginals = ""
RootExamples = "examples"

View file

@ -76,7 +76,7 @@ func (m *Moments) Start() (err error) {
Public: true,
}
if a := entity.FindAlbumBySlug(mom.Slug(), entity.TypeFolder); a != nil {
if a := entity.FindAlbumBySlug(mom.Slug(), entity.AlbumFolder); a != nil {
if a.DeletedAt != nil {
// Nothing to do.
log.Debugf("moments: %s was deleted (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
@ -102,7 +102,7 @@ func (m *Moments) Start() (err error) {
log.Errorf("moments: %s", err.Error())
} else {
for _, mom := range results {
if a := entity.FindAlbumBySlug(mom.Slug(), entity.TypeMonth); a != nil {
if a := entity.FindAlbumBySlug(mom.Slug(), entity.AlbumMonth); a != nil {
if a.DeletedAt != nil {
// Nothing to do.
log.Debugf("moments: %s was deleted (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
@ -130,7 +130,7 @@ func (m *Moments) Start() (err error) {
Public: true,
}
if a := entity.FindAlbumBySlug(mom.Slug(), entity.TypeMoment); a != nil {
if a := entity.FindAlbumBySlug(mom.Slug(), entity.AlbumMoment); a != nil {
if a.DeletedAt != nil {
// Nothing to do.
log.Debugf("moments: %s was deleted (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
@ -161,14 +161,14 @@ func (m *Moments) Start() (err error) {
Public: true,
}
if a := entity.FindAlbumBySlug(mom.Slug(), entity.TypeMoment); a != nil {
if a := entity.FindAlbumBySlug(mom.Slug(), entity.AlbumState); a != nil {
if a.DeletedAt != nil {
// Nothing to do.
log.Debugf("moments: %s was deleted (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
} else {
log.Debugf("moments: %s already exists (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
}
} else if a := entity.NewMomentsAlbum(mom.Title(), mom.Slug(), f.Serialize()); a != nil {
} else if a := entity.NewStateAlbum(mom.Title(), mom.Slug(), f.Serialize()); a != nil {
a.AlbumCountry = mom.Country
if err := a.Create(); err != nil {
@ -190,7 +190,7 @@ func (m *Moments) Start() (err error) {
Public: true,
}
if a := entity.FindAlbumBySlug(mom.Slug(), entity.TypeMoment); a != nil {
if a := entity.FindAlbumBySlug(mom.Slug(), entity.AlbumMoment); a != nil {
log.Debugf("moments: %s already exists (%s)", txt.Quote(mom.Title()), f.Serialize())
if f.Serialize() == a.AlbumFilter || a.DeletedAt != nil {

View file

@ -53,7 +53,7 @@ func AlbumCoverByUID(albumUID string) (file entity.File, err error) {
if err := Db().Where("album_uid = ?", albumUID).First(&a).Error; err != nil {
return file, err
} else if a.AlbumType != entity.TypeAlbum { // TODO: Optimize
} else if a.AlbumType != entity.AlbumDefault { // TODO: Optimize
f := form.PhotoSearch{Album: a.AlbumUID, Filter: a.AlbumFilter, Order: entity.SortOrderRelevance, Count: 1, Offset: 0, Merged: false}
if photos, _, err := PhotoSearch(f); err != nil {

View file

@ -47,7 +47,7 @@ func (c *Counts) Refresh() {
Take(c)
Db().Table("albums").
Select("SUM(album_type = ?) AS albums, SUM(album_type = ?) AS moments, SUM(album_type = ?) AS folders", entity.TypeAlbum, entity.TypeMoment, entity.TypeFolder).
Select("SUM(album_type = ?) AS albums, SUM(album_type = ?) AS moments, SUM(album_type = ?) AS folders", entity.AlbumDefault, entity.AlbumMoment, entity.AlbumFolder).
Where("deleted_at IS NULL").
Take(c)