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());
});
});