Skip to content

Commit

Permalink
Show indirect link shares from parent resources
Browse files Browse the repository at this point in the history
Public link shares from parent resources are now shown in the public
link share panel with a "via" link to jump to the parent resource.
  • Loading branch information
Vincent Petry committed Jan 29, 2020
1 parent 8e797ae commit b4f290f
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 88 deletions.
101 changes: 99 additions & 2 deletions apps/files/src/components/FileLinkSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,57 @@
<a :href="link.url" target="_blank" :uk-tooltip="$_tooltipTextLink" class="uk-text-bold uk-text-truncate oc-files-file-link-url">{{ link.name }}</a>
<br>
<span class="uk-text-meta uk-text-break">
<span>{{ link.description }}</span>
<span class="oc-files-file-link-role">{{ link.description }}</span>
<template v-if="link.expiration"> |
<span v-translate>Expires</span> {{ formDateFromNow(link.expiration) }}
</template>
<template v-if="link.password"> |
<span v-translate>Password protected</span>
</template>
</span>
</oc-table-cell>
<oc-table-cell shrink class="uk-text-nowrap">
<oc-button :aria-label="$_publicLinkCopyLabel" variation="raw" class="oc-files-file-link-copy-url">
<oc-icon v-if="!linksCopied[link.url]" name="copy_to_clipboard" size="small"
v-clipboard:copy="link.url" v-clipboard:success="$_clipboardSuccessHandler"/>
<oc-icon v-else name="ready" size="small" class="oc-files-file-link-copied-url _clipboard-success-animation"/>
</oc-button>
<oc-button :aria-label="$_editButtonLabel" @click="$_editPublicLink(link)" variation="raw" class="oc-files-file-link-edit">
<oc-icon name="edit" size="small"/>
</oc-button>
</oc-table-cell>
</oc-table-row>
</oc-table>
</li>
</transition-group>
</section>
<section v-if="$_indirectLinks.length > 0" class="uk-margin-medium-bottom">
<div class="uk-text-bold">
<translate>Public Links Via Parent</translate>
</div>
<transition-group class="uk-list uk-list-divider uk-overflow-hidden"
enter-active-class="uk-animation-slide-left-medium"
leave-active-class="uk-animation-slide-right-medium uk-animation-reverse"
name="custom-classes-transition"
tag="ul">
<li v-for="link in $_indirectLinks" :key="'li-' + link.id">
<div class="uk-text-meta">
<router-link :to="$_getViaRouterParams(link)" :aria-label="$gettext('Navigate to parent')"
class="oc-files-file-link-via uk-flex uk-flex-middle">
<oc-icon name="exit_to_app" size="small" class="uk-preserve-width" />
<span class="oc-file-name uk-padding-remove uk-text-truncate files-collaborators-collaborator-via-label">{{ $_getViaLabel(link) }}</span>
</router-link>
</div>
<oc-table midldle class="files-file-links-link">
<oc-table-row class="files-file-links-link-table-row-info">
<oc-table-cell shrink>
<oc-icon name="lock" />
</oc-table-cell>
<oc-table-cell>
<a :href="link.url" target="_blank" :uk-tooltip="$_tooltipTextLink" class="uk-text-bold uk-text-truncate oc-files-file-link-url">{{ link.name }}</a>
<br>
<span class="uk-text-meta uk-text-break">
<span class="oc-files-file-link-role">{{ link.description }}</span>
<template v-if="link.expiration"> |
<span v-translate>Expires</span> {{ formDateFromNow(link.expiration) }}
</template>
Expand Down Expand Up @@ -83,9 +133,12 @@
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import { mapGetters, mapActions, mapState } from 'vuex'
import moment from 'moment'
import mixins from '../mixins'
import { shareTypes } from '../helpers/shareTypes'
import { basename, dirname } from 'path'
import { getParentPaths } from '../helpers/path'
const EditPublicLink = _ => import('./PublicLinksSidebar/EditPublicLink.vue')
Expand Down Expand Up @@ -145,6 +198,34 @@ export default {
computed: {
...mapGetters('Files', ['highlightedFile', 'links', 'linksLoading', 'linksError']),
...mapGetters(['getToken', 'capabilities']),
...mapState('Files', [
'sharesTree'
]),
$_indirectLinks () {
const allShares = []
const parentPaths = getParentPaths(this.highlightedFile.path, true)
if (parentPaths.length === 0) {
return []
}
// remove root entry
parentPaths.pop()
parentPaths.forEach((parentPath) => {
const shares = this.sharesTree[parentPath]
if (shares) {
shares.forEach((share) => {
if (share.outgoing && parseInt(share.info.share_type, 10) === shareTypes.link) {
share.key = 'indirect-link-' + share.info.id
allShares.push(share)
}
})
}
})
return allShares
},
$_links () {
return this.links.filter(link => {
Expand Down Expand Up @@ -201,6 +282,22 @@ export default {
expireDate: (this.$_expirationDate.days) ? moment().add(this.$_expirationDate.days, 'days').endOf('day').toISOString() : null
}
},
$_getViaLabel (link) {
const translated = this.$gettext('Via %{folderName}')
return this.$gettextInterpolate(translated, { folderName: basename(link.info.path) }, false)
},
$_getViaRouterParams (link) {
const viaPath = link.info.path
return {
name: 'files-list',
params: {
item: dirname(viaPath) || '/'
},
query: {
scrollTo: basename(viaPath)
}
}
},
$_removePublicLink (link) {
this.removeLink({
client: this.$client,
Expand Down
50 changes: 30 additions & 20 deletions apps/files/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import moment from 'moment'
import _ from 'lodash'
import { getParentPaths } from '../helpers/path'
import { bitmaskToRole, permissionsBitmask } from '../helpers/collaborators'
import { shareTypes } from '../helpers/shareTypes'
const { default: PQueue } = require('p-queue')

function _buildFile (file) {
Expand Down Expand Up @@ -182,8 +183,7 @@ function _buildSharedFile (file) {
}
}

function _buildLink (l, $gettext) {
const link = l.shareInfo
function _buildLink (link, $gettext) {
let description = ''

// FIXME: use bitmask matching with constants
Expand Down Expand Up @@ -214,6 +214,7 @@ function _buildLink (l, $gettext) {
password: !!(link.share_with && link.share_with_displayname),
expiration: (typeof link.expiration === 'string') ? moment(link.expiration).format('YYYY-MM-DD') : null,
itemSource: link.item_source,
info: link,
file: {
parent: link.file_parent,
source: link.file_source,
Expand All @@ -222,17 +223,25 @@ function _buildLink (l, $gettext) {
}
}

function _buildShare (s, file) {
function _buildShare (s, file, $gettext) {
if (parseInt(s.share_type, 10) === shareTypes.link) {
return _buildLink(s, $gettext)
}
return _buildCollaboratorShare(s, file)
}

function _buildCollaboratorShare (s, file) {
const share = {
shareType: parseInt(s.share_type, 10),
info: s
}
switch (s.share_type) {
case ('0'): // user share
switch (share.shareType) {
case (shareTypes.user): // user share
// TODO differentiate groups from users?
// fall through
case ('6'):
case (shareTypes.remote):
// fall through
case ('1'): // group share
case (shareTypes.group): // group share
share.role = bitmaskToRole(s.permissions, file.type === 'folder')
share.permissions = s.permissions
share.name = s.share_with // this is the recipient userid, rename to uid or subject? add separate field userName?
Expand Down Expand Up @@ -296,8 +305,9 @@ export default {
})
if (loadSharesTree) {
context.dispatch('loadSharesTree', {
client: client,
path: absolutePath
client,
path: absolutePath,
$gettext
})
}
}
Expand Down Expand Up @@ -563,7 +573,7 @@ export default {
client.shares.getShares(path, { reshares: true })
.then(data => {
context.commit('SHARES_LOAD', data.map(element => {
return _buildShare(element.shareInfo, context.getters.highlightedFile)
return _buildCollaboratorShare(element.shareInfo, context.getters.highlightedFile)
}))
context.commit('SHARES_LOADING', false)
})
Expand All @@ -583,7 +593,7 @@ export default {
client.shares.getShares(path, { shared_with_me: true })
.then(data => {
context.commit('INCOMING_SHARES_LOAD', data.map(element => {
return _buildShare(element.shareInfo, context.getters.highlightedFile)
return _buildCollaboratorShare(element.shareInfo, context.getters.highlightedFile)
}))
context.commit('INCOMING_SHARES_LOADING', false)
})
Expand Down Expand Up @@ -615,7 +625,7 @@ export default {

client.shares.updateShare(share.info.id, params)
.then((updatedShare) => {
commit('SHARES_UPDATE_SHARE', _buildShare(updatedShare.shareInfo, getters.highlightedFile))
commit('SHARES_UPDATE_SHARE', _buildCollaboratorShare(updatedShare.shareInfo, getters.highlightedFile))
commit('TOGGLE_COLLABORATOR_SAVING', false)
})
.catch(e => {
Expand All @@ -629,7 +639,7 @@ export default {
if (shareType === 1) {
client.shares.shareFileWithGroup(path, shareWith, { permissions: permissions })
.then(share => {
context.commit('SHARES_ADD_SHARE', _buildShare(share.shareInfo, context.getters.highlightedFile))
context.commit('SHARES_ADD_SHARE', _buildCollaboratorShare(share.shareInfo, context.getters.highlightedFile))
context.commit('SHARES_LOADING', false)
})
.catch(e => {
Expand All @@ -653,7 +663,7 @@ export default {

client.shares.shareFileWithUser(path, shareWith, { permissions: permissions, remoteUser: remoteShare })
.then(share => {
context.commit('SHARES_ADD_SHARE', _buildShare(share.shareInfo, context.getters.highlightedFile))
context.commit('SHARES_ADD_SHARE', _buildCollaboratorShare(share.shareInfo, context.getters.highlightedFile))
context.commit('SHARES_LOADING', false)
})
.catch(e => {
Expand Down Expand Up @@ -689,7 +699,7 @@ export default {
* This will add new entries into the shares tree and will
* not remove unrelated existing ones.
*/
loadSharesTree (context, { client, path }) {
loadSharesTree (context, { client, path, $gettext }) {
context.commit('SHARESTREE_ERROR', null)
// prune shares tree cache for all unrelated paths, keeping only
// existing relevant parent entries
Expand Down Expand Up @@ -720,7 +730,7 @@ export default {
client.shares.getShares(queryPath, { reshares: true })
.then(data => {
data.forEach(element => {
sharesTree[queryPath].push({ ..._buildShare(element.shareInfo, { type: 'folder' }), outgoing: true })
sharesTree[queryPath].push({ ..._buildShare(element.shareInfo, { type: 'folder' }, $gettext), outgoing: true })
})
})
.catch(error => {
Expand All @@ -734,7 +744,7 @@ export default {
client.shares.getShares(queryPath, { shared_with_me: true })
.then(data => {
data.forEach(element => {
sharesTree[queryPath].push({ ..._buildShare(element.shareInfo, { type: 'folder' }), incoming: true })
sharesTree[queryPath].push({ ..._buildCollaboratorShare(element.shareInfo, { type: 'folder' }), incoming: true })
})
})
.catch(error => {
Expand Down Expand Up @@ -795,7 +805,7 @@ export default {
.then(data => {
data.forEach(share => {
if (share.shareInfo.share_type === '3') {
context.commit('LINKS_ADD', _buildLink(share, $gettext))
context.commit('LINKS_ADD', _buildLink(share.shareInfo, $gettext))
}
})
})
Expand All @@ -812,7 +822,7 @@ export default {
context.commit('LINKS_LOADING', true)
client.shares.shareFileWithLink(path, params)
.then(data => {
const link = _buildLink(data, $gettext)
const link = _buildLink(data.shareInfo, $gettext)
context.commit('LINKS_ADD', link)
context.commit('LINKS_LOADING', false)
resolve(link)
Expand All @@ -828,7 +838,7 @@ export default {
context.commit('LINKS_LOADING', true)
client.shares.updateShare(id, params)
.then(data => {
const link = _buildLink(data, $gettext)
const link = _buildLink(data.shareInfo, $gettext)
context.commit('LINKS_UPDATE', link)
context.commit('LINKS_LOADING', false)
resolve(link)
Expand Down
6 changes: 4 additions & 2 deletions changelog/unreleased/2897
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
Enhancement: Show indirect outgoing shares in collaborators list
Enhancement: Show indirect outgoing shares in shares panel

Whenever outgoing shares exist on any parent resource from the currently viewed resource,
the collaborators panel will now show these outgoing shares with a link to jump to the matching parent
the shares panel will now show these outgoing shares with a link to jump to the matching parent
resource.
This applies to both indirect collaborators shares and also to indirect public link shares.

https://github.com/owncloud/phoenix/issues/2897
https://github.com/owncloud/phoenix/pull/2929
https://github.com/owncloud/phoenix/pull/2932
Original file line number Diff line number Diff line change
Expand Up @@ -935,43 +935,29 @@ Feature: Share by public link
Then the following resources should not have share indicators on the webUI
| simple-empty-folder |

@skip @yetToImplement @issue-2897
Scenario: sharing details of items inside a shared folder
@issue-2897
Scenario: sharing details of indirect items inside a shared folder
Given user "user1" has created folder "/simple-folder/sub-folder"
And user "user1" has uploaded file with content "test" to "/simple-folder/textfile.txt"
And user "user1" has created a public link share with following settings
And user "user1" has created a public link with following settings
| path | /simple-folder |
| name | Public Link |
And user "user1" has logged in using the webUI
When the user opens folder "simple-folder" using the webUI
And the user opens the link share dialog for folder "sub-folder"
Then public link "Public Link" should be listed as share receiver via "simple-folder" on the webUI
Then a link named "Public Link" should be listed with role "Viewer" in the public link list of resource "sub-folder" via "simple-folder" on the webUI

@skip @yetToImplement @issue-2897
Scenario: sharing details of multiple public link shares with different link names
@issue-2897
Scenario: sharing details of multiple indirect public link shares
Given user "user1" has created folder "/simple-folder/sub-folder"
And user "user1" has uploaded file with content "test" to "/simple-folder/sub-folder/textfile.txt"
And user "user1" has created a public link share with following settings
And user "user1" has created a public link with following settings
| path | /simple-folder |
| name | Public Link |
And user "user1" has created a public link share with following settings
And user "user1" has created a public link with following settings
| path | /simple-folder/sub-folder |
| name | strängé लिंक नाम (#2 &).नेपाली |
And user "user1" has logged in using the webUI
When the user opens folder "simple-folder" using the webUI
And the user opens the link share dialog for folder "sub-folder"
Then public link "Public Link" should be listed as share receiver via "simple-folder" on the webUI
When the user opens folder "sub-folder" using the webUI
And the user opens the link share dialog for file "textfile.txt"
Then public link "strängé लिंक नाम (#2 &).नेपाली" should be listed as share receiver via "sub-folder" on the webUI
And public link "Public Link" should be listed as share receiver via "simple-folder" on the webUI

@skip @yetToImplement @issue-2897
Scenario: sharing detail of items in the webUI shared by public links with empty name
Given user "user1" has uploaded file with content "test" to "/simple-folder/textfile.txt"
And user "user1" has created a public link share with following settings
| path | /simple-folder |
And user "user1" has logged in using the webUI
When the user opens folder "simple-folder" using the webUI
And the user opens the link share dialog for file "textfile.txt"
Then public link with last share token should be listed as share receiver via "simple-folder" on the webUI
When the user opens folder "simple-folder/sub-folder" directly on the webUI
Then a link named "Public Link" should be listed with role "Viewer" in the public link list of resource "textfile.txt" via "simple-folder" on the webUI
And a link named "strängé लिंक नाम (#2 &).नेपाली" should be listed with role "Viewer" in the public link list of resource "textfile.txt" via "sub-folder" on the webUI

Loading

0 comments on commit b4f290f

Please sign in to comment.