diff --git a/frontend/app/abilities/report.js b/frontend/app/abilities/report.js index d883e2972..e1d6b8856 100644 --- a/frontend/app/abilities/report.js +++ b/frontend/app/abilities/report.js @@ -9,24 +9,54 @@ export default class ReportAbility extends Ability { } get canEdit() { - const isEditable = - this.user?.isSuperuser || - (!this.model?.verifiedBy?.get("id") && - // eslint-disable-next-line ember/no-get - (this.model?.user?.get("id") === this.user?.get("id") || - // eslint-disable-next-line ember/no-get - (this.model?.user?.get("supervisors") ?? []) - .map((s) => s.id) - .includes(this.user?.get("id")))); - const isReviewer = - (this.model?.taskAssignees ?? []) - .concat( - this.model?.projectAssignees ?? [], - this.model?.customerAssignees ?? [] - ) - .filter((a) => a?.user) - .map((a) => a.user.get("id")) - .includes(this.user?.get("id")) && !this.model?.verifiedBy?.get("id"); - return isEditable || isReviewer; + if (this.user?.isSuperuser) { + return true; + } + + if (this.model?.verifiedBy?.get("id")) { + return false; + } + + if (this.model?.user?.get("id") === this.user?.get("id")) { + return true; + } + + return false; + } + + async isReviewer() { + return ((await this.model?.taskAssignees) ?? []) + .concat( + (await this.model?.projectAssignees) ?? [], + (await this.model?.customerAssignees) ?? [] + ) + .filter((a) => a?.user) + .map((a) => a.user.get("id")) + .includes(this.user?.get("id")); + } + + async isSupervisee() { + return ((await this.model?.user?.get("supervisors")) ?? []) + .map((s) => s.id) + .includes(this.user?.get("id")); + } + + async canAedit() { + if (this.model?.verifiedBy?.get("id")) { + return false; + } + + const isSupervisee = await this.isSupervisee(); + if (isSupervisee) { + return true; + } + + const isReviewer = await this.isReviewer(); + + if (isReviewer) { + return true; + } + + return false; } } diff --git a/frontend/app/analysis/index/controller.js b/frontend/app/analysis/index/controller.js index d7ba300a3..309c0bb75 100644 --- a/frontend/app/analysis/index/controller.js +++ b/frontend/app/analysis/index/controller.js @@ -56,7 +56,7 @@ export default class AnalysisController extends QPController { @service store; @service router; @service notify; - @service can; + @service abilities; @tracked _scrollOffset = 0; @tracked _shouldLoadMore = false; @@ -363,17 +363,24 @@ export default class AnalysisController extends QPController { } @action - selectRow(report) { - if (this.can.can("edit report", report) || this.canBill) { - const selected = this.selectedReportIds; - - if (selected.includes(report.id)) { - this.selectedReportIds = A([ - ...selected.filter((id) => id !== report.id), - ]); - } else { - this.selectedReportIds = A([...selected, report.id]); - } + async selectRow(report, editable) { + if (!editable) { + return; + } + + const selected = this.selectedReportIds; + + if (selected.includes(report.id)) { + this.selectedReportIds = A([ + ...selected.filter((id) => id !== report.id), + ]); + } else { + this.selectedReportIds = A([...selected, report.id]); } } + + @action + async canEdit(syncEdit, report) { + return syncEdit ? true : await this.abilities.can("aedit report", report); + } } diff --git a/frontend/app/analysis/index/template.hbs b/frontend/app/analysis/index/template.hbs index fd9f46cd6..4974bda04 100644 --- a/frontend/app/analysis/index/template.hbs +++ b/frontend/app/analysis/index/template.hbs @@ -357,6 +357,9 @@ {{#each reports as |report|}} + {{#let (or this.canBill (can 'edit report' report)) as |syncEditable|}} + {{#let (this.canEdit syncEditable report) as |promise|}} + {{! template-lint-disable}} {{report.user.username}} {{moment-format report.date "DD.MM.YYYY"}} @@ -399,6 +402,9 @@ @highlight={{true}} /> + + {{/let}} + {{/let}} {{/each}} {{#if this._canLoadMore}} - -
{{t.customer}}
-
{{t.project}}
-
{{t.task}}
-
- -
- - - {{#if cs.task.project.customerVisible}} - - {{/if}} -
-
- -
-
- {{#if cs.task.project.remainingEffortTracking}} - +
+ - - - - - - {{/if}} -
+
{{t.customer}}
+
{{t.project}}
+
{{t.task}}
+ -
- - - - + + + {{#if cs.task.project.customerVisible}} + + {{/if}} +
+
+ - - - - - - - - -
-
- {{#if this.editable}} - - - {{/if}} -
- -{{/let}} + +
+ {{#if cs.task.project.remainingEffortTracking}} + + + + + + + {{/if}} +
+ +
+ + + + + + + + + + + + +
+
+ {{#if t.value}} + + + {{/if}} +
+ + + {{/let}} + {{/let}} + {{/let}} diff --git a/frontend/app/users/edit/credits/index/controller.js b/frontend/app/users/edit/credits/index/controller.js index b8a23c5b3..6518df7c2 100644 --- a/frontend/app/users/edit/credits/index/controller.js +++ b/frontend/app/users/edit/credits/index/controller.js @@ -1,6 +1,6 @@ import Controller, { inject as controller } from "@ember/controller"; import { action } from "@ember/object"; -import { inject as service } from "@ember/service"; +import { service } from "@ember/service"; import { tracked } from "@glimmer/tracking"; import { dropTask, restartableTask } from "ember-concurrency"; import moment from "moment"; @@ -12,7 +12,7 @@ export default class UsersEditCredits extends Controller { @service notify; @service fetch; - @service can; + @service abilities; @service router; @service store; @@ -42,8 +42,8 @@ export default class UsersEditCredits extends Controller { get allowTransfer() { return ( parseInt(this.year) === moment().year() - 1 && - this.can.can("create overtime-credit") && - this.can.can("create absence-credit") + this.abilities.can("create overtime-credit") && + this.abilities.can("create absence-credit") ); } @@ -95,7 +95,7 @@ export default class UsersEditCredits extends Controller { @dropTask *editAbsenceCredit(id) { - if (this.can.can("edit absence-credit")) { + if (this.abilities.can("edit absence-credit")) { yield this.router.transitionTo( "users.edit.credits.absence-credits.edit", id @@ -105,7 +105,7 @@ export default class UsersEditCredits extends Controller { @dropTask *editOvertimeCredit(id) { - if (this.can.can("edit overtime-credit")) { + if (this.abilities.can("edit overtime-credit")) { yield this.router.transitionTo( "users.edit.credits.overtime-credits.edit", id diff --git a/frontend/package.json b/frontend/package.json index f7b6ae3ac..90bbca704 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -50,7 +50,7 @@ "downloadjs": "1.4.7", "ember-auto-import": "~2.7.4", "ember-basic-dropdown": "^8.2.0", - "ember-can": "4.2.0", + "ember-can": "anehx/ember-can#1755f0fb2c1026b57f2984d065f1c8f10835e935&path:/ember-can", "ember-changeset": "4.1.2", "ember-changeset-validations": "4.1.1", "ember-cli": "~5.4.0", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 00e9f5537..808a0080a 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -87,8 +87,8 @@ importers: specifier: ^8.2.0 version: 8.2.0(@ember/string@3.1.1)(@ember/test-helpers@2.9.3(@babel/core@7.22.9)(@glint/template@1.4.0)(ember-source@5.4.1(@babel/core@7.22.9)(@glimmer/component@1.1.2(@babel/core@7.22.9))(@glint/template@1.4.0)(rsvp@4.8.5)(webpack@5.92.1)))(@glimmer/component@1.1.2(@babel/core@7.22.9))(@glimmer/tracking@1.1.2)(@glint/template@1.4.0)(ember-source@5.4.1(@babel/core@7.22.9)(@glimmer/component@1.1.2(@babel/core@7.22.9))(@glint/template@1.4.0)(rsvp@4.8.5)(webpack@5.92.1)) ember-can: - specifier: 4.2.0 - version: 4.2.0 + specifier: anehx/ember-can#1755f0fb2c1026b57f2984d065f1c8f10835e935&path:/ember-can + version: https://codeload.github.com/anehx/ember-can/tar.gz/1755f0fb2c1026b57f2984d065f1c8f10835e935#path:/ember-can(@babel/core@7.22.9)(@ember/string@3.1.1)(ember-resolver@10.0.0(@ember/string@3.1.1)(ember-source@5.4.1(@babel/core@7.22.9)(@glimmer/component@1.1.2(@babel/core@7.22.9))(@glint/template@1.4.0)(rsvp@4.8.5)(webpack@5.92.1)))(ember-source@5.4.1(@babel/core@7.22.9)(@glimmer/component@1.1.2(@babel/core@7.22.9))(@glint/template@1.4.0)(rsvp@4.8.5)(webpack@5.92.1)) ember-changeset: specifier: 4.1.2 version: 4.1.2(@glint/template@1.4.0)(ember-data@4.12.8(@babel/core@7.22.9)(@ember/string@3.1.1)(@glimmer/tracking@1.1.2)(@glint/template@1.4.0)(ember-source@5.4.1(@babel/core@7.22.9)(@glimmer/component@1.1.2(@babel/core@7.22.9))(@glint/template@1.4.0)(rsvp@4.8.5)(webpack@5.92.1))(webpack@5.92.1))(webpack@5.92.1) @@ -3348,9 +3348,13 @@ packages: peerDependencies: ember-source: ^3.13.0 || ^4.0.0 || >= 5.0.0 - ember-can@4.2.0: - resolution: {integrity: sha512-hiaWZspmI4zWeWmmFWgyw1+yEStSo6edGRHHUXCUPR+vBoqlT/hEfmndlfDGso2GFP8IV59DORMVY0KReMcO+w==} - engines: {node: 12.* || 14.* || >= 16} + ember-can@https://codeload.github.com/anehx/ember-can/tar.gz/1755f0fb2c1026b57f2984d065f1c8f10835e935#path:/ember-can: + resolution: {path: /ember-can, tarball: https://codeload.github.com/anehx/ember-can/tar.gz/1755f0fb2c1026b57f2984d065f1c8f10835e935} + version: 5.0.4 + peerDependencies: + '@ember/string': ^3.1.1 + ember-resolver: '>= 8.0.0' + ember-source: ^3.28.0 || ^4.0.0 || >=5.0.0 ember-changeset-validations@4.1.1: resolution: {integrity: sha512-lRT+LOwY+kTMRC/op85L6+FFHDuOkoQvqgexexTiLFECiTNw4vQbOrcAqhfe6n/QJBr5uypZ+bg4W1Ng34dkMg==} @@ -12561,12 +12565,16 @@ snapshots: - '@glint/template' - supports-color - ember-can@4.2.0: + ember-can@https://codeload.github.com/anehx/ember-can/tar.gz/1755f0fb2c1026b57f2984d065f1c8f10835e935#path:/ember-can(@babel/core@7.22.9)(@ember/string@3.1.1)(ember-resolver@10.0.0(@ember/string@3.1.1)(ember-source@5.4.1(@babel/core@7.22.9)(@glimmer/component@1.1.2(@babel/core@7.22.9))(@glint/template@1.4.0)(rsvp@4.8.5)(webpack@5.92.1)))(ember-source@5.4.1(@babel/core@7.22.9)(@glimmer/component@1.1.2(@babel/core@7.22.9))(@glint/template@1.4.0)(rsvp@4.8.5)(webpack@5.92.1)): dependencies: - ember-cli-babel: 7.26.11 - ember-cli-htmlbars: 6.3.0 + '@ember/string': 3.1.1 + '@embroider/addon-shim': 1.8.9 + decorator-transforms: 2.0.0(@babel/core@7.22.9) ember-inflector: 4.0.2 + ember-resolver: 10.0.0(@ember/string@3.1.1)(ember-source@5.4.1(@babel/core@7.22.9)(@glimmer/component@1.1.2(@babel/core@7.22.9))(@glint/template@1.4.0)(rsvp@4.8.5)(webpack@5.92.1)) + ember-source: 5.4.1(@babel/core@7.22.9)(@glimmer/component@1.1.2(@babel/core@7.22.9))(@glint/template@1.4.0)(rsvp@4.8.5)(webpack@5.92.1) transitivePeerDependencies: + - '@babel/core' - supports-color ember-changeset-validations@4.1.1(@glint/template@1.4.0)(webpack@5.92.1): diff --git a/frontend/tests/unit/abilities/report-test.js b/frontend/tests/unit/abilities/report-test.js index 5ebbd9c91..f81fa9108 100644 --- a/frontend/tests/unit/abilities/report-test.js +++ b/frontend/tests/unit/abilities/report-test.js @@ -7,33 +7,36 @@ module("Unit | Ability | report", function (hooks) { setupTest(hooks); setupCurrentUser(hooks); - test("can edit when user is superuser", function (assert) { + test("can edit when user is superuser", async function (assert) { const ability = this.owner.lookup("ability:report"); const currentUser = this.owner.lookup("service:currentUser"); currentUser.user = EmberObject.create({ isSuperuser: true }); assert.true(ability.canEdit); + assert.false(await ability.canAedit()); }); - test("can edit when user is superuser and report is verified", function (assert) { + test("can edit when user is superuser and report is verified", async function (assert) { const ability = this.owner.lookup("ability:report"); const currentUser = this.owner.lookup("service:currentUser"); currentUser.user = EmberObject.create({ isSuperuser: true }); ability.set("model", { verifiedBy: EmberObject.create({ id: 1 }) }); assert.true(ability.canEdit); + assert.false(await ability.canAedit()); }); - test("can edit when user owns report", function (assert) { + test("can edit when user owns report", async function (assert) { const ability = this.owner.lookup("ability:report"); const currentUser = this.owner.lookup("service:currentUser"); currentUser.user = EmberObject.create({ id: 1 }); ability.set("model", { user: EmberObject.create({ id: 1 }) }); assert.true(ability.canEdit); + assert.false(await ability.canAedit()); }); - test("can edit when user is supervisor of owner", function (assert) { + test("can edit when user is supervisor of owner", async function (assert) { const ability = this.owner.lookup("ability:report"); const currentUser = this.owner.lookup("service:currentUser"); currentUser.user = EmberObject.create({ id: 1 }); @@ -41,10 +44,11 @@ module("Unit | Ability | report", function (hooks) { user: EmberObject.create({ supervisors: [{ id: 1 }] }), }); - assert.true(ability.canEdit); + assert.false(ability.canEdit); + assert.true(await ability.canAedit()); }); - test("can edit when user reviewer of project", function (assert) { + test("can edit when user reviewer of project", async function (assert) { const ability = this.owner.lookup("ability:report"); const user = EmberObject.create({ id: 1 }); const projectAssignee = [{ user }]; @@ -57,10 +61,26 @@ module("Unit | Ability | report", function (hooks) { }) ); - assert.true(ability.canEdit); + assert.false(ability.canEdit); + assert.true(await ability.canAedit()); + }); + + test("can not edit when verified", async function (assert) { + const ability = this.owner.lookup("ability:report"); + const currentUser = this.owner.lookup("service:currentUser"); + currentUser.user = EmberObject.create({ id: 1, isSuperuser: false }); + ability.set("model", { + user: EmberObject.create({ id: 2, supervisors: [{ id: 2 }] }), + task: { project: { reviewers: [{ id: 2 }] } }, + projectAssignees: [{ id: 2 }], + verifiedBy: EmberObject.create({ id: 2 }), + }); + + assert.false(ability.canEdit); + assert.false(await ability.canAedit()); }); - test("can not edit when not allowed", function (assert) { + test("can not edit when not allowed", async function (assert) { const ability = this.owner.lookup("ability:report"); const currentUser = this.owner.lookup("service:currentUser"); currentUser.user = EmberObject.create({ id: 1, isSuperuser: false }); @@ -71,9 +91,10 @@ module("Unit | Ability | report", function (hooks) { }); assert.false(ability.canEdit); + assert.false(await ability.canAedit()); }); - test("can not edit when report is verified and billed", function (assert) { + test("can not edit when report is verified and billed", async function (assert) { const ability = this.owner.lookup("ability:report"); const currentUser = this.owner.lookup("service:currentUser"); currentUser.user = EmberObject.create({ id: 1, isSuperuser: false }); @@ -85,5 +106,6 @@ module("Unit | Ability | report", function (hooks) { }); assert.false(ability.canEdit); + assert.false(await ability.canAedit()); }); });