WebDAV: Fix upload of complete albums #1376

This commit is contained in:
Michael Mayer
2022-02-27 17:32:54 +01:00
parent eb75a58f45
commit c256664a1b
116 changed files with 564 additions and 198 deletions

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package main package main

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View 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;

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -100,7 +100,10 @@ import download from "common/download";
export default { export default {
name: 'PAlbumClipboard', name: 'PAlbumClipboard',
props: { props: {
selection: Array, selection: {
type: Array,
default: () => [],
},
refresh: Function, refresh: Function,
clearSelection: Function, clearSelection: Function,
share: Function, share: Function,

View File

@@ -62,7 +62,7 @@
<p-share-dialog :show="dialog.share" :model="album" @upload="webdavUpload" <p-share-dialog :show="dialog.share" :model="album" @upload="webdavUpload"
@close="dialog.share = false"></p-share-dialog> @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> @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> <p-album-edit-dialog :show="dialog.edit" :album="album" @close="dialog.edit = false"></p-album-edit-dialog>
</v-form> </v-form>
@@ -75,9 +75,18 @@ import download from "common/download";
export default { export default {
name: 'PAlbumToolbar', name: 'PAlbumToolbar',
props: { props: {
album: Object, album: {
filter: Object, type: Object,
settings: Object, default: () => {},
},
filter: {
type: Object,
default: () => {},
},
settings: {
type: Object,
default: () => {},
},
refresh: Function, refresh: Function,
filterChange: Function, filterChange: Function,
}, },

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -69,7 +69,10 @@ import download from "common/download";
export default { export default {
name: 'PFileClipboard', name: 'PFileClipboard',
props: { props: {
selection: Array, selection: {
type: Array,
default: () => [],
},
refresh: Function, refresh: Function,
clearSelection: Function, clearSelection: Function,
}, },

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -81,7 +81,10 @@ import download from "common/download";
export default { export default {
name: 'PLabelClipboard', name: 'PLabelClipboard',
props: { props: {
selection: Array, selection: {
type: Array,
default: () => [],
},
refresh: Function, refresh: Function,
clearSelection: Function, clearSelection: Function,
}, },

View File

@@ -195,12 +195,21 @@ import {Input, InputInvalid, ClickShort, ClickLong} from "common/input";
export default { export default {
name: 'PPhotoCards', name: 'PPhotoCards',
props: { props: {
photos: Array, photos: {
type: Array,
default: () => [],
},
openPhoto: Function, openPhoto: Function,
editPhoto: Function, editPhoto: Function,
openLocation: Function, openLocation: Function,
album: Object, album: {
filter: Object, type: Object,
default: () => {},
},
filter: {
type: Object,
default: () => {},
},
context: String, context: String,
selectMode: Boolean, selectMode: Boolean,
}, },

View File

@@ -148,7 +148,7 @@
@confirm="batchDelete"></p-photo-delete-dialog> @confirm="batchDelete"></p-photo-delete-dialog>
<p-photo-album-dialog :show="dialog.album" @cancel="dialog.album = false" <p-photo-album-dialog :show="dialog.album" @cancel="dialog.album = false"
@confirm="addToAlbum"></p-photo-album-dialog> @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> @confirm="onShared"></p-share-upload-dialog>
</div> </div>
</template> </template>
@@ -162,9 +162,15 @@ import Photo from "model/photo";
export default { export default {
name: 'PPhotoClipboard', name: 'PPhotoClipboard',
props: { props: {
selection: Array, selection: {
type: Array,
default: () => [],
},
refresh: Function, refresh: Function,
album: Object, album: {
type: Object,
default: () => {},
},
context: String, context: String,
}, },
data() { data() {

View File

@@ -117,12 +117,21 @@ import Notify from "common/notify";
export default { export default {
name: 'PPhotoList', name: 'PPhotoList',
props: { props: {
photos: Array, photos: {
type: Array,
default: () => [],
},
openPhoto: Function, openPhoto: Function,
editPhoto: Function, editPhoto: Function,
openLocation: Function, openLocation: Function,
album: Object, album: {
filter: Object, type: Object,
default: () => {},
},
filter: {
type: Object,
default: () => {},
},
context: String, context: String,
selectMode: Boolean, selectMode: Boolean,
}, },

View File

@@ -121,11 +121,20 @@ import {Input, InputInvalid, ClickShort, ClickLong} from "common/input";
export default { export default {
name: 'PPhotoMosaic', name: 'PPhotoMosaic',
props: { props: {
photos: Array, photos: {
type: Array,
default: () => [],
},
openPhoto: Function, openPhoto: Function,
editPhoto: Function, editPhoto: Function,
album: Object, album: {
filter: Object, type: Object,
default: () => {},
},
filter: {
type: Object,
default: () => {},
},
context: String, context: String,
selectMode: Boolean, selectMode: Boolean,
}, },

View File

@@ -156,8 +156,14 @@ export default {
name: 'PPhotoToolbar', name: 'PPhotoToolbar',
props: { props: {
dirty: Boolean, dirty: Boolean,
filter: Object, filter: {
settings: Object, type: Object,
default: () => {},
},
settings: {
type: Object,
default: () => {},
},
refresh: Function, refresh: Function,
filterChange: Function, filterChange: Function,
}, },

View File

@@ -177,7 +177,7 @@ export default {
}, },
openPlayer(video) { openPlayer(video) {
if (!video) { if (!video) {
this.$notify.error("no video selected"); this.$notify.error(this.$gettext("No video selected"));
return; return;
} }

View File

@@ -69,7 +69,10 @@ import download from "common/download";
export default { export default {
name: 'PSubjectClipboard', name: 'PSubjectClipboard',
props: { props: {
selection: Array, selection: {
type: Array,
default: () => [],
},
refresh: Function, refresh: Function,
clearSelection: Function, clearSelection: Function,
}, },

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -274,7 +274,11 @@ export default {
props: { props: {
show: Boolean, show: Boolean,
scope: String, scope: String,
model: Object, model: {
type: Object,
default: () => {
},
},
}, },
data() { data() {
const thumbs = this.$config.values.thumbs; const thumbs = this.$config.values.thumbs;
@@ -366,7 +370,7 @@ export default {
}, },
sizes(thumbs) { sizes(thumbs) {
const result = [ const result = [
{"text": this.$gettext("Original"), "value": ""} {"text": this.$gettext("Originals"), "value": ""},
]; ];
for (let i = 0; i < thumbs.length; i++) { for (let i = 0; i < thumbs.length; i++) {

View File

@@ -30,7 +30,10 @@ export default {
name: 'PAccountDeleteDialog', name: 'PAccountDeleteDialog',
props: { props: {
show: Boolean, show: Boolean,
model: Object, model: {
type: Object,
default: () => {},
},
}, },
data() { data() {
return { return {

View File

@@ -100,7 +100,10 @@ export default {
name: 'PAlbumEditDialog', name: 'PAlbumEditDialog',
props: { props: {
show: Boolean, show: Boolean,
album: Object, album: {
type: Object,
default: () => {},
},
}, },
data() { data() {
return { return {

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -128,8 +128,14 @@ export default {
props: { props: {
index: Number, index: Number,
show: Boolean, show: Boolean,
selection: Array, selection: {
album: Object, type: Array,
default: () => [],
},
album: {
type: Object,
default: () => {},
},
}, },
data() { data() {
return { return {
@@ -217,7 +223,7 @@ export default {
} }
if (!this.selection || !this.selection[index]) { if (!this.selection || !this.selection[index]) {
this.$notify.error("Invalid photo selected"); this.$notify.error(this.$gettext("Invalid photo selected"));
return; return;
} }

View File

@@ -231,7 +231,10 @@ import Util from "common/util";
export default { export default {
name: 'PTabPhotoFiles', name: 'PTabPhotoFiles',
props: { props: {
model: Object, model: {
type: Object,
default: () => {},
},
uid: String, uid: String,
}, },
data() { data() {

View File

@@ -268,7 +268,10 @@ import * as options from "options/options";
export default { export default {
name: 'PTabPhotoAdvanced', name: 'PTabPhotoAdvanced',
props: { props: {
model: Object, model: {
type: Object,
default: () => {},
},
uid: String, uid: String,
}, },
data() { data() {

View File

@@ -92,7 +92,10 @@ import Label from "model/label";
export default { export default {
name: 'PTabPhotoLabels', name: 'PTabPhotoLabels',
props: { props: {
model: Object, model: {
type: Object,
default: () => {},
},
uid: String, uid: String,
}, },
data() { data() {

View File

@@ -108,7 +108,10 @@
export default { export default {
name: 'PTabPhotoPeople', name: 'PTabPhotoPeople',
props: { props: {
model: Object, model: {
type: Object,
default: () => {},
},
uid: String, uid: String,
}, },
data() { data() {

View File

@@ -1,5 +1,5 @@
<template> <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 raised elevation="24">
<v-card-title primary-title class="pb-0"> <v-card-title primary-title class="pb-0">
<v-layout row wrap> <v-layout row wrap>
@@ -134,7 +134,10 @@ export default {
name: 'PShareDialog', name: 'PShareDialog',
props: { props: {
show: Boolean, show: Boolean,
model: Object, model: {
type: Object,
default: () => {},
},
}, },
data() { data() {
return { return {
@@ -181,9 +184,9 @@ export default {
try { try {
const url = link.url(); const url = link.url();
await Util.copyToMachineClipboard(url); await Util.copyToMachineClipboard(url);
this.$notify.success(this.$gettext("Copied to clipboard")) this.$notify.success(this.$gettext("Copied to clipboard"));
} catch (error) { } catch (error) {
this.$notify.error(this.$gettext("Failed copying to clipboard")) this.$notify.error(this.$gettext("Failed copying to clipboard"));
} }
}, },
expires(link) { expires(link) {

View File

@@ -1,5 +1,5 @@
<template> <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 raised elevation="24">
<v-card-title primary-title class="pb-0"> <v-card-title primary-title class="pb-0">
<v-layout row wrap> <v-layout row wrap>
@@ -68,12 +68,20 @@
</template> </template>
<script> <script>
import Account from "model/account"; import Account from "model/account";
import Selection from "common/selection";
export default { export default {
name: 'PShareUploadDialog', name: 'PShareUploadDialog',
props: { props: {
show: Boolean, show: Boolean,
selection: Array, items: {
type: Object,
default: null,
},
model: {
type: Object,
default: null,
}
}, },
data() { data() {
return { return {
@@ -82,6 +90,7 @@ export default {
search: null, search: null,
account: {}, account: {},
accounts: [], accounts: [],
selection: new Selection({}),
path: "/", path: "/",
paths: [ paths: [
{"abs": "/"} {"abs": "/"}
@@ -107,6 +116,8 @@ export default {
show: function (show) { show: function (show) {
if (show) { if (show) {
this.load(); this.load();
} else if (this.selection) {
this.selection.clear();
} }
} }
}, },
@@ -129,7 +140,7 @@ export default {
this.loading = false; this.loading = false;
if (files.length === 1) { if (files.length === 1) {
this.$notify.success("One file uploaded"); this.$notify.success(this.$gettext("One file uploaded"));
} else { } else {
this.$notify.success(this.$gettextInterpolate(this.$gettext("%{n} files uploaded"), {n: files.length})); this.$notify.success(this.$gettextInterpolate(this.$gettext("%{n} files uploaded"), {n: files.length}));
} }
@@ -154,6 +165,18 @@ export default {
load() { load() {
this.loading = true; 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 = { const params = {
share: true, share: true,
count: 1000, count: 1000,

View File

@@ -59,7 +59,7 @@ export default {
}, },
play(fullscreen) { play(fullscreen) {
if (!this.video) { if (!this.video) {
this.$notify.error("no video selected"); this.$notify.error(this.$gettext("No video selected"));
return; return;
} }

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: 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) { Share(selection, folder) {
const values = { Photos: photos, Destination: dest }; 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) Promise.resolve(response.data)
); );
} }

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -198,7 +198,7 @@
</v-container> </v-container>
<p-share-dialog :show="dialog.share" :model="model" @upload="webdavUpload" <p-share-dialog :show="dialog.share" :model="model" @upload="webdavUpload"
@close="dialog.share = false"></p-share-dialog> @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> @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> <p-album-edit-dialog :show="dialog.edit" :album="model" @close="dialog.edit = false"></p-album-edit-dialog>
</div> </div>

View File

@@ -135,7 +135,10 @@ import {ClickLong, ClickShort, Input, InputInvalid} from "common/input";
export default { export default {
name: 'PPageFaces', name: 'PPageFaces',
props: { props: {
staticFilter: Object, staticFilter: {
type: Object,
default: () => {},
},
active: Boolean, active: Boolean,
}, },
data() { data() {

View File

@@ -180,7 +180,10 @@ import {ClickLong, ClickShort, Input, InputInvalid} from "common/input";
export default { export default {
name: 'PPageSubjects', name: 'PPageSubjects',
props: { props: {
staticFilter: Object, staticFilter: {
type: Object,
default: () => {},
},
active: Boolean, active: Boolean,
}, },
data() { data() {

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -51,7 +51,10 @@ import download from "common/download";
export default { export default {
name: 'PAlbumClipboard', name: 'PAlbumClipboard',
props: { props: {
selection: Array, selection: {
type: Array,
default: () => [],
},
refresh: Function, refresh: Function,
clearSelection: Function, clearSelection: Function,
context: String, context: String,

View File

@@ -118,7 +118,10 @@ import {Input, InputInvalid, ClickShort, ClickLong} from "common/input";
export default { export default {
name: 'PPageAlbums', name: 'PPageAlbums',
props: { props: {
staticFilter: Object, staticFilter: {
type: Object,
default: () => {},
},
view: String, view: String,
}, },
data() { data() {

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -146,12 +146,21 @@ import {Input, InputInvalid, ClickShort, ClickLong} from "common/input";
export default { export default {
name: 'PPhotoCards', name: 'PPhotoCards',
props: { props: {
photos: Array, photos: {
type: Array,
default: () => [],
},
openPhoto: Function, openPhoto: Function,
editPhoto: Function, editPhoto: Function,
openLocation: Function, openLocation: Function,
album: Object, album: {
filter: Object, type: Object,
default: () => {},
},
filter: {
type: Object,
default: () => {},
},
context: String, context: String,
selectMode: Boolean, selectMode: Boolean,
}, },

View File

@@ -54,9 +54,15 @@ import Photo from "model/photo";
export default { export default {
name: 'PPhotoClipboard', name: 'PPhotoClipboard',
props: { props: {
selection: Array, selection: {
type: Array,
default: () => [],
},
refresh: Function, refresh: Function,
album: Object, album: {
type: Object,
default: () => {},
},
context: String, context: String,
}, },
data() { data() {

View File

@@ -97,12 +97,21 @@ import Notify from "common/notify";
export default { export default {
name: 'PPhotoList', name: 'PPhotoList',
props: { props: {
photos: Array, photos: {
type: Array,
default: () => [],
},
openPhoto: Function, openPhoto: Function,
editPhoto: Function, editPhoto: Function,
openLocation: Function, openLocation: Function,
album: Object, album: {
filter: Object, type: Object,
default: () => {},
},
filter: {
type: Object,
default: () => {},
},
context: String, context: String,
selectMode: Boolean, selectMode: Boolean,
}, },

View File

@@ -100,11 +100,20 @@ import {Input, InputInvalid, ClickShort, ClickLong} from "common/input";
export default { export default {
name: 'PPhotoMosaic', name: 'PPhotoMosaic',
props: { props: {
photos: Array, photos: {
type: Array,
default: () => [],
},
openPhoto: Function, openPhoto: Function,
editPhoto: Function, editPhoto: Function,
album: Object, album: {
filter: Object, type: Object,
default: () => {},
},
filter: {
type: Object,
default: () => {},
},
context: String, context: String,
selectMode: Boolean, selectMode: Boolean,
}, },

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package acl package acl

View File

@@ -117,6 +117,8 @@ func GetAccountFolders(router *gin.RouterGroup) {
}) })
} }
// ShareWithAccount uploads files to the selected account.
//
// GET /api/v1/accounts/:id/share // GET /api/v1/accounts/:id/share
// //
// Parameters: // Parameters:
@@ -146,8 +148,15 @@ func ShareWithAccount(router *gin.RouterGroup) {
return return
} }
dst := f.Destination folder := f.Folder
files, err := query.FilesByUID(f.Photos, 1000, 0)
// 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 { if err != nil {
AbortEntityNotFound(c) AbortEntityNotFound(c)
@@ -157,7 +166,7 @@ func ShareWithAccount(router *gin.RouterGroup) {
var aliases = make(map[string]int) var aliases = make(map[string]int)
for _, file := range files { for _, file := range files {
alias := path.Join(dst, file.ShareBase(0)) alias := path.Join(folder, file.ShareBase(0))
key := strings.ToLower(alias) key := strings.ToLower(alias)
if seq := aliases[key]; seq > 0 { 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 // POST /api/v1/accounts
func CreateAccount(router *gin.RouterGroup) { func CreateAccount(router *gin.RouterGroup) {
router.POST("/accounts", func(c *gin.Context) { 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 // PUT /api/v1/accounts/:id
// //
// Parameters: // Parameters:
@@ -288,6 +301,8 @@ func UpdateAccount(router *gin.RouterGroup) {
}) })
} }
// DeleteAccount removes a remote account configuration.
//
// DELETE /api/v1/accounts/:id // DELETE /api/v1/accounts/:id
// //
// Parameters: // Parameters:

View File

@@ -365,7 +365,8 @@ func AddPhotosToAlbum(router *gin.RouterGroup) {
return return
} }
photos, err := query.PhotoSelection(f) // Fetch selection from index.
photos, err := query.SelectedPhotos(f)
if err != nil { if err != nil {
log.Errorf("album: %s", err) log.Errorf("album: %s", err)

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package api package api

View File

@@ -44,7 +44,8 @@ func BatchPhotosArchive(router *gin.RouterGroup) {
log.Infof("photos: archiving %s", sanitize.Log(f.String())) log.Infof("photos: archiving %s", sanitize.Log(f.String()))
if service.Config().BackupYaml() { if service.Config().BackupYaml() {
photos, err := query.PhotoSelection(f) // Fetch selection from index.
photos, err := query.SelectedPhotos(f)
if err != nil { if err != nil {
AbortEntityNotFound(c) AbortEntityNotFound(c)
@@ -107,7 +108,8 @@ func BatchPhotosRestore(router *gin.RouterGroup) {
log.Infof("photos: restoring %s", sanitize.Log(f.String())) log.Infof("photos: restoring %s", sanitize.Log(f.String()))
if service.Config().BackupYaml() { if service.Config().BackupYaml() {
photos, err := query.PhotoSelection(f) // Fetch selection from index.
photos, err := query.SelectedPhotos(f)
if err != nil { if err != nil {
AbortEntityNotFound(c) AbortEntityNotFound(c)
@@ -168,7 +170,8 @@ func BatchPhotosApprove(router *gin.RouterGroup) {
log.Infof("photos: approving %s", sanitize.Log(f.String())) 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 { if err != nil {
AbortEntityNotFound(c) AbortEntityNotFound(c)
@@ -267,7 +270,8 @@ func BatchPhotosPrivate(router *gin.RouterGroup) {
// Update precalculated photo and file counts. // Update precalculated photo and file counts.
logWarn("index", entity.UpdateCounts()) 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 { for _, p := range photos {
SavePhotoAsYaml(p) SavePhotoAsYaml(p)
} }
@@ -362,7 +366,8 @@ func BatchPhotosDelete(router *gin.RouterGroup) {
log.Infof("photos: deleting %s", sanitize.Log(f.String())) 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 { if err != nil {
AbortEntityNotFound(c) AbortEntityNotFound(c)

View File

@@ -19,7 +19,7 @@ import (
// //
// Parameters: // Parameters:
// hash: string The photo or video file hash as returned by the search API // 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) { func GetVideo(router *gin.RouterGroup) {
router.GET("/videos/:hash/:token/:type", func(c *gin.Context) { router.GET("/videos/:hash/:token/:type", func(c *gin.Context) {
if InvalidPreviewToken(c) { if InvalidPreviewToken(c) {

View File

@@ -25,6 +25,8 @@ import (
"github.com/photoprism/photoprism/pkg/sanitize" "github.com/photoprism/photoprism/pkg/sanitize"
) )
// CreateZip creates a zip file archive for download.
//
// POST /api/v1/zip // POST /api/v1/zip
func CreateZip(router *gin.RouterGroup) { func CreateZip(router *gin.RouterGroup) {
router.POST("/zip", func(c *gin.Context) { router.POST("/zip", func(c *gin.Context) {
@@ -55,7 +57,8 @@ func CreateZip(router *gin.RouterGroup) {
return return
} }
files, err := query.FileSelection(f) // Select files to be downloaded.
files, err := query.SelectedFiles(f, query.FileSelectionAll())
if err != nil { if err != nil {
Error(c, http.StatusBadRequest, err, i18n.ErrZipFailed) 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 // GET /api/v1/zip/:filename
func DownloadZip(router *gin.RouterGroup) { func DownloadZip(router *gin.RouterGroup) {
router.GET("/zip/:filename", func(c *gin.Context) { 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 { func addFileToZip(zipWriter *zip.Writer, fileName, fileAlias string) error {
fileToZip, err := os.Open(fileName) fileToZip, err := os.Open(fileName)
if err != nil { if err != nil {

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package auto package auto

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package classify package classify

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package config package config

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package crop package crop

View File

@@ -137,3 +137,8 @@ func (m *Account) Save() error {
func (m *Account) Create() error { func (m *Account) Create() error {
return Db().Create(m).Error return Db().Create(m).Error
} }
// ShareOriginals tests if the unmodified originals should be shared.
func (m *Account) ShareOriginals() bool {
return m.ShareSize == ""
}

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package face package face

View File

@@ -1,6 +1,6 @@
package form package form
type AccountShare struct { type AccountShare struct {
Photos []string `json:"photos"` Selection Selection `json:"selection"`
Destination string `json:"destination"` Folder string `json:"folder"`
} }

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package form package form

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package hub package hub

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package places package places

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package i18n package i18n

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package maps package maps

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package meta package meta

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package migrate package migrate

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package nsfw package nsfw

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package photoprism package photoprism

View 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
}

View File

@@ -8,8 +8,8 @@ import (
"github.com/photoprism/photoprism/internal/form" "github.com/photoprism/photoprism/internal/form"
) )
// PhotoSelection queries all selected photos. // SelectedPhotos finds photos based on the given selection form, e.g. for adding them to an album.
func PhotoSelection(f form.Selection) (results entity.Photos, err error) { func SelectedPhotos(f form.Selection) (results entity.Photos, err error) {
if f.Empty() { if f.Empty() {
return results, errors.New("no items selected") return results, errors.New("no items selected")
} }
@@ -47,47 +47,3 @@ func PhotoSelection(f form.Selection) (results entity.Photos, err error) {
return results, nil 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
}

View File

@@ -14,7 +14,7 @@ func TestPhotoSelection(t *testing.T) {
Photos: []string{}, Photos: []string{},
} }
r, err := PhotoSelection(f) r, err := SelectedPhotos(f)
assert.Equal(t, "no items selected", err.Error()) assert.Equal(t, "no items selected", err.Error())
assert.Empty(t, r) assert.Empty(t, r)
@@ -24,7 +24,7 @@ func TestPhotoSelection(t *testing.T) {
Photos: []string{"pt9jtdre2lvl0yh7", "pt9jtdre2lvl0yh8"}, Photos: []string{"pt9jtdre2lvl0yh7", "pt9jtdre2lvl0yh8"},
} }
r, err := PhotoSelection(f) r, err := SelectedPhotos(f)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@@ -41,7 +41,7 @@ func TestFileSelection(t *testing.T) {
Photos: []string{}, Photos: []string{},
} }
r, err := FileSelection(f) r, err := SelectedFiles(f, FileSelectionAll())
assert.Equal(t, "no items selected", err.Error()) assert.Equal(t, "no items selected", err.Error())
assert.Empty(t, r) assert.Empty(t, r)
@@ -51,7 +51,7 @@ func TestFileSelection(t *testing.T) {
Photos: []string{"pt9jtdre2lvl0yh7", "pt9jtdre2lvl0yh8"}, Photos: []string{"pt9jtdre2lvl0yh7", "pt9jtdre2lvl0yh8"},
} }
r, err := FileSelection(f) r, err := SelectedFiles(f, FileSelectionAll())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package query package query

View File

@@ -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. want to support our work, or just want to say hello.
Additional information can be found in our Developer Guide: Additional information can be found in our Developer Guide:
https://docs.photoprism.app/developer-guide/ <https://docs.photoprism.app/developer-guide/>
*/ */
package remote package remote

Some files were not shown because too many files have changed in this diff Show More