WebDAV: Fix upload of complete albums #1376
This commit is contained in:
parent
eb75a58f45
commit
c256664a1b
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package main
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
108
frontend/src/common/selection.js
Normal file
108
frontend/src/common/selection.js
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2018 - 2022 Michael Mayer <hello@photoprism.app>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under Version 3 of the GNU Affero General Public License (the "AGPL"):
|
||||
<https://docs.photoprism.app/license/agpl>
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
The AGPL is supplemented by our Trademark and Brand Guidelines,
|
||||
which describe how our Brand Assets may be used:
|
||||
<https://photoprism.app/trademark>
|
||||
|
||||
Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
||||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
function isObject(val) {
|
||||
return val && val instanceof Object;
|
||||
}
|
||||
|
||||
function isModel(model) {
|
||||
return (
|
||||
model &&
|
||||
typeof model.getId === "function" &&
|
||||
typeof model.constructor.getCollectionResource === "function"
|
||||
);
|
||||
}
|
||||
|
||||
class Selection {
|
||||
/**
|
||||
* @param {Object?} items
|
||||
*/
|
||||
constructor(items) {
|
||||
this.clear();
|
||||
this.addItems(items);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.files = [];
|
||||
this.photos = [];
|
||||
this.albums = [];
|
||||
this.labels = [];
|
||||
this.places = [];
|
||||
this.subjects = [];
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} items
|
||||
*/
|
||||
addItems(items) {
|
||||
if (isObject(items) && Object.keys(items).length > 0) {
|
||||
for (const [key, value] of Object.entries(items)) {
|
||||
if (this.hasOwnProperty(key) && Array.isArray(value) && value.length > 0) {
|
||||
if (this[key].length === 0 || this[key][0] !== value[0]) {
|
||||
this[key].push(...value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
addModel(model) {
|
||||
if (!isModel(model)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const id = model.getId();
|
||||
const key = model.constructor.getCollectionResource();
|
||||
|
||||
if (!id || !key || !this.hasOwnProperty(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this[key].includes(id)) {
|
||||
this[key].push(id);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isEmpty() {
|
||||
for (const items of Object.values(this)) {
|
||||
if (Array.isArray(items) && items.length > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export default Selection;
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -100,7 +100,10 @@ import download from "common/download";
|
|||
export default {
|
||||
name: 'PAlbumClipboard',
|
||||
props: {
|
||||
selection: Array,
|
||||
selection: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
refresh: Function,
|
||||
clearSelection: Function,
|
||||
share: Function,
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
|
||||
<p-share-dialog :show="dialog.share" :model="album" @upload="webdavUpload"
|
||||
@close="dialog.share = false"></p-share-dialog>
|
||||
<p-share-upload-dialog :show="dialog.upload" :selection="[album.getId()]" @cancel="dialog.upload = false"
|
||||
<p-share-upload-dialog :show="dialog.upload" :items="{albums: album.getId()}" :model="album" @cancel="dialog.upload = false"
|
||||
@confirm="dialog.upload = false"></p-share-upload-dialog>
|
||||
<p-album-edit-dialog :show="dialog.edit" :album="album" @close="dialog.edit = false"></p-album-edit-dialog>
|
||||
</v-form>
|
||||
|
@ -75,9 +75,18 @@ import download from "common/download";
|
|||
export default {
|
||||
name: 'PAlbumToolbar',
|
||||
props: {
|
||||
album: Object,
|
||||
filter: Object,
|
||||
settings: Object,
|
||||
album: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
filter: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
settings: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
refresh: Function,
|
||||
filterChange: Function,
|
||||
},
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -69,7 +69,10 @@ import download from "common/download";
|
|||
export default {
|
||||
name: 'PFileClipboard',
|
||||
props: {
|
||||
selection: Array,
|
||||
selection: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
refresh: Function,
|
||||
clearSelection: Function,
|
||||
},
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -81,7 +81,10 @@ import download from "common/download";
|
|||
export default {
|
||||
name: 'PLabelClipboard',
|
||||
props: {
|
||||
selection: Array,
|
||||
selection: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
refresh: Function,
|
||||
clearSelection: Function,
|
||||
},
|
||||
|
|
|
@ -195,12 +195,21 @@ import {Input, InputInvalid, ClickShort, ClickLong} from "common/input";
|
|||
export default {
|
||||
name: 'PPhotoCards',
|
||||
props: {
|
||||
photos: Array,
|
||||
photos: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
openPhoto: Function,
|
||||
editPhoto: Function,
|
||||
openLocation: Function,
|
||||
album: Object,
|
||||
filter: Object,
|
||||
album: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
filter: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
context: String,
|
||||
selectMode: Boolean,
|
||||
},
|
||||
|
|
|
@ -148,7 +148,7 @@
|
|||
@confirm="batchDelete"></p-photo-delete-dialog>
|
||||
<p-photo-album-dialog :show="dialog.album" @cancel="dialog.album = false"
|
||||
@confirm="addToAlbum"></p-photo-album-dialog>
|
||||
<p-share-upload-dialog :show="dialog.share" :selection="selection" :album="album" @cancel="dialog.share = false"
|
||||
<p-share-upload-dialog :show="dialog.share" :items="{photos: selection}" :model="album" @cancel="dialog.share = false"
|
||||
@confirm="onShared"></p-share-upload-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -162,9 +162,15 @@ import Photo from "model/photo";
|
|||
export default {
|
||||
name: 'PPhotoClipboard',
|
||||
props: {
|
||||
selection: Array,
|
||||
selection: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
refresh: Function,
|
||||
album: Object,
|
||||
album: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
context: String,
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -117,12 +117,21 @@ import Notify from "common/notify";
|
|||
export default {
|
||||
name: 'PPhotoList',
|
||||
props: {
|
||||
photos: Array,
|
||||
photos: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
openPhoto: Function,
|
||||
editPhoto: Function,
|
||||
openLocation: Function,
|
||||
album: Object,
|
||||
filter: Object,
|
||||
album: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
filter: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
context: String,
|
||||
selectMode: Boolean,
|
||||
},
|
||||
|
|
|
@ -121,11 +121,20 @@ import {Input, InputInvalid, ClickShort, ClickLong} from "common/input";
|
|||
export default {
|
||||
name: 'PPhotoMosaic',
|
||||
props: {
|
||||
photos: Array,
|
||||
photos: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
openPhoto: Function,
|
||||
editPhoto: Function,
|
||||
album: Object,
|
||||
filter: Object,
|
||||
album: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
filter: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
context: String,
|
||||
selectMode: Boolean,
|
||||
},
|
||||
|
|
|
@ -156,8 +156,14 @@ export default {
|
|||
name: 'PPhotoToolbar',
|
||||
props: {
|
||||
dirty: Boolean,
|
||||
filter: Object,
|
||||
settings: Object,
|
||||
filter: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
settings: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
refresh: Function,
|
||||
filterChange: Function,
|
||||
},
|
||||
|
|
|
@ -177,7 +177,7 @@ export default {
|
|||
},
|
||||
openPlayer(video) {
|
||||
if (!video) {
|
||||
this.$notify.error("no video selected");
|
||||
this.$notify.error(this.$gettext("No video selected"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,10 @@ import download from "common/download";
|
|||
export default {
|
||||
name: 'PSubjectClipboard',
|
||||
props: {
|
||||
selection: Array,
|
||||
selection: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
refresh: Function,
|
||||
clearSelection: Function,
|
||||
},
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -274,7 +274,11 @@ export default {
|
|||
props: {
|
||||
show: Boolean,
|
||||
scope: String,
|
||||
model: Object,
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
const thumbs = this.$config.values.thumbs;
|
||||
|
@ -366,7 +370,7 @@ export default {
|
|||
},
|
||||
sizes(thumbs) {
|
||||
const result = [
|
||||
{"text": this.$gettext("Original"), "value": ""}
|
||||
{"text": this.$gettext("Originals"), "value": ""},
|
||||
];
|
||||
|
||||
for (let i = 0; i < thumbs.length; i++) {
|
||||
|
|
|
@ -30,7 +30,10 @@ export default {
|
|||
name: 'PAccountDeleteDialog',
|
||||
props: {
|
||||
show: Boolean,
|
||||
model: Object,
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -100,7 +100,10 @@ export default {
|
|||
name: 'PAlbumEditDialog',
|
||||
props: {
|
||||
show: Boolean,
|
||||
album: Object,
|
||||
album: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -128,8 +128,14 @@ export default {
|
|||
props: {
|
||||
index: Number,
|
||||
show: Boolean,
|
||||
selection: Array,
|
||||
album: Object,
|
||||
selection: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
album: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -217,7 +223,7 @@ export default {
|
|||
}
|
||||
|
||||
if (!this.selection || !this.selection[index]) {
|
||||
this.$notify.error("Invalid photo selected");
|
||||
this.$notify.error(this.$gettext("Invalid photo selected"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -231,7 +231,10 @@ import Util from "common/util";
|
|||
export default {
|
||||
name: 'PTabPhotoFiles',
|
||||
props: {
|
||||
model: Object,
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
uid: String,
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -268,7 +268,10 @@ import * as options from "options/options";
|
|||
export default {
|
||||
name: 'PTabPhotoAdvanced',
|
||||
props: {
|
||||
model: Object,
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
uid: String,
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -92,7 +92,10 @@ import Label from "model/label";
|
|||
export default {
|
||||
name: 'PTabPhotoLabels',
|
||||
props: {
|
||||
model: Object,
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
uid: String,
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -108,7 +108,10 @@
|
|||
export default {
|
||||
name: 'PTabPhotoPeople',
|
||||
props: {
|
||||
model: Object,
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
uid: String,
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<v-dialog v-model="show" lazy persistent max-width="500" class="p-share-dialog" @keydown.esc="close">
|
||||
<v-dialog :value="show" lazy persistent max-width="500" class="p-share-dialog" @keydown.esc="close">
|
||||
<v-card raised elevation="24">
|
||||
<v-card-title primary-title class="pb-0">
|
||||
<v-layout row wrap>
|
||||
|
@ -134,7 +134,10 @@ export default {
|
|||
name: 'PShareDialog',
|
||||
props: {
|
||||
show: Boolean,
|
||||
model: Object,
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -181,9 +184,9 @@ export default {
|
|||
try {
|
||||
const url = link.url();
|
||||
await Util.copyToMachineClipboard(url);
|
||||
this.$notify.success(this.$gettext("Copied to clipboard"))
|
||||
this.$notify.success(this.$gettext("Copied to clipboard"));
|
||||
} catch (error) {
|
||||
this.$notify.error(this.$gettext("Failed copying to clipboard"))
|
||||
this.$notify.error(this.$gettext("Failed copying to clipboard"));
|
||||
}
|
||||
},
|
||||
expires(link) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<v-dialog v-model="show" lazy persistent max-width="400" class="p-share-upload-dialog" @keydown.esc="cancel">
|
||||
<v-dialog :value="show" lazy persistent max-width="400" class="p-share-upload-dialog" @keydown.esc="cancel">
|
||||
<v-card raised elevation="24">
|
||||
<v-card-title primary-title class="pb-0">
|
||||
<v-layout row wrap>
|
||||
|
@ -68,12 +68,20 @@
|
|||
</template>
|
||||
<script>
|
||||
import Account from "model/account";
|
||||
import Selection from "common/selection";
|
||||
|
||||
export default {
|
||||
name: 'PShareUploadDialog',
|
||||
props: {
|
||||
show: Boolean,
|
||||
selection: Array,
|
||||
items: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
model: {
|
||||
type: Object,
|
||||
default: null,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -82,6 +90,7 @@ export default {
|
|||
search: null,
|
||||
account: {},
|
||||
accounts: [],
|
||||
selection: new Selection({}),
|
||||
path: "/",
|
||||
paths: [
|
||||
{"abs": "/"}
|
||||
|
@ -107,6 +116,8 @@ export default {
|
|||
show: function (show) {
|
||||
if (show) {
|
||||
this.load();
|
||||
} else if (this.selection) {
|
||||
this.selection.clear();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -129,7 +140,7 @@ export default {
|
|||
this.loading = false;
|
||||
|
||||
if (files.length === 1) {
|
||||
this.$notify.success("One file uploaded");
|
||||
this.$notify.success(this.$gettext("One file uploaded"));
|
||||
} else {
|
||||
this.$notify.success(this.$gettextInterpolate(this.$gettext("%{n} files uploaded"), {n: files.length}));
|
||||
}
|
||||
|
@ -154,6 +165,18 @@ export default {
|
|||
load() {
|
||||
this.loading = true;
|
||||
|
||||
this.selection.clear().addItems(this.items);
|
||||
|
||||
if (this.selection.isEmpty()) {
|
||||
this.selection.addModel(this.model);
|
||||
}
|
||||
|
||||
if (this.selection.isEmpty()) {
|
||||
this.loading = false;
|
||||
this.$emit('cancel');
|
||||
return;
|
||||
}
|
||||
|
||||
const params = {
|
||||
share: true,
|
||||
count: 1000,
|
||||
|
|
|
@ -59,7 +59,7 @@ export default {
|
|||
},
|
||||
play(fullscreen) {
|
||||
if (!this.video) {
|
||||
this.$notify.error("no video selected");
|
||||
this.$notify.error(this.$gettext("No video selected"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
@ -75,10 +75,16 @@ export class Account extends RestModel {
|
|||
);
|
||||
}
|
||||
|
||||
Share(photos, dest) {
|
||||
const values = { Photos: photos, Destination: dest };
|
||||
Share(selection, folder) {
|
||||
if (!selection) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Api.post(this.getEntityResource() + "/share", values).then((response) =>
|
||||
if (Array.isArray(selection)) {
|
||||
selection = { Photos: selection };
|
||||
}
|
||||
|
||||
return Api.post(this.getEntityResource() + "/share", { selection, folder }).then((response) =>
|
||||
Promise.resolve(response.data)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -198,7 +198,7 @@
|
|||
</v-container>
|
||||
<p-share-dialog :show="dialog.share" :model="model" @upload="webdavUpload"
|
||||
@close="dialog.share = false"></p-share-dialog>
|
||||
<p-share-upload-dialog :show="dialog.upload" :selection="selection" @cancel="dialog.upload = false"
|
||||
<p-share-upload-dialog :show="dialog.upload" :items="{albums: selection}" :model="model" @cancel="dialog.upload = false"
|
||||
@confirm="dialog.upload = false"></p-share-upload-dialog>
|
||||
<p-album-edit-dialog :show="dialog.edit" :album="model" @close="dialog.edit = false"></p-album-edit-dialog>
|
||||
</div>
|
||||
|
|
|
@ -135,7 +135,10 @@ import {ClickLong, ClickShort, Input, InputInvalid} from "common/input";
|
|||
export default {
|
||||
name: 'PPageFaces',
|
||||
props: {
|
||||
staticFilter: Object,
|
||||
staticFilter: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
active: Boolean,
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -180,7 +180,10 @@ import {ClickLong, ClickShort, Input, InputInvalid} from "common/input";
|
|||
export default {
|
||||
name: 'PPageSubjects',
|
||||
props: {
|
||||
staticFilter: Object,
|
||||
staticFilter: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
active: Boolean,
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -51,7 +51,10 @@ import download from "common/download";
|
|||
export default {
|
||||
name: 'PAlbumClipboard',
|
||||
props: {
|
||||
selection: Array,
|
||||
selection: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
refresh: Function,
|
||||
clearSelection: Function,
|
||||
context: String,
|
||||
|
|
|
@ -118,7 +118,10 @@ import {Input, InputInvalid, ClickShort, ClickLong} from "common/input";
|
|||
export default {
|
||||
name: 'PPageAlbums',
|
||||
props: {
|
||||
staticFilter: Object,
|
||||
staticFilter: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
view: String,
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -146,12 +146,21 @@ import {Input, InputInvalid, ClickShort, ClickLong} from "common/input";
|
|||
export default {
|
||||
name: 'PPhotoCards',
|
||||
props: {
|
||||
photos: Array,
|
||||
photos: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
openPhoto: Function,
|
||||
editPhoto: Function,
|
||||
openLocation: Function,
|
||||
album: Object,
|
||||
filter: Object,
|
||||
album: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
filter: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
context: String,
|
||||
selectMode: Boolean,
|
||||
},
|
||||
|
|
|
@ -54,9 +54,15 @@ import Photo from "model/photo";
|
|||
export default {
|
||||
name: 'PPhotoClipboard',
|
||||
props: {
|
||||
selection: Array,
|
||||
selection: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
refresh: Function,
|
||||
album: Object,
|
||||
album: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
context: String,
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -97,12 +97,21 @@ import Notify from "common/notify";
|
|||
export default {
|
||||
name: 'PPhotoList',
|
||||
props: {
|
||||
photos: Array,
|
||||
photos: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
openPhoto: Function,
|
||||
editPhoto: Function,
|
||||
openLocation: Function,
|
||||
album: Object,
|
||||
filter: Object,
|
||||
album: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
filter: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
context: String,
|
||||
selectMode: Boolean,
|
||||
},
|
||||
|
|
|
@ -100,11 +100,20 @@ import {Input, InputInvalid, ClickShort, ClickLong} from "common/input";
|
|||
export default {
|
||||
name: 'PPhotoMosaic',
|
||||
props: {
|
||||
photos: Array,
|
||||
photos: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
openPhoto: Function,
|
||||
editPhoto: Function,
|
||||
album: Object,
|
||||
filter: Object,
|
||||
album: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
filter: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
context: String,
|
||||
selectMode: Boolean,
|
||||
},
|
||||
|
|
|
@ -19,7 +19,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package acl
|
||||
|
|
|
@ -117,6 +117,8 @@ func GetAccountFolders(router *gin.RouterGroup) {
|
|||
})
|
||||
}
|
||||
|
||||
// ShareWithAccount uploads files to the selected account.
|
||||
//
|
||||
// GET /api/v1/accounts/:id/share
|
||||
//
|
||||
// Parameters:
|
||||
|
@ -146,8 +148,15 @@ func ShareWithAccount(router *gin.RouterGroup) {
|
|||
return
|
||||
}
|
||||
|
||||
dst := f.Destination
|
||||
files, err := query.FilesByUID(f.Photos, 1000, 0)
|
||||
folder := f.Folder
|
||||
|
||||
// Select files to be shared.
|
||||
o := query.FileSelection{
|
||||
Video: true,
|
||||
OriginalsOnly: m.ShareOriginals(),
|
||||
PrimaryOnly: !m.ShareOriginals(),
|
||||
}
|
||||
files, err := query.SelectedFiles(f.Selection, o)
|
||||
|
||||
if err != nil {
|
||||
AbortEntityNotFound(c)
|
||||
|
@ -157,7 +166,7 @@ func ShareWithAccount(router *gin.RouterGroup) {
|
|||
var aliases = make(map[string]int)
|
||||
|
||||
for _, file := range files {
|
||||
alias := path.Join(dst, file.ShareBase(0))
|
||||
alias := path.Join(folder, file.ShareBase(0))
|
||||
key := strings.ToLower(alias)
|
||||
|
||||
if seq := aliases[key]; seq > 0 {
|
||||
|
@ -175,6 +184,8 @@ func ShareWithAccount(router *gin.RouterGroup) {
|
|||
})
|
||||
}
|
||||
|
||||
// CreateAccount creates a new remote account configuration.
|
||||
//
|
||||
// POST /api/v1/accounts
|
||||
func CreateAccount(router *gin.RouterGroup) {
|
||||
router.POST("/accounts", func(c *gin.Context) {
|
||||
|
@ -219,6 +230,8 @@ func CreateAccount(router *gin.RouterGroup) {
|
|||
})
|
||||
}
|
||||
|
||||
// UpdateAccount updates a remote account configuration.
|
||||
//
|
||||
// PUT /api/v1/accounts/:id
|
||||
//
|
||||
// Parameters:
|
||||
|
@ -288,6 +301,8 @@ func UpdateAccount(router *gin.RouterGroup) {
|
|||
})
|
||||
}
|
||||
|
||||
// DeleteAccount removes a remote account configuration.
|
||||
//
|
||||
// DELETE /api/v1/accounts/:id
|
||||
//
|
||||
// Parameters:
|
||||
|
|
|
@ -365,7 +365,8 @@ func AddPhotosToAlbum(router *gin.RouterGroup) {
|
|||
return
|
||||
}
|
||||
|
||||
photos, err := query.PhotoSelection(f)
|
||||
// Fetch selection from index.
|
||||
photos, err := query.SelectedPhotos(f)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("album: %s", err)
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package api
|
||||
|
|
|
@ -44,7 +44,8 @@ func BatchPhotosArchive(router *gin.RouterGroup) {
|
|||
log.Infof("photos: archiving %s", sanitize.Log(f.String()))
|
||||
|
||||
if service.Config().BackupYaml() {
|
||||
photos, err := query.PhotoSelection(f)
|
||||
// Fetch selection from index.
|
||||
photos, err := query.SelectedPhotos(f)
|
||||
|
||||
if err != nil {
|
||||
AbortEntityNotFound(c)
|
||||
|
@ -107,7 +108,8 @@ func BatchPhotosRestore(router *gin.RouterGroup) {
|
|||
log.Infof("photos: restoring %s", sanitize.Log(f.String()))
|
||||
|
||||
if service.Config().BackupYaml() {
|
||||
photos, err := query.PhotoSelection(f)
|
||||
// Fetch selection from index.
|
||||
photos, err := query.SelectedPhotos(f)
|
||||
|
||||
if err != nil {
|
||||
AbortEntityNotFound(c)
|
||||
|
@ -168,7 +170,8 @@ func BatchPhotosApprove(router *gin.RouterGroup) {
|
|||
|
||||
log.Infof("photos: approving %s", sanitize.Log(f.String()))
|
||||
|
||||
photos, err := query.PhotoSelection(f)
|
||||
// Fetch selection from index.
|
||||
photos, err := query.SelectedPhotos(f)
|
||||
|
||||
if err != nil {
|
||||
AbortEntityNotFound(c)
|
||||
|
@ -267,7 +270,8 @@ func BatchPhotosPrivate(router *gin.RouterGroup) {
|
|||
// Update precalculated photo and file counts.
|
||||
logWarn("index", entity.UpdateCounts())
|
||||
|
||||
if photos, err := query.PhotoSelection(f); err == nil {
|
||||
// Fetch selection from index.
|
||||
if photos, err := query.SelectedPhotos(f); err == nil {
|
||||
for _, p := range photos {
|
||||
SavePhotoAsYaml(p)
|
||||
}
|
||||
|
@ -362,7 +366,8 @@ func BatchPhotosDelete(router *gin.RouterGroup) {
|
|||
|
||||
log.Infof("photos: deleting %s", sanitize.Log(f.String()))
|
||||
|
||||
photos, err := query.PhotoSelection(f)
|
||||
// Fetch selection from index.
|
||||
photos, err := query.SelectedPhotos(f)
|
||||
|
||||
if err != nil {
|
||||
AbortEntityNotFound(c)
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
//
|
||||
// Parameters:
|
||||
// hash: string The photo or video file hash as returned by the search API
|
||||
// type: string Video type
|
||||
// type: string Video format
|
||||
func GetVideo(router *gin.RouterGroup) {
|
||||
router.GET("/videos/:hash/:token/:type", func(c *gin.Context) {
|
||||
if InvalidPreviewToken(c) {
|
||||
|
|
|
@ -25,6 +25,8 @@ import (
|
|||
"github.com/photoprism/photoprism/pkg/sanitize"
|
||||
)
|
||||
|
||||
// CreateZip creates a zip file archive for download.
|
||||
//
|
||||
// POST /api/v1/zip
|
||||
func CreateZip(router *gin.RouterGroup) {
|
||||
router.POST("/zip", func(c *gin.Context) {
|
||||
|
@ -55,7 +57,8 @@ func CreateZip(router *gin.RouterGroup) {
|
|||
return
|
||||
}
|
||||
|
||||
files, err := query.FileSelection(f)
|
||||
// Select files to be downloaded.
|
||||
files, err := query.SelectedFiles(f, query.FileSelectionAll())
|
||||
|
||||
if err != nil {
|
||||
Error(c, http.StatusBadRequest, err, i18n.ErrZipFailed)
|
||||
|
@ -132,6 +135,8 @@ func CreateZip(router *gin.RouterGroup) {
|
|||
})
|
||||
}
|
||||
|
||||
// DownloadZip downloads a zip file archive.
|
||||
//
|
||||
// GET /api/v1/zip/:filename
|
||||
func DownloadZip(router *gin.RouterGroup) {
|
||||
router.GET("/zip/:filename", func(c *gin.Context) {
|
||||
|
@ -159,6 +164,7 @@ func DownloadZip(router *gin.RouterGroup) {
|
|||
})
|
||||
}
|
||||
|
||||
// addFileToZip adds a file to a zip archive.
|
||||
func addFileToZip(zipWriter *zip.Writer, fileName, fileAlias string) error {
|
||||
fileToZip, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package auto
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package classify
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package config
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package crop
|
||||
|
|
|
@ -137,3 +137,8 @@ func (m *Account) Save() error {
|
|||
func (m *Account) Create() error {
|
||||
return Db().Create(m).Error
|
||||
}
|
||||
|
||||
// ShareOriginals tests if the unmodified originals should be shared.
|
||||
func (m *Account) ShareOriginals() bool {
|
||||
return m.ShareSize == ""
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package face
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package form
|
||||
|
||||
type AccountShare struct {
|
||||
Photos []string `json:"photos"`
|
||||
Destination string `json:"destination"`
|
||||
Selection Selection `json:"selection"`
|
||||
Folder string `json:"folder"`
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package form
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package hub
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package places
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package i18n
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package maps
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package meta
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package migrate
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package nsfw
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package photoprism
|
||||
|
|
105
internal/query/file_selection.go
Normal file
105
internal/query/file_selection.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
package query
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
)
|
||||
|
||||
// FileSelection represents a selection filter to include/exclude certain files.
|
||||
type FileSelection struct {
|
||||
Video bool
|
||||
Sidecar bool
|
||||
PrimaryOnly bool
|
||||
OriginalsOnly bool
|
||||
SizeLimit int
|
||||
Include []string
|
||||
Exclude []string
|
||||
}
|
||||
|
||||
// FileSelectionAll returns options that include videos and sidecar files.
|
||||
func FileSelectionAll() FileSelection {
|
||||
return FileSelection{
|
||||
Video: true,
|
||||
Sidecar: true,
|
||||
PrimaryOnly: false,
|
||||
OriginalsOnly: false,
|
||||
SizeLimit: 0,
|
||||
Include: []string{},
|
||||
Exclude: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// SelectedFiles finds files based on the given selection form, e.g. for downloading or sharing.
|
||||
func SelectedFiles(f form.Selection, o FileSelection) (results entity.Files, err error) {
|
||||
if f.Empty() {
|
||||
return results, errors.New("no items selected")
|
||||
}
|
||||
|
||||
var concat string
|
||||
|
||||
switch DbDialect() {
|
||||
case MySQL:
|
||||
concat = "CONCAT(a.path, '/%')"
|
||||
case SQLite3:
|
||||
concat = "a.path || '/%'"
|
||||
default:
|
||||
return results, fmt.Errorf("unknown sql dialect: %s", DbDialect())
|
||||
}
|
||||
|
||||
where := fmt.Sprintf(`photos.photo_uid IN (?)
|
||||
OR photos.place_id IN (?)
|
||||
OR photos.photo_uid IN (SELECT photo_uid FROM files WHERE file_uid IN (?))
|
||||
OR photos.photo_path IN (
|
||||
SELECT a.path FROM folders a WHERE a.folder_uid IN (?) UNION
|
||||
SELECT b.path FROM folders a JOIN folders b ON b.path LIKE %s WHERE a.folder_uid IN (?))
|
||||
OR photos.photo_uid IN (SELECT photo_uid FROM photos_albums WHERE hidden = 0 AND album_uid IN (?))
|
||||
OR files.file_uid IN (SELECT file_uid FROM %s m WHERE m.subj_uid IN (?))
|
||||
OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN labels l ON pl.label_id = l.id AND l.deleted_at IS NULL WHERE l.label_uid IN (?))
|
||||
OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN categories c ON c.label_id = pl.label_id JOIN labels lc ON lc.id = c.category_id AND lc.deleted_at IS NULL WHERE lc.label_uid IN (?))`,
|
||||
concat, entity.Marker{}.TableName())
|
||||
|
||||
s := UnscopedDb().Table("files").
|
||||
Select("files.*").
|
||||
Joins("JOIN photos ON photos.id = files.photo_id").
|
||||
Where("photos.deleted_at IS NULL").
|
||||
Where("files.file_missing = 0").
|
||||
Where(where, f.Photos, f.Places, f.Files, f.Files, f.Files, f.Albums, f.Subjects, f.Labels, f.Labels).
|
||||
Group("files.id")
|
||||
|
||||
if o.OriginalsOnly {
|
||||
s = s.Where("file_root = '/'")
|
||||
}
|
||||
|
||||
if o.PrimaryOnly {
|
||||
s = s.Where("file_primary = 1")
|
||||
}
|
||||
|
||||
if !o.Sidecar {
|
||||
s = s.Where("file_sidecar = 0")
|
||||
}
|
||||
|
||||
if !o.Video {
|
||||
s = s.Where("file_video = 0")
|
||||
}
|
||||
|
||||
if o.SizeLimit > 0 {
|
||||
s = s.Where("file_size < ?", o.SizeLimit)
|
||||
}
|
||||
|
||||
if len(o.Include) > 0 {
|
||||
s = s.Where("file_type IN (?)", o.Include)
|
||||
}
|
||||
|
||||
if len(o.Exclude) > 0 {
|
||||
s = s.Where("file_type NOT IN (?)", o.Exclude)
|
||||
}
|
||||
|
||||
if result := s.Scan(&results); result.Error != nil {
|
||||
return results, result.Error
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
|
@ -8,8 +8,8 @@ import (
|
|||
"github.com/photoprism/photoprism/internal/form"
|
||||
)
|
||||
|
||||
// PhotoSelection queries all selected photos.
|
||||
func PhotoSelection(f form.Selection) (results entity.Photos, err error) {
|
||||
// SelectedPhotos finds photos based on the given selection form, e.g. for adding them to an album.
|
||||
func SelectedPhotos(f form.Selection) (results entity.Photos, err error) {
|
||||
if f.Empty() {
|
||||
return results, errors.New("no items selected")
|
||||
}
|
||||
|
@ -47,47 +47,3 @@ func PhotoSelection(f form.Selection) (results entity.Photos, err error) {
|
|||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// FileSelection queries all selected files e.g. for downloading.
|
||||
func FileSelection(f form.Selection) (results entity.Files, err error) {
|
||||
if f.Empty() {
|
||||
return results, errors.New("no items selected")
|
||||
}
|
||||
|
||||
var concat string
|
||||
|
||||
switch DbDialect() {
|
||||
case MySQL:
|
||||
concat = "CONCAT(a.path, '/%')"
|
||||
case SQLite3:
|
||||
concat = "a.path || '/%'"
|
||||
default:
|
||||
return results, fmt.Errorf("unknown sql dialect: %s", DbDialect())
|
||||
}
|
||||
|
||||
where := fmt.Sprintf(`photos.photo_uid IN (?)
|
||||
OR photos.place_id IN (?)
|
||||
OR photos.photo_uid IN (SELECT photo_uid FROM files WHERE file_uid IN (?))
|
||||
OR photos.photo_path IN (
|
||||
SELECT a.path FROM folders a WHERE a.folder_uid IN (?) UNION
|
||||
SELECT b.path FROM folders a JOIN folders b ON b.path LIKE %s WHERE a.folder_uid IN (?))
|
||||
OR photos.photo_uid IN (SELECT photo_uid FROM photos_albums WHERE hidden = 0 AND album_uid IN (?))
|
||||
OR files.file_uid IN (SELECT file_uid FROM %s m WHERE m.subj_uid IN (?))
|
||||
OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN labels l ON pl.label_id = l.id AND l.deleted_at IS NULL WHERE l.label_uid IN (?))
|
||||
OR photos.id IN (SELECT pl.photo_id FROM photos_labels pl JOIN categories c ON c.label_id = pl.label_id JOIN labels lc ON lc.id = c.category_id AND lc.deleted_at IS NULL WHERE lc.label_uid IN (?))`,
|
||||
concat, entity.Marker{}.TableName())
|
||||
|
||||
s := UnscopedDb().Table("files").
|
||||
Select("files.*").
|
||||
Joins("JOIN photos ON photos.id = files.photo_id").
|
||||
Where("photos.deleted_at IS NULL").
|
||||
Where("files.file_missing = 0").
|
||||
Where(where, f.Photos, f.Places, f.Files, f.Files, f.Files, f.Albums, f.Subjects, f.Labels, f.Labels).
|
||||
Group("files.id")
|
||||
|
||||
if result := s.Scan(&results); result.Error != nil {
|
||||
return results, result.Error
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ func TestPhotoSelection(t *testing.T) {
|
|||
Photos: []string{},
|
||||
}
|
||||
|
||||
r, err := PhotoSelection(f)
|
||||
r, err := SelectedPhotos(f)
|
||||
|
||||
assert.Equal(t, "no items selected", err.Error())
|
||||
assert.Empty(t, r)
|
||||
|
@ -24,7 +24,7 @@ func TestPhotoSelection(t *testing.T) {
|
|||
Photos: []string{"pt9jtdre2lvl0yh7", "pt9jtdre2lvl0yh8"},
|
||||
}
|
||||
|
||||
r, err := PhotoSelection(f)
|
||||
r, err := SelectedPhotos(f)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -41,7 +41,7 @@ func TestFileSelection(t *testing.T) {
|
|||
Photos: []string{},
|
||||
}
|
||||
|
||||
r, err := FileSelection(f)
|
||||
r, err := SelectedFiles(f, FileSelectionAll())
|
||||
|
||||
assert.Equal(t, "no items selected", err.Error())
|
||||
assert.Empty(t, r)
|
||||
|
@ -51,7 +51,7 @@ func TestFileSelection(t *testing.T) {
|
|||
Photos: []string{"pt9jtdre2lvl0yh7", "pt9jtdre2lvl0yh8"},
|
||||
}
|
||||
|
||||
r, err := FileSelection(f)
|
||||
r, err := SelectedFiles(f, FileSelectionAll())
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
@ -21,7 +21,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package query
|
||||
|
|
|
@ -24,7 +24,7 @@ Feel free to send an e-mail to hello@photoprism.app if you have questions,
|
|||
want to support our work, or just want to say hello.
|
||||
|
||||
Additional information can be found in our Developer Guide:
|
||||
https://docs.photoprism.app/developer-guide/
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
|
||||
*/
|
||||
package remote
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user