Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/bugfix/segments-permissions' int…
Browse files Browse the repository at this point in the history
…o lf-staging-main
  • Loading branch information
joanagmaia committed Jan 16, 2024
2 parents 4a6c6e6 + bf6d1c6 commit cd8ac85
Show file tree
Hide file tree
Showing 29 changed files with 251 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ class OrganizationCacheRepository {
replacements: {
id,
name: nameToCreateIdentity,
website: data.website,
website: data.website || null,
},
type: QueryTypes.INSERT,
transaction,
Expand Down
4 changes: 1 addition & 3 deletions backend/src/services/user/permissionChecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,7 @@ export default class PermissionChecker {
}

// Third, for project admin, we need to check if the user is admin of all segments
return this.currentSegments.every((segment) =>
this.adminSegments.includes(segment.projectGroupId),
)
return this.currentSegments.every((segment) => this.adminSegments.includes(segment.id))
})
}

Expand Down
17 changes: 15 additions & 2 deletions frontend/src/middleware/auth/segment-guard.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { hasAccessToProjectGroup } from '@/utils/segments';
import { hasAccessToProjectGroup, hasAccessToSegmentId } from '@/utils/segments';
import { useLfSegmentsStore } from '@/modules/lf/segments/store';

/**
* Segment Guard
Expand All @@ -19,7 +20,19 @@ export default async function ({ to, store, router }) {

await store.dispatch('auth/doWaitUntilInit');

if (!hasAccessToProjectGroup(to.params[to.meta.paramSegmentAccess])) {
const lsSegmentsStore = useLfSegmentsStore();
const isCheckingProjectGroup = to.meta.paramSegmentAccess.name === 'grandparent';
let hasPermission;

if (isCheckingProjectGroup) {
await lsSegmentsStore.listAdminProjectGroups();

hasPermission = hasAccessToProjectGroup(to.params[to.meta.paramSegmentAccess.parameter]);
} else {
hasPermission = hasAccessToSegmentId(to.params[to.meta.paramSegmentAccess.parameter]);
}

if (!hasPermission) {
router.push('/403');
}
}
114 changes: 72 additions & 42 deletions frontend/src/modules/dashboard/components/dashboard-project-group.vue
Original file line number Diff line number Diff line change
@@ -1,70 +1,81 @@
<template>
<img
v-if="isUrl(selectedProjectGroup.url)"
:src="selectedProjectGroup.url"
alt="Project group logo"
class="h-6 mb-3"
<div
v-if="loading"
v-loading="loading"
class="app-page-spinner h-16 !relative !min-h-5 mt-10"
/>
<div class="text-base font-semibold text-gray-900 mb-8 break-words">
{{ selectedProjectGroup.name }}
</div>

<div class="py-3">
<div class="text-2xs text-gray-400 mb-0.5">
Projects
<div v-else>
<img
v-if="isUrl(selectedProjectGroup.url)"
:src="selectedProjectGroup.url"
alt="Project group logo"
class="h-6 mb-3"
/>
<div class="text-base font-semibold text-gray-900 mb-8 break-words">
{{ selectedProjectGroup.name }}
</div>
<div class="text-xs text-gray-900">
{{ selectedProjectGroup.projects.length }}

<div class="py-3">
<div class="text-2xs text-gray-400 mb-0.5">
Projects
</div>
<div class="text-xs text-gray-900">
{{ selectedProjectGroup.projects.length }}
</div>
</div>
</div>

<div class="mt-8">
<el-button
class="btn btn--md btn--secondary btn--full mb-4"
@click="isDrawerOpen = true"
>
Projects list
</el-button>
<router-link
v-if="hasPermissionToEditProject && hasAccessToProjectGroup(selectedProjectGroup.id)"
:to="{
name: 'adminProjects',
params: {
id: selectedProjectGroup.id,
},
}"
>
<div class="mt-8">
<el-button
class="btn btn-link btn-link--md btn-link--primary btn--full"
class="btn btn--md btn--secondary btn--full mb-4"
@click="isDrawerOpen = true"
>
<i class="ri-external-link-line" />
<span>Settings</span>
Projects list
</el-button>
</router-link>
</div>
<router-link
v-if="hasPermissionToEditProject && hasAccessToProjectGroup(selectedProjectGroup.id)"
:to="{
name: 'adminProjects',
params: {
id: selectedProjectGroup.id,
},
}"
>
<el-button
class="btn btn-link btn-link--md btn-link--primary btn--full"
>
<i class="ri-external-link-line" />
<span>Settings</span>
</el-button>
</router-link>
</div>

<app-dashboard-project-group-drawer
v-if="isDrawerOpen"
v-model:is-visible="isDrawerOpen"
:project-group="selectedProjectGroup"
/>
<app-dashboard-project-group-drawer
v-if="isDrawerOpen"
v-model:is-visible="isDrawerOpen"
:project-group="selectedProjectGroup"
/>
</div>
</template>

<script setup>
import { storeToRefs } from 'pinia';
import { useLfSegmentsStore } from '@/modules/lf/segments/store';
import isUrl from '@/utils/isUrl';
import { ref, computed } from 'vue';
import { ref, computed, onMounted } from 'vue';
import { LfPermissions } from '@/modules/lf/lf-permissions';
import { mapGetters } from '@/shared/vuex/vuex.helpers';
import { hasAccessToProjectGroup } from '@/utils/segments';
import { PermissionChecker } from '@/modules/user/permission-checker';
import Roles from '@/security/roles';
import AppDashboardProjectGroupDrawer from './dashboard-project-group-drawer.vue';
const lsSegmentsStore = useLfSegmentsStore();
const { selectedProjectGroup } = storeToRefs(lsSegmentsStore);
const isDrawerOpen = ref(false);
const loading = ref(true);
const { currentTenant, currentUser } = mapGetters('auth');
const hasPermissionToEditProject = computed(
Expand All @@ -73,6 +84,25 @@ const hasPermissionToEditProject = computed(
currentUser.value,
).editProject,
);
const isProjectAdminUser = computed(() => {
const permissionChecker = new PermissionChecker(
currentTenant.value,
currentUser.value,
);
return permissionChecker.currentUserRolesIds.includes(Roles.values.projectAdmin);
});
onMounted(() => {
if (isProjectAdminUser.value) {
lsSegmentsStore.listAdminProjectGroups().finally(() => {
loading.value = false;
});
} else {
loading.value = false;
}
});
</script>

<script>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/modules/dashboard/pages/dashboard-page.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
</div>
<aside
v-if="selectedProjectGroup"
class="border-l border-gray-200 overflow-auto px-5 py-6 h-screen"
class="border-l border-gray-200 overflow-auto px-5 py-6 h-screen min-w-[15rem]"
>
<cr-dashboard-upgrade-plan-widget v-if="displayUpgradeWidget" class="mb-10" />
<app-dashboard-project-group />
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/modules/integration/integration-routes.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Layout from '@/modules/layout/components/layout.vue';
import Permissions from '@/security/permissions';
import { hasAccessToProjectGroup } from '@/utils/segments';

const IntegrationListPage = () => import(
'@/modules/integration/components/integration-list-page.vue'
Expand Down Expand Up @@ -57,7 +56,10 @@ export default [
meta: {
auth: true,
permission: Permissions.values.integrationRead,
paramSegmentAccess: 'grandparentId',
paramSegmentAccess: {
name: 'child',
parameter: 'id',
},
},
},
],
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/modules/lf/layout/components/lf-banners.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<span class="font-semibold mx-1">{{ integrationsWithErrors[0]?.name }}</span>
<span>has integrations with connectivity issues</span>
<router-link
v-if="hasAccessToSegmentId(integrationsWithErrors[0].id)"
:to="{
name: 'integration',
params: {
Expand Down Expand Up @@ -72,6 +73,7 @@
<span class="font-semibold mx-1">{{ integrationsWithNoData[0]?.name }}</span>
<span>has integrations that are not receiving activities</span>
<router-link
v-if="hasAccessToSegmentId(integrationsWithNoData[0].id)"
:to="{
name: 'integration',
params: {
Expand Down Expand Up @@ -163,7 +165,7 @@ import {
watch, ref, computed, onUnmounted,
} from 'vue';
import { IntegrationService } from '@/modules/integration/integration-service';
import { getSegmentsFromProjectGroup } from '@/utils/segments';
import { getSegmentsFromProjectGroup, hasAccessToSegmentId } from '@/utils/segments';
import { isCurrentDateAfterGivenWorkingDays } from '@/utils/date';
import { CrowdIntegrations } from '@/integrations/integrations-config';
import { useRoute } from 'vue-router';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const model = computed({
},
});
const queryProjectGroups = () => {
const queryProjectGroups = async () => {
loading.value = true;
return LfService.queryProjectGroups({
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/modules/lf/lf-routes.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Layout from '@/modules/layout/components/layout.vue';
import Permissions from '@/security/permissions';
import { hasAccessToProjectGroup } from '@/utils/segments';

const ProjectGroupsListPage = () => import(
'@/modules/lf/segments/pages/lf-project-groups-list-page.vue'
Expand Down Expand Up @@ -50,7 +49,10 @@ export default [
auth: true,
title: 'Admin Panel',
permission: Permissions.values.projectEdit,
paramSegmentAccess: 'id',
paramSegmentAccess: {
name: 'grandparent',
parameter: 'id',
},
},
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ import {
import AppFormItem from '@/shared/form/form-item.vue';
import statusOptions from '@/modules/lf/config/status';
import { useLfSegmentsStore } from '@/modules/lf/segments/store';
import { useRoute } from 'vue-router';
const emit = defineEmits(['update:modelValue']);
const props = defineProps({
Expand All @@ -137,6 +138,8 @@ const props = defineProps({
},
});
const route = useRoute();
const lsSegmentsStore = useLfSegmentsStore();
const {
createProject,
Expand Down Expand Up @@ -218,7 +221,10 @@ const onSubmit = () => {
model.value = false;
});
} else {
createProject(form)
createProject({
...form,
segments: [route.params.id],
})
.finally(() => {
submitLoading.value = false;
model.value = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ const props = defineProps({
type: String,
default: () => null,
},
parentId: {
type: String,
default: () => null,
},
grandparentSlug: {
type: String,
default: () => null,
Expand Down Expand Up @@ -224,7 +228,10 @@ const onSubmit = () => {
model.value = false;
});
} else {
createSubProject(form)
createSubProject({
...form,
segments: [props.parentId],
})
.finally(() => {
submitLoading.value = false;
model.value = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</button>
<template #dropdown>
<el-dropdown-item
v-if="hasPermissionToEditProjectGroup"
v-if="hasPermissionToEditProjectGroup && hasAccessToSegmentId(id)"
class="h-10 mb-1"
:command="editProjectGroup"
>
Expand All @@ -24,7 +24,7 @@
<span class="text-xs">Edit project group</span>
</el-dropdown-item>
<el-dropdown-item
v-if="hasPermissionToCreateProject"
v-if="hasPermissionToCreateProject && hasAccessToSegmentId(id)"
class="h-10 mb-1"
:command="addProject"
>
Expand All @@ -33,7 +33,7 @@
/><span class="text-xs">Add project</span>
</el-dropdown-item>
<el-divider
v-if="hasPermissionToEditProjectGroup || hasPermissionToCreateProject"
v-if="(hasPermissionToEditProjectGroup && hasAccessToSegmentId(id)) || (hasPermissionToCreateProject && hasAccessToSegmentId(id))"
class="border-gray-200 !my-2"
/>
<el-dropdown-item
Expand All @@ -56,6 +56,7 @@ import { useLfSegmentsStore } from '@/modules/lf/segments/store';
import { LfPermissions } from '@/modules/lf/lf-permissions';
import { mapGetters } from '@/shared/vuex/vuex.helpers';
import { computed } from 'vue';
import { hasAccessToSegmentId } from '@/utils/segments';
const emit = defineEmits(['onEditProjectGroup', 'onAddProject']);
Expand Down
Loading

0 comments on commit cd8ac85

Please sign in to comment.