Skip to content

Commit

Permalink
Preferences for not logged in users (public link context) (#10207)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexAndBear authored Jan 15, 2024
1 parent 56b5a08 commit 934b889
Show file tree
Hide file tree
Showing 23 changed files with 454 additions and 304 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Enable user preferences in public links

We've enabled user preferences in public links, so any user even without an account can open
preferences in a public link context and for example change the current language.

https://github.com/owncloud/web/pull/10207
8 changes: 7 additions & 1 deletion packages/web-app-admin-settings/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,13 @@ export default defineWebApplication({
isFileEditor: false,
applicationMenu: {
enabled: () => {
return userStore.user && can('read-all', 'Setting')
return (
userStore.user &&
(can('read-all', 'Setting') ||
can('read-all', 'Account') ||
can('read-all', 'Group') ||
can('read-all', 'Drive'))
)
},
priority: 40
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,11 @@ export default defineComponent({
})
})
const showWebDavDetails = computed(() => {
return store.getters['Files/areWebDavDetailsShown']
/**
* webDavPath might not be set when user is navigating on public link,
* even if the user is authenticated and the file owner.
*/
return store.getters['Files/areWebDavDetailsShown'] && unref(resource).webDavPath
})
const formatDateRelative = (date) => {
return formatRelativeDateFromJSDate(new Date(date), language.current)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,13 @@ export default defineComponent({
if (unref(resource)?.tags) {
selectedTags.value = unref(currentTags)
}
loadAvailableTagsTask.perform()
/**
* If the user can't edit the tags, for example on a public link, there is no need to load the available tags
*/
if (!unref(readonly)) {
loadAvailableTagsTask.perform()
}
})
const keydownMethods = (map, vm) => {
Expand Down
19 changes: 13 additions & 6 deletions packages/web-app-files/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,9 @@ const appInfo = {
icon: 'resource-type-folder',
color: 'var(--oc-color-swatch-primary-muted)',
isFileEditor: false,
extensions: [],
applicationMenu: {
enabled: () => true,
priority: 10
}
extensions: []
}

export const navItems = (context): AppNavigationItem[] => {
const spacesStores = useSpacesStore()
const userStore = useUserStore()
Expand Down Expand Up @@ -127,8 +124,18 @@ export const navItems = (context): AppNavigationItem[] => {

export default defineWebApplication({
setup() {
const userStore = useUserStore()

return {
appInfo,
appInfo: {
...appInfo,
applicationMenu: {
enabled: () => {
return !!userStore.user
},
priority: 10
}
},
store,
routes: buildRoutes({
App,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ describe('DriveResolver view', () => {
space,
internalSpace,
mocks: { $clientService: clientService },
isUserContextReady: true
userContextReady: true
})

await wrapper.vm.$nextTick()
Expand All @@ -94,7 +94,7 @@ describe('DriveResolver view', () => {
const { wrapper, mocks } = getMountedWrapper({
space,
mocks: { $clientService: clientService },
isUserContextReady: true
userContextReady: true
})

await wrapper.vm.$nextTick()
Expand All @@ -121,7 +121,7 @@ function getMountedWrapper({
space = undefined,
internalSpace = undefined,
currentRouteName = 'files-spaces-generic',
isUserContextReady = false,
userContextReady = false,
driveAliasAndItem = 'personal/einstein/file',
fileId = '1'
} = {}) {
Expand Down Expand Up @@ -157,7 +157,7 @@ function getMountedWrapper({
global: {
plugins: [
...defaultPlugins({
piniaOptions: { authState: { userContextReady: isUserContextReady } }
piniaOptions: { authState: { userContextReady: userContextReady } }
}),
store
],
Expand Down
10 changes: 8 additions & 2 deletions packages/web-app-ocm/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import App from './views/App.vue'
import { defineWebApplication, useRouter } from '@ownclouders/web-pkg'
import { defineWebApplication, useRouter, useUserStore } from '@ownclouders/web-pkg'
import translations from '../l10n/translations.json'
import { extensions } from './extensions'
import { RouteRecordRaw } from 'vue-router'
Expand Down Expand Up @@ -27,13 +27,19 @@ export default defineWebApplication({
setup() {
const { $gettext } = useGettext()
const router = useRouter()
const userStore = useUserStore()

const appInfo = {
name: $gettext('ScienceMesh'),
id: 'ocm',
color: '#AE291D',
icon: 'contacts-book',
isFileEditor: false
isFileEditor: false,
applicationMenu: {
enabled: () => {
return !!userStore.user
}
}
}

router.addRoute({
Expand Down
6 changes: 3 additions & 3 deletions packages/web-app-search/tests/unit/portals/SearchBar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ describe('Search Bar portal component', () => {
expect(wrapper.find(selectors.search).exists()).toBeFalsy()
})
test('does not render a search field if no user given', () => {
wrapper = getMountedWrapper({ isUserContextReady: false }).wrapper
wrapper = getMountedWrapper({ userContextReady: false }).wrapper
expect(wrapper.find(selectors.search).exists()).toBeFalsy()
})
test('updates the search term on input', () => {
Expand Down Expand Up @@ -228,7 +228,7 @@ describe('Search Bar portal component', () => {

function getMountedWrapper({
mocks = {},
isUserContextReady = true,
userContextReady = true,
providers = [providerFiles, providerContacts]
} = {}) {
jest.mocked(useAvailableProviders).mockReturnValue(ref(providers))
Expand All @@ -253,7 +253,7 @@ function getMountedWrapper({
global: {
plugins: [
...defaultPlugins({
piniaOptions: { authState: { userContextReady: isUserContextReady } }
piniaOptions: { authState: { userContextReady: userContextReady } }
}),
store
],
Expand Down
2 changes: 1 addition & 1 deletion packages/web-pkg/src/apps/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export interface ApplicationQuickAction {
export type AppConfigObject = Record<string, any>

export interface ApplicationMenuItem {
enabled?: () => boolean
enabled: () => boolean
priority?: number
openAsEditor?: boolean
}
Expand Down
2 changes: 1 addition & 1 deletion packages/web-pkg/src/composables/piniaStores/apps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const useAppsStore = defineStore('apps', () => {
}

unref(apps)[appInfo.id] = {
applicationMenu: appInfo.applicationMenu || {},
applicationMenu: appInfo.applicationMenu || { enabled: () => false },
defaultExtension: appInfo.defaultExtension || '',
icon: 'check_box_outline_blank',
name: appInfo.name || appInfo.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ describe('ResourceTable', () => {
const resource = mockDeep<Resource>({ id: '1', tags: ['1'] })
const { wrapper } = getMountedWrapper({
props: { resources: [resource] },
isUserContextReady: false
userContextReady: false
})
const resourceRow = wrapper.find(`[data-item-id="${resource.id}"]`)
expect(resourceRow.find('.resource-table-tag-wrapper').element.tagName).toEqual('SPAN')
Expand Down Expand Up @@ -456,7 +456,7 @@ describe('ResourceTable', () => {

function getMountedWrapper({
props = {},
isUserContextReady = true,
userContextReady = true,
addProcessingResources = false
} = {}) {
const storeOptions = defaultStoreMockOptions
Expand Down Expand Up @@ -494,7 +494,7 @@ function getMountedWrapper({
plugins: [
...defaultPlugins({
piniaOptions: {
authState: { userContextReady: isUserContextReady },
authState: { userContextReady: userContextReady },
capabilityState: { capabilities }
}
}),
Expand Down
43 changes: 24 additions & 19 deletions packages/web-runtime/src/components/Topbar/TopBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
v-if="appMenuItems.length && !isEmbedModeEnabled"
:applications-list="appMenuItems"
/>
<router-link
ref="navigationSidebarLogo"
v-oc-tooltip="$gettext('Back to home')"
to="/"
class="oc-width-1-1"
>
<oc-img :src="currentTheme.logo.topbar" :alt="sidebarLogoAlt" class="oc-logo-image" />
<router-link ref="navigationSidebarLogo" :to="homeLink" class="oc-width-1-1">
<oc-img
v-oc-tooltip="$gettext('Back to home')"
:src="currentTheme.logo.topbar"
:alt="sidebarLogoAlt"
class="oc-logo-image"
/>
</router-link>
</div>
<div v-if="!contentOnLeftPortal" class="oc-topbar-center">
Expand Down Expand Up @@ -56,13 +56,11 @@ import {
useAuthStore,
useCapabilityStore,
useEmbedMode,
useExtensionRegistry,
useRouter,
useStore,
useThemeStore
} from '@ownclouders/web-pkg'
import { isRuntimeRoute } from '../../router'
import { getExtensionNavItems } from '../../helpers/navItems'
export default {
components: {
Expand All @@ -83,7 +81,6 @@ export default {
setup(props) {
const store = useStore()
const capabilityStore = useCapabilityStore()
const extensionRegistry = useExtensionRegistry()
const themeStore = useThemeStore()
const { currentTheme } = storeToRefs(themeStore)
Expand All @@ -100,6 +97,17 @@ export default {
)
})
const homeLink = computed(() => {
if (authStore.publicLinkContextReady && !authStore.userContextReady) {
return {
name: 'resolvePublicLink',
params: { token: authStore.publicLinkToken }
}
}
return '/'
})
const isSideBarToggleVisible = computed(() => {
return authStore.userContextReady || authStore.publicLinkContextReady
})
Expand All @@ -115,7 +123,7 @@ export default {
}
/**
* Returns well formed menuItem objects by a list of extensions.
* Returns well-formed menuItem objects by a list of extensions.
* The following properties must be accessible in the wrapping code:
* - applicationsList
* - $language
Expand All @@ -128,14 +136,10 @@ export default {
return props.applicationsList
.filter((app) => {
if (app.type === 'extension') {
// check if the extension has at least one navItem with a matching menuId
return (
getExtensionNavItems({ extensionRegistry, appId: app.id }).filter((navItem) =>
isNavItemPermitted(permittedMenus, navItem)
).length > 0 ||
(app.applicationMenu.enabled instanceof Function &&
app.applicationMenu.enabled(store, ability) &&
!permittedMenus.includes('user'))
app.applicationMenu.enabled instanceof Function &&
app.applicationMenu.enabled(store, ability) &&
!permittedMenus.includes('user')
)
}
return isNavItemPermitted(permittedMenus, app)
Expand Down Expand Up @@ -209,7 +213,8 @@ export default {
logoWidth,
isEmbedModeEnabled,
isSideBarToggleVisible,
isSideBarToggleDisabled
isSideBarToggleDisabled,
homeLink
}
},
computed: {
Expand Down
Loading

0 comments on commit 934b889

Please sign in to comment.