diff --git a/e2e-tests/pages/AccessPermissionsTab.ts b/e2e-tests/pages/AccessPermissionsTab.ts index a033183..d09be1b 100644 --- a/e2e-tests/pages/AccessPermissionsTab.ts +++ b/e2e-tests/pages/AccessPermissionsTab.ts @@ -18,6 +18,10 @@ export class AccessPermissionsTab extends BasePage { return this.page.getByRole('Button', {name: 'add'}); } + private get confirmButton() { + return this.page.getByRole('Button', {name: 'confirm'}); + } + async addPermission(username: string, role: string) { await this.usernameInput.fill(username); await this.page.getByRole('option', { name: username }).click(); @@ -27,6 +31,11 @@ export class AccessPermissionsTab extends BasePage { await this.addButton.click(); + + if (await this.confirmButton.count() > 0) { + await this.confirmButton.click(); + } + await expect(this.page.getByRole("cell", {name: username})).toBeVisible(); await expect(this.page.getByRole("cell", {name: role})).toBeVisible(); diff --git a/e2e-tests/pages/ActivityPage.ts b/e2e-tests/pages/ActivityPage.ts index dea4409..ec16570 100644 --- a/e2e-tests/pages/ActivityPage.ts +++ b/e2e-tests/pages/ActivityPage.ts @@ -29,6 +29,7 @@ export class ActivityPage extends BasePage { async createActivity(name: string, description: string, type: string): Promise { await this.createButton.click(); + await this.waitForPageLoad(); await this.nameInput.fill(name); await this.descriptionInput.fill(description); await this.typeDropdown.click(); diff --git a/e2e-tests/pages/DatasetListPage.ts b/e2e-tests/pages/DatasetListPage.ts index 24ad7c1..037e0e9 100644 --- a/e2e-tests/pages/DatasetListPage.ts +++ b/e2e-tests/pages/DatasetListPage.ts @@ -26,6 +26,15 @@ export class DatasetListPage extends BasePage { await expect(card).toContainText(dataset.description); } + async verifyDatasetEditable(dataset: { + name: string; + }): Promise { + const card = this.datasetCardWithName(dataset.name); + await expect(card + .locator('[data-testid^="edit-button"]') + .first()).toBeVisible(); + } + async useAnyDataset(): Promise { const card = this.page.locator('.dataset-card').first(); await card.locator('button:has-text("Select and proceed")').click(); diff --git a/e2e-tests/pages/MeasurePage.ts b/e2e-tests/pages/MeasurePage.ts new file mode 100644 index 0000000..8634baa --- /dev/null +++ b/e2e-tests/pages/MeasurePage.ts @@ -0,0 +1,8 @@ +import {BasePage} from './BasePage'; + +export class MeasurePage extends BasePage { + async visit(): Promise { + await this.page.goto('/measures'); + await this.waitForPageLoad(); + } +} diff --git a/e2e-tests/pages/ParticipantPage.ts b/e2e-tests/pages/ParticipantPage.ts new file mode 100644 index 0000000..47d0582 --- /dev/null +++ b/e2e-tests/pages/ParticipantPage.ts @@ -0,0 +1,8 @@ +import { BasePage } from './BasePage'; + +export class ParticipantPage extends BasePage { + async visit(): Promise { + await this.page.goto('/participants'); + await this.waitForPageLoad(); + } +} diff --git a/e2e-tests/tests/process.spec.ts b/e2e-tests/tests/process.spec.ts index e5faf15..8eae517 100644 --- a/e2e-tests/tests/process.spec.ts +++ b/e2e-tests/tests/process.spec.ts @@ -14,6 +14,7 @@ import { RegistrationPage } from '../pages/RegistrationPage'; import {SettingsPage} from "../pages/SettingsPage"; import {AccessPermissionsTab} from "../pages/AccessPermissionsTab"; import generateDate from '../utils/generate-date-util'; +import {MeasurePage} from "../pages/MeasurePage"; const hash = Math.random().toString(36).substring(2); @@ -360,7 +361,7 @@ test.describe.serial('Przejście całego procesu', () => { await registrationPage.register(usernameOther, emailOther, emailOther, firstNameOther, lastNameOther); }); - test('[12] - Użytkownik dodaje uprawnienia dostępu', async ({ userPage }) => { + test('[12] - Użytkownik dodaje uprawnienia dostępu do odczytu', async ({ userPage }) => { await selectDataset(userPage); await new SettingsPage(userPage).visit(); const accessPermissionsTab = new AccessPermissionsTab(userPage); @@ -368,7 +369,7 @@ test.describe.serial('Przejście całego procesu', () => { await accessPermissionsTab.addPermission(usernameOther, 'Reader'); }); - test('[13] - Inny użytkonik nie może tworzyć eksperymentu', async ({ otherUserPage }) => { + test('[13] - Inny użytkonik [Reader] nie może tworzyć eksperymentu', async ({ otherUserPage }) => { await selectDataset(otherUserPage); const experimentPage = new ExperimentPage(otherUserPage); @@ -376,7 +377,8 @@ test.describe.serial('Przejście całego procesu', () => { await expect(otherUserPage.getByRole('Button', { name: 'Create' }).first()).toHaveCount(0); }); - test('[14] - Inny użytkonik nie może edytować składowych eksperymentu', async ({ otherUserPage }) => { + test('[14] - Inny użytkonik [Reader] nie może edytować składowych eksperymentu', async ({ otherUserPage }) => { + await selectDataset(otherUserPage); await (new ExperimentListPage(otherUserPage)).useExperimentByName(newExperiment.name); @@ -397,6 +399,95 @@ test.describe.serial('Przejście całego procesu', () => { await recordingsTab.visit(); await expect(otherUserPage.getByRole('Button', { name: 'Create' }).first()).toHaveCount(0); }); + + test('[15] - Inny użytkonik [Reader] nie może tworzyć aktywności', async ({ otherUserPage }) => { + await selectDataset(otherUserPage); + + const activityPage = new ActivityPage(otherUserPage); + await activityPage.visit(); + await otherUserPage.waitForTimeout(3000); + await expect(otherUserPage.getByRole('Button', { name: 'Create' }).first()).toHaveCount(0); + }); + + test('[16] - Inny użytkonik [Reader] nie może tworzyć uczestników', async ({ otherUserPage }) => { + await selectDataset(otherUserPage); + + const measurePage = new MeasurePage(otherUserPage); + await measurePage.visit(); + await otherUserPage.waitForTimeout(3000); + await expect(otherUserPage.getByRole('Button', { name: 'Create' }).first()).toHaveCount(0); + }); + + test('[17] - Inny użytkonik [Reader] nie może odwiedzić ustawień', async ({ otherUserPage }) => { + await selectDataset(otherUserPage); + + const settingsPage = new SettingsPage(otherUserPage); + await settingsPage.visit(); + await expect(otherUserPage).toHaveURL(/.*\/access-denied/); + }); + + test('[18] - Użytkownik dodaje uprawnienia dostępu do edycji', async ({ userPage }) => { + await selectDataset(userPage); + await new SettingsPage(userPage).visit(); + const accessPermissionsTab = new AccessPermissionsTab(userPage); + await accessPermissionsTab.visit(); + await accessPermissionsTab.addPermission(usernameOther, 'Editor'); + }); + + test('[19] - Inny użytkonik [Editor] może tworzyć eksperyment', async ({ otherUserPage }) => { + await selectDataset(otherUserPage); + + const experimentPage = new ExperimentPage(otherUserPage); + await experimentPage.visit(); + await expect(otherUserPage.getByRole('Button', { name: 'Create' }).first()).toHaveCount(0); + }); + + test('[20] - Inny użytkonik [Editor] może edytować składowe eksperymentu', async ({ otherUserPage }) => { + + await selectDataset(otherUserPage); + + await (new ExperimentListPage(otherUserPage)).useExperimentByName(newExperiment.name); + + const participantsTab = new ParticipantsTab(otherUserPage); + await participantsTab.visit(); + await expect(otherUserPage.getByRole('Button', { name: 'Add' }).first()).toHaveCount(1); + + const scenariosTab = new ScenariosTab(otherUserPage); + await scenariosTab.visit(); + await expect(otherUserPage.getByRole('Button', { name: 'Create' }).first()).toHaveCount(1); + + const scenariosExecutionTab = new ScenariosExecutionsTab(otherUserPage); + await scenariosExecutionTab.visit(); + await expect(otherUserPage.getByRole('Button', { name: 'Create' }).first()).toHaveCount(1); + + const recordingsTab = new RecordingsTab(otherUserPage); + await recordingsTab.visit(); + await expect(otherUserPage.getByRole('Button', { name: 'Create' }).first()).toHaveCount(1); + }); + + test('[21] - Inny użytkonik [Editor] może tworzyć aktywności', async ({ otherUserPage }) => { + await selectDataset(otherUserPage); + + const activityPage = new ActivityPage(otherUserPage); + await activityPage.visit(); + await otherUserPage.waitForTimeout(3000); + await expect(otherUserPage.getByRole('Button', { name: 'Create' }).first()).toHaveCount(1); + }); + + test('[22] - Inny użytkonik [Editor] może tworzyć uczestników', async ({ otherUserPage }) => { + await selectDataset(otherUserPage); + + const measurePage = new MeasurePage(otherUserPage); + await measurePage.visit(); + await otherUserPage.waitForTimeout(3000); + await expect(otherUserPage.getByRole('Button', { name: 'Create' }).first()).toHaveCount(1); + }); + + test('[23] - Inny użytkonik [Editor] widzi ustawień', async ({ userPage }) => { + await selectDataset(userPage); + await expect(userPage.getByRole('link', { name: 'Settings' })).toHaveCount(1); + }); + }); async function selectDataset(page: Page) { diff --git a/src/router/index.js b/src/router/index.js index 91c100d..b22b730 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -11,6 +11,7 @@ import datasetRoutes from '@/router/datasetRoutes'; import ClassesDescriptions from '@/const/ClassesDescriptions'; import AuthService from '@/services/AuthService'; import store from '@/store/index'; +import AccessRoles from '@/const/AccessRoles'; Vue.use(VueRouter); @@ -56,6 +57,7 @@ const routes = [ name: 'settings', component: () => import('@/views/settings/SettingsView.vue'), meta: { + canEnterRoles: [AccessRoles.EDITOR, AccessRoles.OWNER], icon: 'mdi-cog', order: 20, name: 'Settings', diff --git a/src/store/index.js b/src/store/index.js index ca058e1..43be18d 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -33,7 +33,7 @@ const store = new Vuex.Store({ getters: { getUser: state => state.user, getDataset: state => state.dataset, - getPermission: state => state.permissions.filter(permission => permission.datasetId == state.dataset.id)[0], + getPermission: state => state.permissions.filter(permission => permission.datasetId === state.dataset.id)[0], }, plugins: [createPersistedState()], }); diff --git a/src/views/datasets/DatasetDetailedView.vue b/src/views/datasets/DatasetDetailedView.vue index 36355d5..6757866 100644 --- a/src/views/datasets/DatasetDetailedView.vue +++ b/src/views/datasets/DatasetDetailedView.vue @@ -98,11 +98,11 @@ import DatasetAPI from '@/api/DatasetAPI'; import AppBreadcrumbs from '@/components/AppBreadcrumbs.vue'; import InfoToolTipComponent from '@/components/InfoToolTipComponent.vue'; -import config from '../../../config.js'; import { mapState } from 'vuex'; import PermissionsService from '@/services/PermissionsService'; import Roles from '@/const/AccessRoles'; +import router from '@/router'; export default { name: 'DatasetDetailedView', @@ -131,9 +131,6 @@ export default { buttonText() { return this.editMode ? 'update' : 'create'; }, - tokenExpiration() { - return new Date().getTime() + config.sessionDurationMinutes * 60000; - }, }, watch: { '$route.params.id': { @@ -160,13 +157,14 @@ export default { } else { DatasetAPI.store(this.dataset) .then(({ data }) => { - PermissionsService.add({ + return PermissionsService.add({ userId: this.user.sub, datasetId: data.id, role: Roles.OWNER, - }).then(({ data }) => { - localStorage.setItem('token', data.token); - localStorage.setItem('tokenExpiration', this.tokenExpiration); + }).then(_ => { + PermissionsService.getUserPermissions(this.user.sub).then(data => + router.app.$store.commit('setPermissions', data.data)); + }).then(_ => { this.$router.push('/datasets'); }); }); diff --git a/src/views/datasets/DatasetsView.vue b/src/views/datasets/DatasetsView.vue index fba4567..1f66a48 100644 --- a/src/views/datasets/DatasetsView.vue +++ b/src/views/datasets/DatasetsView.vue @@ -76,6 +76,7 @@ {{ taba.name }} @@ -43,6 +44,8 @@ import LocalStorageService from '@/storage/LocalStorageService'; import ParametersTab from '@/views/settings/tabs/ParametersTab'; import AccessPermissionsTab from '@/views/settings/tabs/AccessPermissionsTab.vue'; import AppBreadcrumbs from '@/components/AppBreadcrumbs.vue'; +import AccessRoles from '@/const/AccessRoles'; +import { mapGetters } from 'vuex'; export default { name: 'SettingsView', @@ -54,12 +57,22 @@ export default { data() { return { tab: 0, - tabs: [ - { id: 1, name: 'Parameters' }, - { id: 2, name: 'Access permissions' }, - ], }; }, + computed: { + ...mapGetters({ + getPermission: 'getPermission', + }), + isOwner() { + return this.getPermission.role === AccessRoles.OWNER; + }, + tabs() { + return [ + { id: 1, name: 'Parameters', disabled: false }, + { id: 2, name: 'Access permissions', disabled: !this.isOwner }, + ]; + }, + }, methods: { resetStorage() { LocalStorageService.clear();