Cleaning before review

Signed-off-by: Louis Chemineau <louis@chmn.me>
This commit is contained in:
Louis Chemineau 2022-09-26 18:17:35 +02:00
parent e88d44909d
commit 57373f329a
8 changed files with 46 additions and 251 deletions

View File

@ -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' => '.*',

View File

@ -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']);

View File

@ -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 {

17
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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()

View File

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

View File

@ -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,
},