mirror of https://github.com/nextcloud/photos
Cleaning before review
Signed-off-by: Louis Chemineau <louis@chmn.me>
This commit is contained in:
parent
e88d44909d
commit
57373f329a
|
@ -83,7 +83,6 @@ return [
|
|||
'path' => '.*',
|
||||
],
|
||||
],
|
||||
[ 'name' => 'public#get', 'url' => '/display/{token}', 'verb' => 'GET' ],
|
||||
['name' => 'page#index', 'url' => '/tags/{path}', 'verb' => 'GET', 'postfix' => 'tags',
|
||||
'requirements' => [
|
||||
'path' => '.*',
|
||||
|
|
|
@ -313,7 +313,6 @@ class AlbumMapper {
|
|||
break;
|
||||
case self::TYPE_LINK:
|
||||
$displayName = $this->l->t('Public link');
|
||||
;
|
||||
break;
|
||||
default:
|
||||
throw new \Exception('Invalid collaborator type: ' . $row['collaborator_type']);
|
||||
|
|
|
@ -90,26 +90,31 @@ class PhotosHome implements ICollection {
|
|||
}
|
||||
|
||||
public function getChild($name) {
|
||||
if ($name === 'albums') {
|
||||
return new AlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService);
|
||||
} elseif ($name === 'sharedalbums') {
|
||||
return new SharedAlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->groupManager, $this->userConfigService);
|
||||
} elseif ($name === 'public') {
|
||||
return new PublicAlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService);
|
||||
switch ($name) {
|
||||
case 'albums':
|
||||
return new AlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService);
|
||||
case 'sharedalbums':
|
||||
return new SharedAlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->groupManager, $this->userConfigService);
|
||||
case 'public':
|
||||
return new PublicAlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService);
|
||||
}
|
||||
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return (AlbumsHome|SharedAlbumsHome|PublicAlbumHome)[]
|
||||
* @return (AlbumsHome)[]
|
||||
*/
|
||||
public function getChildren(): array {
|
||||
return [new AlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService)];
|
||||
return [
|
||||
new AlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService),
|
||||
new SharedAlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->groupManager, $this->userConfigService),
|
||||
new PublicAlbumsHome($this->principalInfo, $this->albumMapper, $this->user, $this->rootFolder, $this->userConfigService),
|
||||
];
|
||||
}
|
||||
|
||||
public function childExists($name): bool {
|
||||
return $name === 'albums' || $name === 'sharedalbums';
|
||||
return $name === 'albums' || $name === 'sharedalbums' || $name === 'public';
|
||||
}
|
||||
|
||||
public function getLastModified(): int {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
"@nextcloud/moment": "^1.2.1",
|
||||
"@nextcloud/paths": "^2.1.0",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/sharing": "^0.1.0",
|
||||
"@nextcloud/upload": "^1.0.0-beta.8",
|
||||
"@nextcloud/vue": "^7.0.0-beta.4",
|
||||
"camelcase": "^7.0.0",
|
||||
|
@ -3395,6 +3396,14 @@
|
|||
"core-js": "^3.6.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/sharing": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/sharing/-/sharing-0.1.0.tgz",
|
||||
"integrity": "sha512-Cv4uc1aFrA18w0dltq7a5om/EbJSXf36rtO0LP3vi42E6l8ZDVCZwHLKrsZZa/TXNLeYErs1g/6tmWx5xiSSow==",
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/stylelint-config": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/stylelint-config/-/stylelint-config-2.2.0.tgz",
|
||||
|
@ -22612,6 +22621,14 @@
|
|||
"core-js": "^3.6.4"
|
||||
}
|
||||
},
|
||||
"@nextcloud/sharing": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/sharing/-/sharing-0.1.0.tgz",
|
||||
"integrity": "sha512-Cv4uc1aFrA18w0dltq7a5om/EbJSXf36rtO0LP3vi42E6l8ZDVCZwHLKrsZZa/TXNLeYErs1g/6tmWx5xiSSow==",
|
||||
"requires": {
|
||||
"core-js": "^3.6.4"
|
||||
}
|
||||
},
|
||||
"@nextcloud/stylelint-config": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/stylelint-config/-/stylelint-config-2.2.0.tgz",
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
"@nextcloud/moment": "^1.2.1",
|
||||
"@nextcloud/paths": "^2.1.0",
|
||||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/sharing": "^0.1.0",
|
||||
"@nextcloud/upload": "^1.0.0-beta.8",
|
||||
"@nextcloud/vue": "^7.0.0-beta.4",
|
||||
"camelcase": "^7.0.0",
|
||||
|
|
|
@ -140,6 +140,7 @@ import { showError } from '@nextcloud/dialogs'
|
|||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import { generateOcsUrl, generateUrl } from '@nextcloud/router'
|
||||
import { NcButton, NcListItemIcon, NcLoadingIcon, NcPopover, NcTextField, NcEmptyContent } from '@nextcloud/vue'
|
||||
import { Type } from '@nextcloud/sharing'
|
||||
|
||||
import logger from '../../services/logger.js'
|
||||
import AbortControllerMixin from '../../mixins/AbortControllerMixin.js'
|
||||
|
@ -149,7 +150,7 @@ import { fetchAlbum } from '../../services/Albums.js'
|
|||
* @typedef {object} Collaborator
|
||||
* @property {string} id - The id of the collaborator.
|
||||
* @property {string} label - The label of the collaborator for display.
|
||||
* @property {0|1|3} type - The type of the collaborator.
|
||||
* @property {Type.SHARE_TYPE_USER|Type.SHARE_TYPE_GROUP|Type.SHARE_TYPE_LINK} type - The type of the collaborator.
|
||||
*/
|
||||
|
||||
export default {
|
||||
|
@ -226,7 +227,7 @@ export default {
|
|||
*/
|
||||
listableSelectedCollaboratorsKeys() {
|
||||
return this.selectedCollaboratorsKeys
|
||||
.filter(collaboratorKey => this.availableCollaborators[collaboratorKey].type !== OC.Share.SHARE_TYPE_LINK)
|
||||
.filter(collaboratorKey => this.availableCollaborators[collaboratorKey].type !== Type.SHARE_TYPE_LINK)
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -241,12 +242,12 @@ export default {
|
|||
* @return {boolean}
|
||||
*/
|
||||
isPublicLinkSelected() {
|
||||
return this.selectedCollaboratorsKeys.includes(OC.Share.SHARE_TYPE_LINK.toString())
|
||||
return this.selectedCollaboratorsKeys.includes(`${Type.SHARE_TYPE_LINK}`)
|
||||
},
|
||||
|
||||
/** @return {Collaborator} */
|
||||
publicLink() {
|
||||
return this.availableCollaborators[OC.Share.SHARE_TYPE_LINK]
|
||||
return this.availableCollaborators[Type.SHARE_TYPE_LINK]
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -279,8 +280,8 @@ export default {
|
|||
search: this.searchText,
|
||||
itemType: 'share-recipients',
|
||||
shareTypes: [
|
||||
OC.Share.SHARE_TYPE_USER,
|
||||
OC.Share.SHARE_TYPE_GROUP,
|
||||
Type.SHARE_TYPE_USER,
|
||||
Type.SHARE_TYPE_GROUP,
|
||||
],
|
||||
},
|
||||
})
|
||||
|
@ -289,9 +290,9 @@ export default {
|
|||
.map(collaborator => {
|
||||
switch (collaborator.source) {
|
||||
case 'users':
|
||||
return { id: collaborator.id, label: collaborator.label, type: OC.Share.SHARE_TYPE_USER }
|
||||
return { id: collaborator.id, label: collaborator.label, type: Type.SHARE_TYPE_USER }
|
||||
case 'groups':
|
||||
return { id: collaborator.id, label: collaborator.label, type: OC.Share.SHARE_TYPE_GROUP }
|
||||
return { id: collaborator.id, label: collaborator.label, type: Type.SHARE_TYPE_GROUP }
|
||||
default:
|
||||
throw new Error(`Invalid collaborator source ${collaborator.source}`)
|
||||
}
|
||||
|
@ -322,7 +323,7 @@ export default {
|
|||
3: {
|
||||
id: '',
|
||||
label: t('photos', 'Public link'),
|
||||
type: OC.Share.SHARE_TYPE_LINK,
|
||||
type: Type.SHARE_TYPE_LINK,
|
||||
},
|
||||
...this.availableCollaborators,
|
||||
...initialCollaborators,
|
||||
|
@ -334,11 +335,11 @@ export default {
|
|||
* @param {Collaborator} collaborator - A collaborator
|
||||
*/
|
||||
indexCollaborators(collaborators, collaborator) {
|
||||
return { ...collaborators, [`${collaborator.type}${collaborator.type === OC.Share.SHARE_TYPE_LINK ? '' : ':'}${collaborator.type === OC.Share.SHARE_TYPE_LINK ? '' : collaborator.id}`]: collaborator }
|
||||
return { ...collaborators, [`${collaborator.type}${collaborator.type === Type.SHARE_TYPE_LINK ? '' : ':'}${collaborator.type === Type.SHARE_TYPE_LINK ? '' : collaborator.id}`]: collaborator }
|
||||
},
|
||||
|
||||
async createPublicLinkForAlbum() {
|
||||
this.selectEntity(OC.Share.SHARE_TYPE_LINK.toString())
|
||||
this.selectEntity(`${Type.SHARE_TYPE_LINK}`)
|
||||
await this.updateAlbumCollaborators()
|
||||
try {
|
||||
this.loadingAlbum = true
|
||||
|
@ -365,11 +366,11 @@ export default {
|
|||
},
|
||||
|
||||
async deletePublicLink() {
|
||||
this.unselectEntity(OC.Share.SHARE_TYPE_LINK.toString())
|
||||
this.unselectEntity(`${Type.SHARE_TYPE_LINK}`)
|
||||
this.availableCollaborators[3] = {
|
||||
id: '',
|
||||
label: t('photos', 'Public link'),
|
||||
type: OC.Share.SHARE_TYPE_LINK,
|
||||
type: Type.SHARE_TYPE_LINK,
|
||||
}
|
||||
this.publicLinkCopied = false
|
||||
await this.updateAlbumCollaborators()
|
||||
|
|
|
@ -1,213 +0,0 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2022 Louis Chemineau <louis@chmn.me>
|
||||
*
|
||||
* @author Louis Chemineau <louis@chmn.me>
|
||||
*
|
||||
* @license AGPL-3.0-or-later
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
|
||||
import client from '../services/DavClient.js'
|
||||
import logger from '../services/logger.js'
|
||||
import Semaphore from '../utils/semaphoreWithPriority.js'
|
||||
|
||||
/**
|
||||
* @typedef {object} Album
|
||||
* @property {string} basename - The name of the album.
|
||||
* @property {number} lastmod - The creation date of the album.
|
||||
* @property {string} size - The number of items in the album.
|
||||
*/
|
||||
|
||||
const state = {
|
||||
sharedAlbums: {},
|
||||
sharedAlbumsFiles: {},
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
/**
|
||||
* Add albums to the album collection.
|
||||
*
|
||||
* @param {object} state vuex state
|
||||
* @param {object} data destructuring object
|
||||
* @param {Array} data.albums list of albums
|
||||
*/
|
||||
addSharedAlbums(state, { albums }) {
|
||||
state.sharedAlbums = {
|
||||
...state.sharedAlbums,
|
||||
...albums.reduce((albums, album) => ({ ...albums, [album.basename]: album }), {}),
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove albums from the album collection.
|
||||
*
|
||||
* @param {object} state vuex state
|
||||
* @param {object} data destructuring object
|
||||
* @param {Array} data.albumNames list of albums ids
|
||||
*/
|
||||
removeSharedAlbums(state, { albumNames }) {
|
||||
albumNames.forEach(albumName => delete state.sharedAlbums[albumName])
|
||||
albumNames.forEach(albumName => delete state.sharedAlbumsFiles[albumName])
|
||||
},
|
||||
|
||||
/**
|
||||
* Add files to an album.
|
||||
*
|
||||
* @param {object} state vuex state
|
||||
* @param {object} data destructuring object
|
||||
* @param {string} data.albumName the album id
|
||||
* @param {string[]} data.fileIdsToAdd list of files
|
||||
*/
|
||||
addFilesToSharedAlbum(state, { albumName, fileIdsToAdd }) {
|
||||
const albumFiles = state.sharedAlbumsFiles[albumName] || []
|
||||
state.sharedAlbumsFiles = {
|
||||
...state.sharedAlbumsFiles,
|
||||
[albumName]: [
|
||||
...albumFiles,
|
||||
...fileIdsToAdd.filter(fileId => !albumFiles.includes(fileId)), // Filter to prevent duplicate fileId.
|
||||
],
|
||||
}
|
||||
state.sharedAlbums[albumName].nbItems += fileIdsToAdd.length
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove files to an album.
|
||||
*
|
||||
* @param {object} state vuex state
|
||||
* @param {object} data destructuring object
|
||||
* @param {string} data.albumName the album id
|
||||
* @param {string[]} data.fileIdsToRemove list of files
|
||||
*/
|
||||
removeFilesFromSharedAlbum(state, { albumName, fileIdsToRemove }) {
|
||||
state.sharedAlbumsFiles = {
|
||||
...state.sharedAlbumsFiles,
|
||||
[albumName]: state.sharedAlbumsFiles[albumName].filter(fileId => !fileIdsToRemove.includes(fileId)),
|
||||
}
|
||||
state.sharedAlbums[albumName].nbItems -= fileIdsToRemove.length
|
||||
},
|
||||
}
|
||||
|
||||
const getters = {
|
||||
sharedAlbums: state => state.sharedAlbums,
|
||||
sharedAlbumsFiles: state => state.sharedAlbumsFiles,
|
||||
}
|
||||
|
||||
const actions = {
|
||||
/**
|
||||
* Update files and albums
|
||||
*
|
||||
* @param {object} context vuex context
|
||||
* @param {object} data destructuring object
|
||||
* @param {Album[]} data.albums list of albums
|
||||
*/
|
||||
addSharedAlbums(context, { albums }) {
|
||||
context.commit('addSharedAlbums', { albums })
|
||||
},
|
||||
|
||||
/**
|
||||
* Add files to an album.
|
||||
*
|
||||
* @param {object} context vuex context
|
||||
* @param {object} data destructuring object
|
||||
* @param {string} data.albumName the album name
|
||||
* @param {string[]} data.fileIdsToAdd list of files ids to add
|
||||
*/
|
||||
async addFilesToSharedAlbum(context, { albumName, fileIdsToAdd }) {
|
||||
const semaphore = new Semaphore(5)
|
||||
|
||||
context.commit('addFilesToSharedAlbum', { albumName, fileIdsToAdd })
|
||||
|
||||
const promises = fileIdsToAdd
|
||||
.map(async (fileId) => {
|
||||
const file = context.getters.files[fileId]
|
||||
const album = context.getters.sharedAlbums[albumName]
|
||||
const symbol = await semaphore.acquire()
|
||||
|
||||
try {
|
||||
await client.copyFile(
|
||||
file.filename,
|
||||
`${album.filename}/${file.basename}`,
|
||||
)
|
||||
} catch (error) {
|
||||
if (error.response.status !== 409) { // Already in the album.
|
||||
context.commit('removeFilesFromSharedAlbum', { albumName, fileIdsToRemove: [fileId] })
|
||||
|
||||
logger.error(t('photos', 'Failed to add {fileBaseName} to shared album {albumName}.', { fileBaseName: file.basename, albumName }), error)
|
||||
showError(t('photos', 'Failed to add {fileBaseName} to shared album {albumName}.', { fileBaseName: file.basename, albumName }))
|
||||
}
|
||||
} finally {
|
||||
semaphore.release(symbol)
|
||||
}
|
||||
})
|
||||
|
||||
return Promise.all(promises)
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove files to an album.
|
||||
*
|
||||
* @param {object} context vuex context
|
||||
* @param {object} data destructuring object
|
||||
* @param {string} data.albumName the album name
|
||||
* @param {string[]} data.fileIdsToRemove list of files ids to remove
|
||||
*/
|
||||
async removeFilesFromSharedAlbum(context, { albumName, fileIdsToRemove }) {
|
||||
const semaphore = new Semaphore(5)
|
||||
|
||||
context.commit('removeFilesFromSharedAlbum', { albumName, fileIdsToRemove })
|
||||
|
||||
const promises = fileIdsToRemove
|
||||
.map(async (fileId) => {
|
||||
const file = context.getters.files[fileId]
|
||||
const symbol = await semaphore.acquire()
|
||||
|
||||
try {
|
||||
await client.deleteFile(file.filename)
|
||||
} catch (error) {
|
||||
context.commit('addFilesToSharedAlbum', { albumName, fileIdsToAdd: [fileId] })
|
||||
|
||||
logger.error(t('photos', 'Failed to delete {fileBaseName}.', { fileBaseName: file.basename }), error)
|
||||
showError(t('photos', 'Failed to delete {fileBaseName}.', { fileBaseName: file.basename }))
|
||||
} finally {
|
||||
semaphore.release(symbol)
|
||||
}
|
||||
})
|
||||
|
||||
return Promise.all(promises)
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete an album.
|
||||
*
|
||||
* @param {object} context vuex context
|
||||
* @param {object} data destructuring object
|
||||
* @param {string} data.albumName the id of the album
|
||||
*/
|
||||
async deleteSharedAlbum(context, { albumName }) {
|
||||
try {
|
||||
const album = context.getters.sharedAlbums[albumName]
|
||||
await client.deleteFile(album.filename)
|
||||
context.commit('removeSharedAlbums', { albumNames: [albumName] })
|
||||
} catch (error) {
|
||||
logger.error(t('photos', 'Failed to delete {albumName}.', { albumName }), error)
|
||||
showError(t('photos', 'Failed to delete {albumName}.', { albumName }))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export default { state, mutations, getters, actions }
|
|
@ -88,17 +88,6 @@
|
|||
</NcButton>
|
||||
</NcEmptyContent>
|
||||
</CollectionContent>
|
||||
|
||||
<!-- Modals -->
|
||||
<NcModal v-if="showAddPhotosModal"
|
||||
size="large"
|
||||
:title="t('photos', 'Add photos to the album')"
|
||||
@close="showAddPhotosModal = false">
|
||||
<FilesPicker :destination="album.basename"
|
||||
:blacklist-ids="albumFileIds"
|
||||
:loading="loadingAddFilesToAlbum"
|
||||
@files-picked="handleFilesPicked" />
|
||||
</NcModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -119,7 +108,6 @@ import AbortControllerMixin from '../mixins/AbortControllerMixin.js'
|
|||
import CollectionContent from '../components/Collection/CollectionContent.vue'
|
||||
import HeaderNavigation from '../components/HeaderNavigation.vue'
|
||||
// import ActionDownload from '../components/Actions/ActionDownload.vue'
|
||||
import FilesPicker from '../components/FilesPicker.vue'
|
||||
import { fetchAlbum, fetchAlbumContent } from '../services/Albums.js'
|
||||
import logger from '../services/logger.js'
|
||||
|
||||
|
@ -137,10 +125,8 @@ export default {
|
|||
NcActionButton,
|
||||
// NcActionSeparator,
|
||||
NcButton,
|
||||
NcModal,
|
||||
CollectionContent,
|
||||
// ActionDownload,
|
||||
FilesPicker,
|
||||
HeaderNavigation,
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in New Issue