Skip to content

Commit

Permalink
api: Send correct notifications after assigining workflow item
Browse files Browse the repository at this point in the history
* The recipient for notifications after assigning workflowitems is now
the new assignee of the workflowitem as it should be
* Added unit test to test this behaviour
* Fixed typos in other unit tests and added one test case each
  • Loading branch information
mathiashoeld committed May 20, 2019
1 parent 833fc25 commit 9974e35
Show file tree
Hide file tree
Showing 8 changed files with 605 additions and 63 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Navigation on notifications page now works as expected [#272](https://github.com/openkfw/TruBudget/pull/272)
- The link to the project/subproject is now active when the user has permissions to see it [#284](https://github.com/openkfw/TruBudget/pull/284)
- The link to the project/subproject in fly-in notifications correctly redirects the user [#284](https://github.com/openkfw/TruBudget/pull/284)
- When a workflow item is assigned, the new assignee gets notified [#272](https://github.com/openkfw/TruBudget/pull/272)

<!-- ### Security -->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,31 @@ describe("Delete project projected budget: permissions", () => {
});

it("The root user doesn't need permission to delete a projected budget", async () => {
const result = await deleteProjectedBudget(ctx, root, projectId, "Othertestcorp", "EUR", {
...baseRepository,
getProject: async () => ({
...baseProject,
permissions: {},
projectedBudgets: [
{
organization: "Testcorp",
value: "10000",
currencyCode: "EUR",
},
],
}),
});
const projectedBudget = {
organization: "Testcorp",
currencyCode: "EUR",
};
const result = await deleteProjectedBudget(
ctx,
root,
projectId,
projectedBudget.organization,
projectedBudget.currencyCode,
{
...baseRepository,
getProject: async () => ({
...baseProject,
permissions: {},
projectedBudgets: [
{
organization: projectedBudget.organization,
currencyCode: projectedBudget.currencyCode,
value: "10000",
},
],
}),
},
);

// No errors, despite the missing permissions:
assert.isTrue(Result.isOk(result), (result as Error).message);
Expand All @@ -85,17 +96,69 @@ describe("Delete project projected budget: permissions", () => {
assert.instanceOf(result, NotFound);
});

// Test can be activated if #290 is fixed or deleted otherwise
// it("Deleting a projected budget fails if the projected budget cannot be found.", async () => {
// const result = await deleteProjectedBudget(ctx, alice, projectId, "Somecorp", "EUR", {
// ...baseRepository,
// getProject: async () => ({ ...baseProject }),
// });

// // NotFound error as the project cannot be fetched:
// assert.isTrue(Result.isErr(result));
// // assert.instanceOf(result, NotFound);
// });
it("Deleting a projected budget does nothing if the projected budget cannot be found.", async () => {
const result = await deleteProjectedBudget(ctx, alice, projectId, "Somecorp", "EUR", {
...baseRepository,
getProject: async () => ({
...baseProject,
projectedBudgets: [
{
organization: "Testcorp",
currencyCode: "USD",
value: "10000",
},
],
}),
});

// NotFound error as the project cannot be fetched:
assert.isTrue(Result.isOk(result));
});
});

describe("Delete project projected budget: deletion", () => {
it("The projected budget is not available after deletion", async () => {
const projectedBudget = {
organization: "Testcorp",
currencyCode: "EUR",
};
const projectedBudgetToDelete = {
organization: "Otherestcorp",
currencyCode: "EUR",
};
const result = await deleteProjectedBudget(
ctx,
alice,
projectId,
projectedBudgetToDelete.organization,
projectedBudgetToDelete.currencyCode,
{
...baseRepository,
getProject: async () => ({
...baseProject,
projectedBudgets: [
{
organization: projectedBudget.organization,
value: "10000",
currencyCode: projectedBudget.currencyCode,
},
{
organization: projectedBudgetToDelete.organization,
value: "10000",
currencyCode: projectedBudgetToDelete.currencyCode,
},
],
}),
},
);

assert.isTrue(Result.isOk(result));
if (Result.isErr(result)) {
throw result;
}
const { projectedBudgets } = result;
assert.isTrue(projectedBudgets.length === 1);
});
});

describe("Deleting Projected Budgets: notifications", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { NotFound } from "../errors/not_found";
import { ServiceUser } from "../organization/service_user";
import { Project } from "./project";
import { updateProjectedBudget } from "./project_projected_budget_update";
import { Subproject } from "./subproject";

const ctx: Ctx = { requestId: "", source: "test" };
const root: ServiceUser = { id: "root", groups: [] };
Expand Down Expand Up @@ -102,6 +101,45 @@ describe("Update project projected budget: permissions", () => {
});
});

describe("Update project projected budget: updating", () => {
it("The projected budget is updated", async () => {
const projectedBudgetToUpdate = {
organization: "Otherestcorp",
value: "10000",
currencyCode: "EUR",
};
const updatedValue = "9999";
const result = await updateProjectedBudget(
ctx,
alice,
projectId,
projectedBudgetToUpdate.organization,
updatedValue,
projectedBudgetToUpdate.currencyCode,
{
...baseRepository,
getProject: async () => ({
...baseProject,
projectedBudgets: [
{
organization: projectedBudgetToUpdate.organization,
value: projectedBudgetToUpdate.value,
currencyCode: projectedBudgetToUpdate.currencyCode,
},
],
}),
},
);

assert.isTrue(Result.isOk(result));
if (Result.isErr(result)) {
throw result;
}
const { projectedBudgets } = result;
assert.equal(projectedBudgets[0].value, updatedValue);
});
});

describe("Update Projected Budgets: notifications", () => {
it("When a user updates a projected budget, a notification is issued to the assignee.", async () => {
const result = await updateProjectedBudget(ctx, alice, projectId, "Testcorp", "9999", "EUR", {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,33 +42,37 @@ const baseRepository = {
},
};

describe("Update subproject projected budget: permissions", () => {
it("Without the subproject.budget.updateProjected permission, a user cannot update a projected budget.", async () => {
const result = await deleteProjectedBudget(
ctx,
alice,
projectId,
subprojectId,
"Othertestcorp",
"EUR",
{
...baseRepository,
getSubproject: async () => ({ ...baseSubproject, permissions: {} }),
},
);
describe("Delete subproject projected budget: permissions", () => {
it(
"Without the subproject.budget.deleteProjected permission," +
" a user cannot delete a projected budget.",
async () => {
const result = await deleteProjectedBudget(
ctx,
alice,
projectId,
subprojectId,
"Testcorp",
"EUR",
{
...baseRepository,
getSubproject: async () => ({ ...baseSubproject, permissions: {} }),
},
);

// NotAuthorized error due to the missing permissions:
assert.isTrue(Result.isErr(result));
assert.instanceOf(result, NotAuthorized);
});
// NotAuthorized error due to the missing permissions:
assert.isTrue(Result.isErr(result));
assert.instanceOf(result, NotAuthorized);
},
);

it("The root user doesn't need permission to update a projected budget", async () => {
it("The root user doesn't need permission to delete a projected budget", async () => {
const result = await deleteProjectedBudget(
ctx,
root,
projectId,
subprojectId,
"Othertestcorp",
"Testcorp",
"EUR",
{
...baseRepository,
Expand All @@ -90,13 +94,13 @@ describe("Update subproject projected budget: permissions", () => {
assert.isTrue(Result.isOk(result), (result as Error).message);
});

it("Updating a projected budget fails if the subproject cannot be found.", async () => {
it("Deleting a projected budget fails if the subproject cannot be found.", async () => {
const result = await deleteProjectedBudget(
ctx,
alice,
projectId,
subprojectId,
"Othercorp",
"Testcorp",
"EUR",
{
...baseRepository,
Expand All @@ -110,8 +114,54 @@ describe("Update subproject projected budget: permissions", () => {
});
});

describe("Update Projected Budgets: notifications", () => {
it("When a user updates a projected budget, a notification is issued to the assignee.", async () => {
describe("Delete subproject projected budget: deletion", () => {
it("The projected budget is not available after deletion", async () => {
const projectedBudget = {
organization: "Testcorp",
currencyCode: "EUR",
};
const projectedBudgetToDelete = {
organization: "Otherestcorp",
currencyCode: "EUR",
};
const result = await deleteProjectedBudget(
ctx,
alice,
projectId,
subprojectId,
projectedBudgetToDelete.organization,
projectedBudgetToDelete.currencyCode,
{
...baseRepository,
getSubproject: async () => ({
...baseSubproject,
projectedBudgets: [
{
organization: projectedBudget.organization,
value: "10000",
currencyCode: projectedBudget.currencyCode,
},
{
organization: projectedBudgetToDelete.organization,
value: "10000",
currencyCode: projectedBudgetToDelete.currencyCode,
},
],
}),
},
);

assert.isTrue(Result.isOk(result));
if (Result.isErr(result)) {
throw result;
}
const { projectedBudgets } = result;
assert.isTrue(projectedBudgets.length === 1);
});
});

describe("Delete Projected Budgets: notifications", () => {
it("When a user deletes a projected budget, a notification is issued to the assignee.", async () => {
const result = await deleteProjectedBudget(
ctx,
alice,
Expand Down Expand Up @@ -149,14 +199,18 @@ describe("Update Projected Budgets: notifications", () => {
);
});

it("If there is no assignee when updating a projected budget, no notifications are issued.", async () => {
it("If there is no assignee when deleting a projected budget, no notifications are issued.", async () => {
const projectedBudget = {
organization: "Testcorp",
currencyCode: "EUR",
};
const result = await deleteProjectedBudget(
ctx,
alice,
projectId,
subprojectId,
"Testcorp",
"EUR",
projectedBudget.organization,
projectedBudget.currencyCode,
{
...baseRepository,
getSubproject: async () => ({
Expand All @@ -165,8 +219,8 @@ describe("Update Projected Budgets: notifications", () => {
assignee: undefined,
projectedBudgets: [
{
organization: "Testcorp",
value: "10000",
organization: projectedBudget.organization,
value: projectedBudget.currencyCode,
currencyCode: "EUR",
},
],
Expand All @@ -186,7 +240,7 @@ describe("Update Projected Budgets: notifications", () => {
});

it(
"If the user that updates a projected budget is assigned " +
"If the user that deletes a projected budget is assigned " +
"to the subproject herself,no notifications are issued.",
async () => {
const result = await deleteProjectedBudget(
Expand Down Expand Up @@ -226,7 +280,7 @@ describe("Update Projected Budgets: notifications", () => {
);

it(
"If a subproject is assigned to a group when updating a projected budget, " +
"If a subproject is assigned to a group when deleting a projected budget, " +
"each member, except for the user that updates it, receives a notificaton.",
async () => {
const group = "alice_and_bob_and_charlie";
Expand Down
Loading

0 comments on commit 9974e35

Please sign in to comment.