Add approve button to photo card view

Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
Michael Mayer 2020-06-09 09:20:20 +02:00
parent 20d0a88bf6
commit d72480200e
5 changed files with 90 additions and 6 deletions

View file

@ -81,8 +81,12 @@
<v-btn icon flat large absolute :ripple="false" <v-btn icon flat large absolute :ripple="false"
:class="photo.Favorite ? 'p-photo-like opacity-75' : 'p-photo-like opacity-50'" :class="photo.Favorite ? 'p-photo-like opacity-75' : 'p-photo-like opacity-50'"
@click.stop.prevent="photo.toggleLike()"> @click.stop.prevent="photo.toggleLike()">
<v-icon v-if="photo.Favorite" color="white" class="t-like t-on" :data-uid="photo.UID">favorite</v-icon> <v-icon v-if="photo.Favorite" color="white" class="t-like t-on" :data-uid="photo.UID">
<v-icon v-else color="accent lighten-3" class="t-like t-off" :data-uid="photo.UID">favorite_border</v-icon> favorite
</v-icon>
<v-icon v-else color="accent lighten-3" class="t-like t-off" :data-uid="photo.UID">
favorite_border
</v-icon>
</v-btn> </v-btn>
<template v-if="photo.isPlayable()"> <template v-if="photo.isPlayable()">
@ -117,7 +121,8 @@
<v-card-title primary-title class="pa-3 p-photo-desc" style="user-select: none;"> <v-card-title primary-title class="pa-3 p-photo-desc" style="user-select: none;">
<div> <div>
<h3 class="body-2 mb-2" :title="photo.Title"> <h3 class="body-2 mb-2" :title="photo.Title">
<button @click.exact="editPhoto(index)" class="action-title-edit" :data-uid="photo.UID"> <button @click.exact="editPhoto(index)" class="action-title-edit"
:data-uid="photo.UID">
{{ photo.Title | truncate(80) }} {{ photo.Title | truncate(80) }}
</button> </button>
</h3> </h3>
@ -127,7 +132,8 @@
</button> </button>
</div> </div>
<div class="caption"> <div class="caption">
<button @click.exact="editPhoto(index)" class="action-date-edit" :data-uid="photo.UID"> <button @click.exact="editPhoto(index)" class="action-date-edit"
:data-uid="photo.UID">
<v-icon size="14" title="Taken">date_range</v-icon> <v-icon size="14" title="Taken">date_range</v-icon>
{{ photo.getDateString() }} {{ photo.getDateString() }}
</button> </button>
@ -138,7 +144,8 @@
<v-icon size="14">movie</v-icon> <v-icon size="14">movie</v-icon>
{{ photo.getVideoInfo() }} {{ photo.getVideoInfo() }}
</button> </button>
<button v-else @click.exact="editPhoto(index)" title="Camera" class="action-camera-edit" :data-uid="photo.UID"> <button v-else @click.exact="editPhoto(index)" title="Camera"
class="action-camera-edit" :data-uid="photo.UID">
<v-icon size="14">photo_camera</v-icon> <v-icon size="14">photo_camera</v-icon>
{{ photo.getPhotoInfo() }} {{ photo.getPhotoInfo() }}
</button> </button>
@ -153,7 +160,8 @@
</template> </template>
<template v-if="showLocation && photo.Country !== 'zz'"> <template v-if="showLocation && photo.Country !== 'zz'">
<br/> <br/>
<button @click.exact="openLocation(index)" title="Location" class="action-location" :data-uid="photo.UID"> <button @click.exact="openLocation(index)" title="Location"
class="action-location" :data-uid="photo.UID">
<v-icon size="14">location_on</v-icon> <v-icon size="14">location_on</v-icon>
{{ photo.locationInfo() }} {{ photo.locationInfo() }}
</button> </button>
@ -161,6 +169,18 @@
</div> </div>
</div> </div>
</v-card-title> </v-card-title>
<v-card-actions v-if="photo.Quality < 3 && $config.feature('review')">
<v-layout row wrap align-center>
<v-flex xs12>
<div class="text-xs-center">
<v-btn color="secondary-dark" small depressed dark @click.stop="photo.approve()"
class="action-approve text-xs-center">
<span>Approve</span>
</v-btn>
</div>
</v-flex>
</v-layout>
</v-card-actions>
</v-card> </v-card>
</v-hover> </v-hover>
</v-flex> </v-flex>

View file

@ -412,6 +412,10 @@ export class Photo extends RestModel {
return "Unknown"; return "Unknown";
} }
approve() {
return Api.post(this.getEntityResource() + "/approve");
}
toggleLike() { toggleLike() {
this.Favorite = !this.Favorite; this.Favorite = !this.Favorite;

View file

@ -179,6 +179,39 @@ func GetPhotoYaml(router *gin.RouterGroup, conf *config.Config) {
}) })
} }
// POST /api/v1/photos/:uid/approve
//
// Parameters:
// uid: string PhotoUID as returned by the API
func ApprovePhoto(router *gin.RouterGroup, conf *config.Config) {
router.POST("/photos/:uid/approve", func(c *gin.Context) {
if Unauthorized(c, conf) {
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
return
}
id := c.Param("uid")
m, err := query.PhotoByUID(id)
if err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, ErrPhotoNotFound)
return
}
if err := m.Approve(); err != nil {
log.Errorf("photo: %s", err.Error())
c.AbortWithStatusJSON(http.StatusInternalServerError, ErrSaveFailed)
return
}
SavePhotoAsYaml(m, conf)
PublishPhotoEvent(EntityUpdated, id, c)
c.JSON(http.StatusOK, gin.H{"photo": m})
})
}
// POST /api/v1/photos/:uid/like // POST /api/v1/photos/:uid/like
// //
// Parameters: // Parameters:

View file

@ -843,3 +843,29 @@ func (m *Photo) SetFavorite(favorite bool) error {
return nil return nil
} }
// Approve approves a photo in review.
func (m *Photo) Approve() error {
if m.PhotoQuality >= 3 {
// Nothing to do.
return nil
}
edited := time.Now().UTC()
m.EditedAt = &edited
m.PhotoQuality = m.QualityScore()
if err := Db().Model(m).Updates(Photo{EditedAt: m.EditedAt, PhotoQuality: m.PhotoQuality}).Error; err != nil {
return err
}
if err := UpdatePhotoCounts(); err != nil {
log.Errorf("photo: %s", err)
}
event.Publish("count.review", event.Data{
"count": -1,
})
return nil
}

View file

@ -38,6 +38,7 @@ func registerRoutes(router *gin.Engine, conf *config.Config) {
api.GetPhotos(v1, conf) api.GetPhotos(v1, conf)
api.GetPhotoDownload(v1, conf) api.GetPhotoDownload(v1, conf)
api.LinkPhoto(v1, conf) api.LinkPhoto(v1, conf)
api.ApprovePhoto(v1, conf)
api.LikePhoto(v1, conf) api.LikePhoto(v1, conf)
api.DislikePhoto(v1, conf) api.DislikePhoto(v1, conf)
api.AddPhotoLabel(v1, conf) api.AddPhotoLabel(v1, conf)