Proof-of-concept for batch like & delete
Requires additional code clean-up and unit / acceptance tests
This commit is contained in:
parent
9e761549e4
commit
ea3f209f8f
|
@ -79,10 +79,14 @@
|
|||
</v-speed-dial>
|
||||
</template>
|
||||
<script>
|
||||
import Event from "pubsub-js";
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
name: 'p-photo-clipboard',
|
||||
props: {
|
||||
selection: Array,
|
||||
refresh: Function,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -95,12 +99,32 @@
|
|||
this.expanded = false;
|
||||
},
|
||||
batchLike() {
|
||||
this.$alert.warning("Not implemented yet");
|
||||
this.expanded = false;
|
||||
Event.publish("ajax.start");
|
||||
|
||||
const ctx = this;
|
||||
|
||||
axios.post("/api/v1/batch/photos/like", {"ids": this.selection}).then(function () {
|
||||
Event.publish("ajax.end");
|
||||
Event.publish("alert.success", "Photos liked");
|
||||
ctx.clearClipboard();
|
||||
ctx.refresh();
|
||||
}).catch(() => {
|
||||
Event.publish("ajax.end");
|
||||
});
|
||||
},
|
||||
batchDelete() {
|
||||
this.$alert.warning("Not implemented yet");
|
||||
this.expanded = false;
|
||||
Event.publish("ajax.start");
|
||||
|
||||
const ctx = this;
|
||||
|
||||
axios.post("/api/v1/batch/photos/delete", {"ids": this.selection}).then(function () {
|
||||
Event.publish("ajax.end");
|
||||
Event.publish("alert.success", "Photos deleted");
|
||||
ctx.clearClipboard();
|
||||
ctx.refresh();
|
||||
}).catch(() => {
|
||||
Event.publish("ajax.end");
|
||||
});
|
||||
},
|
||||
batchTag() {
|
||||
this.$alert.warning("Not implemented yet");
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
:settings-change="updateQuery"></p-photo-search>
|
||||
|
||||
<v-container fluid>
|
||||
<p-photo-clipboard :selection="selection"></p-photo-clipboard>
|
||||
<p-photo-clipboard :refresh="refresh" :selection="selection"></p-photo-clipboard>
|
||||
|
||||
<p-photo-mosaic v-if="settings.view === 'mosaic'" :photos="results" :selection="selection"
|
||||
:open-photo="openPhoto"></p-photo-mosaic>
|
||||
|
@ -151,6 +151,10 @@
|
|||
|
||||
return params;
|
||||
},
|
||||
refresh() {
|
||||
this.lastFilter = {};
|
||||
this.search();
|
||||
},
|
||||
search() {
|
||||
this.scrollDisabled = true;
|
||||
|
||||
|
|
75
internal/api/batch.go
Normal file
75
internal/api/batch.go
Normal file
|
@ -0,0 +1,75 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/config"
|
||||
"github.com/photoprism/photoprism/internal/models"
|
||||
"github.com/photoprism/photoprism/internal/util"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type BatchParams struct {
|
||||
Ids []int `json:"ids"`
|
||||
}
|
||||
|
||||
// POST /api/v1/batch/photos/delete
|
||||
func BatchPhotosDelete(router *gin.RouterGroup, conf *config.Config) {
|
||||
router.POST("/batch/photos/delete", func(c *gin.Context) {
|
||||
start := time.Now()
|
||||
|
||||
var params BatchParams
|
||||
|
||||
if err := c.BindJSON(¶ms); err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": util.UcFirst(err.Error())})
|
||||
}
|
||||
|
||||
if len(params.Ids) == 0 {
|
||||
log.Error("no photos selected")
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": util.UcFirst("no photos selected")})
|
||||
}
|
||||
|
||||
log.Infof("deleting photos: %#v", params.Ids)
|
||||
|
||||
db := conf.Db()
|
||||
|
||||
db.Where("id IN (?)", params.Ids).Delete(&models.Photo{})
|
||||
db.Where("photo_id IN (?)", params.Ids).Delete(&models.File{})
|
||||
|
||||
elapsed := time.Since(start)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("photos deleted in %s", elapsed)})
|
||||
})
|
||||
}
|
||||
|
||||
// POST /api/v1/batch/photos/like
|
||||
func BatchPhotosLike(router *gin.RouterGroup, conf *config.Config) {
|
||||
router.POST("/batch/photos/like", func(c *gin.Context) {
|
||||
start := time.Now()
|
||||
|
||||
var params BatchParams
|
||||
|
||||
if err := c.BindJSON(¶ms); err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": util.UcFirst(err.Error())})
|
||||
}
|
||||
|
||||
if len(params.Ids) == 0 {
|
||||
log.Error("no photos selected")
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": util.UcFirst("no photos selected")})
|
||||
}
|
||||
|
||||
log.Infof("liking photos: %#v", params.Ids)
|
||||
|
||||
db := conf.Db()
|
||||
|
||||
db.Model(models.Photo{}).Where("id IN (?)", params.Ids).Updates(models.Photo{PhotoFavorite: true})
|
||||
|
||||
elapsed := time.Since(start)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("photos liked in %s", elapsed)})
|
||||
})
|
||||
}
|
|
@ -32,6 +32,9 @@ func registerRoutes(router *gin.Engine, conf *config.Config) {
|
|||
|
||||
api.Upload(v1, conf)
|
||||
api.Import(v1, conf)
|
||||
|
||||
api.BatchPhotosDelete(v1, conf)
|
||||
api.BatchPhotosLike(v1, conf)
|
||||
}
|
||||
|
||||
// Default HTML page (client-side routing implemented via Vue.js)
|
||||
|
|
Loading…
Reference in a new issue