Skip to content

Commit

Permalink
Merge pull request #212 from d-velop/develop
Browse files Browse the repository at this point in the history
Add TaskApp Functionality
  • Loading branch information
LenKlose authored Sep 18, 2024
2 parents 119e1f7 + 38ceca5 commit cb187a8
Show file tree
Hide file tree
Showing 6 changed files with 630 additions and 2 deletions.
4 changes: 3 additions & 1 deletion packages/task/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@ export { CreateTaskParams, createTask } from "./tasks/create-task/create-task";
export { CompleteTaskParams, completeTask } from "./tasks/complete-task/complete-task";
export { DeleteTaskParams, deleteTask } from "./tasks/delete-task/delete-task";
export { getTaskCount } from "./tasks/get-task-count/get-task-count";
export { UpdateTaskParams, updateTask } from "./tasks/update-task/update-task";
export { UpdateTaskParams, updateTask } from "./tasks/update-task/update-task";
export { GetTaskParams, getTask } from "./tasks/get-task/get-task";
export { SearchTasksParams, SearchTasksPage, searchTasks, buildRangeParameter } from "./tasks/search-tasks/search-tasks";
49 changes: 49 additions & 0 deletions packages/task/src/tasks/get-task/get-task.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {_getTaskDefaultTransformFunction, _getTaskFactory, GetTaskParams} from "./get-task";
import {DvelopContext} from "@dvelop-sdk/core";
import {HttpResponse} from "../../utils/http";

describe("getTaskFactory", () => {
let mockHttpRequestFunction = jest.fn();
let mockTransformFunction = jest.fn();

let params : GetTaskParams = {
taskId: "SomeTestId"
};
let context: DvelopContext = {
systemBaseUri: "someBaseUri"
};

beforeEach(() => {
jest.resetAllMocks();
});

it("should map params correctly", async () => {
const getTask = _getTaskFactory(mockHttpRequestFunction, mockTransformFunction);

await getTask(context, params);
expect(mockHttpRequestFunction).toHaveBeenCalledWith(context, {
method: "GET",
url: "/task/tasks/SomeTestId"
});
});

it("should transform response", async () => {
mockHttpRequestFunction.mockResolvedValue({ data: {
"id" : "SomeTestId",
"subject" : "My subject",
"assignees" : ["bob"],
"sender" : "alice",
"receiveDate" : "2024-07-28T12:12:12.000Z"
}} as unknown as HttpResponse);
const getTask = _getTaskFactory(mockHttpRequestFunction, _getTaskDefaultTransformFunction);

const task = await getTask(context, params);

expect(task.id).toBe("SomeTestId");
expect(task.subject).toBe("My subject");
expect(task.assignees).toEqual(["bob"]);
expect(task.sender).toBe("alice");
expect(task.receiveDate).toEqual(new Date("2024-07-28T12:12:12.000Z"));
});

});
156 changes: 156 additions & 0 deletions packages/task/src/tasks/get-task/get-task.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import { DvelopContext } from "@dvelop-sdk/core";
import { HttpConfig, HttpResponse, _defaultHttpRequestFunction } from "../../utils/http";

/**
* Parameters for the {@link getTask}-function.
* @category Task
*/
export interface GetTaskParams {
/** ID of the task */
taskId: string;
}

/**
* Response for the {@link getTask}-function.
* @category Task
*/
export interface Task {
/** Unique id of the task */
id: string;
/** The subject of the task */
subject: string;
/** The recipients of the task. You can specify individual users as well as groups using IDs of the Identityprovider-App */
assignees: string[];
/** Sender of the task */
sender: string;
/** The correlation key ensures that only one task is created for this unique key. If a task already exists with the passed key, a new task will not be created. */
correlationKey?: string;
/** A descriptive text of the task */
description?: string;
/** State of the task */
state: "OPEN" | "COMPLETED";
/** Priority between 0 (low) and 100 (high) */
priority?: number,
/** Receive date */
receiveDate: Date;
/** Reminder date. If you transfer a date without a timestamp, the reminder date is the transferred date at 00:00:00. */
reminderDate?: Date;
/** Due date of the task. If you transfer a date without a timestamp, the due date is the transferred date at 00:00:00. */
dueDate?: Date;
/**
* Specify how long the task details should be kept after completing the task. Valid values are between 0 and 365 days. After this time has passed, the task details will be deleted automatically.
* The information is specified as a time span in days according to ISO-8601, e.g. P30D for 30 days. Specify the time span P0D if the task details should be deleted immediately after the task is completed. If you make no specification, 30 days are automatically assumed.
*/
retentionTime?: string;
/** ID of the user that completed this task. Only present if completed */
completionUser?: string;
/** Time at which the task was completed. Only present if completed */
completionDate?: Date;
/** The context of a task */
context?: {
/** A technical identifier for the context */
key?: string;
/** Type of the context */
type?: string;
/** Display name of the context */
name?: string;
},

/** Metadata for the task. See [the documentation](https://developer.d-velop.de/documentation/taskapi/en#creating-a-task) for further information */
metadata?: {
/** A technical identifier for the metadata-field */
key: string;
/** Label of the metadata-field */
caption?: string;
/** Type of the metadata-field */
type: "String" | "Number" | "Money" | "Date";
/** Value of the metadata field. Currently, only one value is allowed per metadata-field. */
values?: string;
}[];
/** DmsObject that references the task. */
dmsReferences?: {
/** ID of the repository */
repoId: string;
/** ID of the DmsObject */
objectId: string;
}[];

/** Links to the task */
_links?: {
/** Link to this task. */
self: { href: string; };
/** This URI provides an editing dialog for the task. You can find further details in the section [Adding editing dialogs](https://developer.d-velop.de/documentation/taskapi/en#adding-editing-dialogs). */
form?: { href: string; };
/** This URI is displayed as an action in the user interface to display additional information for the user. */
attachment?: { href: string; };
}
}

/**
* Default transform-function provided to the {@link getTask}-function. See [Advanced Topics](https://github.com/d-velop/dvelop-sdk-node#advanced-topics) for more information.
* @internal
* @category Task
*/
export function _getTaskDefaultTransformFunction(response: HttpResponse, _: DvelopContext, __: GetTaskParams): Task {
let task : Task;
const responseTask = response.data;
task = {...responseTask};

if (responseTask.receiveDate) {
task.receiveDate = new Date(responseTask.receiveDate);
}
if (responseTask.reminderDate) {
task.reminderDate = new Date(responseTask.reminderDate);
}
if (responseTask.dueDate) {
task.dueDate = new Date(responseTask.dueDate);
}
if (responseTask.completionDate) {
task.completionDate = new Date(responseTask.completionDate);
}

return task;
}

/**
* Factory for the {@link getTask}-function. See [Advanced Topics](https://github.com/d-velop/dvelop-sdk-node#advanced-topics) for more information.
* @typeparam T Return type of the {@link getTask}-function. A corresponding transformFunction has to be supplied.
* @internal
* @category Task
*/
export function _getTaskFactory<T>(
httpRequestFunction: (context: DvelopContext, config: HttpConfig) => Promise<HttpResponse>,
transformFunction: (response: HttpResponse, context: DvelopContext, params: GetTaskParams) => T
): (context: DvelopContext, params: GetTaskParams) => Promise<T> {

return async (context: DvelopContext, params: GetTaskParams) => {
const response: HttpResponse = await httpRequestFunction(context, {
method: "GET",
url: `/task/tasks/${params.taskId}`
});

return transformFunction(response, context, params);
};
}

/**
* Get a task.
* @returns A task object
*
* ```typescript
* import { getTask } from "@dvelop-sdk/task";
*
* const task = await getTask({
* systemBaseUri: "https://umbrella-corp.d-velop.cloud",
* authSessionId: "dQw4w9WgXcQ"
* }, {
* id: "SomeTaskId"
* });
* ```
*
* @category Task
*/
/* istanbul ignore next */
export function getTask(context: DvelopContext, params: GetTaskParams): Promise<Task> {
return _getTaskFactory(_defaultHttpRequestFunction, _getTaskDefaultTransformFunction)(context, params);
}
155 changes: 155 additions & 0 deletions packages/task/src/tasks/search-tasks/search-tasks.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import {_searchTasksDefaultTransformFunctionFactory, _searchTasksFactory, buildRangeParameter, SearchTasksParams} from "./search-tasks";
import {DvelopContext} from "@dvelop-sdk/core";
import {HttpResponse} from "../../utils/http";

describe("build range parameters", () => {

it("should create a valid range string", () => {
const result = buildRangeParameter({
from: 10,
to: 20,
beginInclusive: true,
endInclusive: false
});

expect(result).toBe("[10..20)");
});

it("should use inclusive search as default", () => {
const result = buildRangeParameter({
from: 10,
to: 20
});

expect(result).toBe("[10..20]");
});

it("should throw when no values are present", () => {
expect(() => buildRangeParameter({})).toThrow();
});

it("should work with an open range", () => {
const result = buildRangeParameter({
to: 20
});

expect(result).toBe("[..20]");
});

it("should work with Date", () => {
const result = buildRangeParameter({
from: new Date("2024-01-01T00:00:00.000Z"),
to: new Date("2025-01-01T00:00:00.000Z")
});

expect(result).toBe("[2024-01-01T00:00:00.000Z..2025-01-01T00:00:00.000Z]");
});
});

describe("search tasks", () => {
let mockHttpRequestFunction = jest.fn();
let mockTransformFunction = jest.fn();

let context: DvelopContext = {
systemBaseUri: "someBaseUri"
};

beforeEach(() => {
jest.resetAllMocks();
});

it("should call the correct endpoint", async () => {
const searchTasks = _searchTasksFactory(mockHttpRequestFunction, mockTransformFunction);

let params : SearchTasksParams = {};

await searchTasks(context, params);

expect(mockHttpRequestFunction).toHaveBeenCalledWith(context, {
method: "POST",
url: "/task/api/tasks/search",
data: {}
});
});

it("should pass parameters", async () => {
const searchTasks = _searchTasksFactory(mockHttpRequestFunction, mockTransformFunction);

let params : SearchTasksParams = {
pageSize: 5,
orderBy: "subject",
orderDir: "DESC",
filter: {
subject: ["test"]
}
};

await searchTasks(context, params);

expect(mockHttpRequestFunction).toHaveBeenCalledWith(context, {
method: "POST",
url: "/task/api/tasks/search",
data: {
pageSize: 5,
orderBy: "subject",
orderDir: "DESC",
filter: {
subject: ["test"]
}
}
});
});

it ("should transform date values", async () => {
mockHttpRequestFunction.mockResolvedValue({ data: {
tasks: [{
id: "test1",
receiveDate: "2024-01-01T12:00:00.000Z",
dueDate: "2025-01-01T12:00:00.000Z",
reminderDate: "2026-01-01T12:00:00.000Z",
completionDate: "2027-01-01T12:00:00.000Z",
state: "COMPLETED"
}]
}} as unknown as HttpResponse);

const transformFunction = _searchTasksDefaultTransformFunctionFactory(mockHttpRequestFunction);
const searchTasks = _searchTasksFactory(mockHttpRequestFunction, transformFunction);

let page = await searchTasks(context, {});

expect(page.tasks[0].receiveDate).toStrictEqual(new Date("2024-01-01T12:00:00.000Z"));
expect(page.tasks[0].dueDate).toStrictEqual(new Date("2025-01-01T12:00:00.000Z"));
expect(page.tasks[0].reminderDate).toStrictEqual(new Date("2026-01-01T12:00:00.000Z"));
expect(page.tasks[0].completionDate).toStrictEqual(new Date("2027-01-01T12:00:00.000Z"));
});

it("should support paging", async () => {
mockHttpRequestFunction.mockResolvedValue({ data: {
tasks: [],
_links: {
next: {href: "/test/next"}
}
}} as unknown as HttpResponse);

const transformFunction = _searchTasksDefaultTransformFunctionFactory(mockHttpRequestFunction);
const searchTasks = _searchTasksFactory(mockHttpRequestFunction, transformFunction);

const params : SearchTasksParams = {
pageSize: 1
};
let searchTasksPage = await searchTasks(context, params);

await searchTasksPage.getNextPage();

expect(mockHttpRequestFunction).toHaveBeenCalledTimes(2);

expect(mockHttpRequestFunction).toHaveBeenCalledWith(context, {
method: "POST",
url: "/test/next",
data: {
pageSize: 1
}
});

});
});
Loading

0 comments on commit cb187a8

Please sign in to comment.