Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added expiration date to collaborators #3086

Merged
merged 1 commit into from
Mar 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions apps/files/src/components/Collaborators/Collaborator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@
(me)
</translate>
</div>
<span class="oc-text"><span class="files-collaborators-collaborator-role">{{ originalRole.label }}</span><template v-if="collaborator.expires"> | <translate :translate-params="{expires: formDateFromNow(collaborator.expires)}">Expires: %{expires}</translate></template></span>
<span class="uk-text-meta files-collaborators-collaborator-share-type" v-text="$_ocCollaborators_collaboratorType(collaborator.shareType)" />
<span class="oc-text"><span class="files-collaborators-collaborator-role">{{ originalRole.label }}</span><template v-if="collaborator.expires"> | <translate class="files-collaborators-collaborator-expires" :translate-params="{expires: formDateFromNow(collaborator.expires)}">Expires %{expires}</translate></template></span>
</div>
</oc-table-cell>
<oc-table-cell shrink>
Expand Down Expand Up @@ -94,12 +94,14 @@
import { mapGetters } from 'vuex'
import { shareTypes } from '../../helpers/shareTypes'
import { basename, dirname } from 'path'
import Mixins from '../../mixins/collaborators'
import CollaboratorsMixins from '../../mixins/collaborators'
import Mixins from '../../mixins'

export default {
name: 'Collaborator',
mixins: [
Mixins
Mixins,
CollaboratorsMixins
],
props: {
collaborator: {
Expand Down
179 changes: 166 additions & 13 deletions apps/files/src/components/Collaborators/CollaboratorsEditOptions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,54 @@
:collaboratorsPermissions="collaboratorsPermissions"
@permissionChecked="checkAdditionalPermissions"
/>
<oc-grid v-if="$_ocCollaborators_expirationSupported" gutter="small">
<div class="uk-width-1-1">
<label class="oc-label" for="files-collaborators-new-collaborator-expiration">
<translate>Expiration date</translate>
<translate class="uk-text-meta uk-remove-margin">(optional)</translate>
</label>
<oc-text-input type="date" class="uk-width-1-1 oc-button-role" id="files-collaborators-new-collaborator-expiration" :value="expirationDate">04 - 07 - 2019</oc-text-input>
<div v-if="expirationSupported">
<label for="files-collaborators-collaborator-expiration-input">
<translate>Expiration date:</translate>
<translate v-if="expirationDateEnforced" tag="em">(required)</translate>
</label>
<div class="uk-position-relative">
<oc-datepicker
id="files-collaborators-collaborator-expiration-input"
:key="`collaborator-datepicker-${enteredExpirationDate}`"
:date="enteredExpirationDate"
:maxDatetime="maxExpirationDate"
:minDatetime="minExpirationDate"
:placeholder="expirationDatePlaceholder"
@input="setExpirationDate"
/>
<div
v-if="canResetExpirationDate"
id="files-collaborators-collaborator-expiration-delete"
class="uk-position-small uk-position-center-right oc-cursor-pointer"
:uk-tooltip="expirationDateRemoveTooltip"
@click="resetExpirationDate"
uk-close
/>
</div>
</oc-grid>
</div>
</oc-grid>
</template>

<script>
import { mapGetters } from 'vuex'
import moment from 'moment'
import collaboratorsMixins from '../../mixins/collaborators'
const RolesSelect = () => import('../Roles/RolesSelect.vue')
const AdditionalPermissions = () => import('./AdditionalPermissions.vue')
export default {
name: 'CollaboratorsEditOptions',
components: {
RolesSelect,
AdditionalPermissions
},
mixins: [
collaboratorsMixins
],
props: {
existingRole: {
type: Object,
Expand All @@ -51,19 +72,35 @@ export default {
required: false
},
expirationDate: {
type: String,
type: Date,
required: false
},
existingCollaboratorType: {
type: [Object, String],
required: false,
validator: function (value) {
return ['user', 'group'].indexOf(value) > -1 || value === null
}
}
},
data () {
return {
selectedRole: null,
additionalPermissions: null
additionalPermissions: null,
enteredExpirationDate: null
}
},
computed: {
$_ocCollaborators_expirationSupported () {
return false
...mapGetters(['capabilities']),
editingUser () {
return this.existingCollaboratorType === 'user'
},
editingGroup () {
return this.existingCollaboratorType === 'group'
},
$_ocCollaborators_hasAdditionalPermissions () {
Expand Down Expand Up @@ -98,8 +135,108 @@ export default {
}
return this.selectedRole
},
expirationSupported () {
return this.userExpirationDate && this.groupExpirationDate
},
defaultExpirationDateSet () {
if (this.editingUser) {
return this.userExpirationDate.enabled
}
if (this.editingGroup) {
return this.groupExpirationDate.enabled
}
return this.userExpirationDate.enabled || this.groupExpirationDate.enabled
},
userExpirationDate () {
return this.capabilities.files_sharing.user.expire_date
},
groupExpirationDate () {
return this.capabilities.files_sharing.group.expire_date
},
defaultExpirationDate () {
if (!this.defaultExpirationDateSet) {
return null
}
const userMaxExpirationDays = parseInt(this.userExpirationDate.days, 10)
const groupMaxExpirationDays = parseInt(this.groupExpirationDate.days, 10)
if (this.editingUser) {
return moment().add(userMaxExpirationDays, 'days').endOf('day').toISOString()
}
if (this.editingGroup) {
return moment().add(groupMaxExpirationDays, 'days').endOf('day').toISOString()
}
// Since we are not separating process for adding users and groups as collaborators
// we are using the one which is smaller as enforced date
let days = 0
if (userMaxExpirationDays && groupMaxExpirationDays) {
days = Math.min(userMaxExpirationDays, groupMaxExpirationDays)
} else {
days = userMaxExpirationDays || groupMaxExpirationDays
}
return moment().add(days, 'days').endOf('day').toISOString()
},
expirationDateEnforced () {
if (this.editingUser) {
return this.userExpirationDate.enforced
}
if (this.editingGroup) {
return this.groupExpirationDate.enforced
}
return this.userExpirationDate.enforced || this.groupExpirationDate.enforced
},
maxExpirationDate () {
if (!this.expirationDateEnforced) {
return null
}
return this.defaultExpirationDate
},
minExpirationDate () {
return moment().add(1, 'days').endOf('day').toISOString()
},
expirationDatePlaceholder () {
return this.$gettext('Expiration date')
},
expirationDateRemoveTooltip () {
return this.$gettext('Remove expiration date')
},
canResetExpirationDate () {
return !this.expirationDateEnforced && this.enteredExpirationDate
}
},
mounted () {
if (this.editingUser || this.editingGroup) {
// FIXME: Datepicker is not displaying correct timezone so for now we add it manually
// this.enteredExpirationDate = this.expirationDate ? moment(this.expirationDate).toISOString(true) : null
this.enteredExpirationDate = this.expirationDate ? moment(this.expirationDate).add(moment().utcOffset(), 'm').toISOString() : null
} else {
this.enteredExpirationDate = this.defaultExpirationDate
}
},
methods: {
selectRole (role) {
this.selectedRole = role
Expand All @@ -111,8 +248,24 @@ export default {
this.publishChange()
},
setExpirationDate (date) {
// Expiration date picker is emitting empty string when the component is initialised
// This ensures it will be null as we treat it everywhere in that way
this.enteredExpirationDate = date === '' ? null : date
this.publishChange()
},
resetExpirationDate () {
this.enteredExpirationDate = null
this.publishChange()
},
publishChange () {
this.$emit('optionChange', { role: this.selectedRole, permissions: this.additionalPermissions, expirationDate: this.expirationDate })
this.$emit('optionChange', {
role: this.selectedRole,
permissions: this.additionalPermissions,
expirationDate: this.enteredExpirationDate
})
}
}
}
Expand Down
49 changes: 47 additions & 2 deletions apps/files/src/components/Collaborators/EditCollaborator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
<collaborators-edit-options
:existingRole="$_originalRole"
:collaboratorsPermissions="$_originalPermissions"
:expirationDate="originalExpirationDate"
:existingCollaboratorType="collaboratorType"
@optionChange="collaboratorOptionChanged"
class="uk-margin-bottom"
/>
Expand All @@ -31,7 +33,9 @@
<script>
import filterObject from 'filter-obj'
import { mapGetters, mapActions } from 'vuex'
import moment from 'moment'
import { roleToBitmask, bitmaskToRole } from '../../helpers/collaborators'
import { shareTypes } from '../../helpers/shareTypes'
import Collaborator from './Collaborator.vue'
import CollaboratorsEditOptions from './CollaboratorsEditOptions.vue'
import Mixins from '../../mixins/collaborators'
Expand All @@ -55,13 +59,32 @@ export default {
return {
selectedRole: null,
additionalPermissions: null,
saving: false
saving: false,
expirationDate: null
}
},
computed: {
...mapGetters('Files', ['highlightedFile']),
...mapGetters(['user']),

collaboratorType () {
const collaboratorShareType = this.collaborator.shareType

if (
collaboratorShareType === shareTypes.user ||
collaboratorShareType === shareTypes.guest ||
collaboratorShareType === shareTypes.remote
) {
return 'user'
}

if (collaboratorShareType === shareTypes.group) {
return 'group'
}

return null
},

$_originalPermissions () {
const permissions = this.collaborator.customPermissions
return filterObject(permissions, (key, value) => value)
Expand All @@ -82,8 +105,28 @@ export default {
// if the role has changed, always return true. The user doesn't need to understand if two bitmasks of different roles are the same!
return true
}

// FIXME: Datepicker is not displaying correct timezone so for now we add it manually
const originalExpirationDate = this.originalExpirationDate
? moment(this.originalExpirationDate).add(moment().utcOffset(), 'm').toISOString()
: null

if (this.expirationDate !== originalExpirationDate) {
return true
}

const originalBitmask = roleToBitmask(this.$_originalRole, Object.keys(this.$_originalPermissions))
return originalBitmask !== this.$_permissionsBitmask
},

originalExpirationDate () {
const expirationDate = this.collaborator.expires

if (expirationDate) {
return expirationDate
}

return null
}
},
methods: {
Expand All @@ -100,7 +143,8 @@ export default {
share: this.collaborator,
// Map bitmask to role to get the correct role in case the advanced role was mapped to existing role
role: bitmaskToRole(bitmask, this.highlightedFile.type === 'folder'),
permissions: bitmask
permissions: bitmask,
expirationDate: this.expirationDate
})
.then(() => this.$_ocCollaborators_cancelChanges())
.catch(() => {
Expand All @@ -111,6 +155,7 @@ export default {
$_ocCollaborators_cancelChanges () {
this.selectedRole = null
this.additionalPermissions = null
this.expirationDate = this.originalExpirationDate
this.saving = false
this.close()
},
Expand Down
6 changes: 4 additions & 2 deletions apps/files/src/components/Collaborators/NewCollaborator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ export default {
selectedCollaborators: [],
selectedRole: null,
additionalPermissions: null,
saving: false
saving: false,
expirationDate: null
}
},
computed: {
Expand Down Expand Up @@ -209,7 +210,8 @@ export default {
$gettext: this.$gettext,
shareWith: collaborator.value.shareWith,
shareType: collaborator.value.shareType,
permissions: roleToBitmask(this.selectedRole, this.additionalPermissions)
permissions: roleToBitmask(this.selectedRole, this.additionalPermissions),
expirationDate: this.expirationDate
})))
})

Expand Down
3 changes: 2 additions & 1 deletion apps/files/src/mixins/collaborators.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@ export default {

return this.$gettext('Group')
},
collaboratorOptionChanged ({ role, permissions }) {
collaboratorOptionChanged ({ role, permissions, expirationDate }) {
this.selectedRole = role
this.additionalPermissions = permissions
this.expirationDate = expirationDate
}
}
}
Loading