From 982b88eb1c2af9029cebe89a2e2debc0586849ad Mon Sep 17 00:00:00 2001 From: Roland Bernard <rolbernard@unibz.it> Date: Fri, 7 May 2021 23:51:12 +0200 Subject: [PATCH] Reduced code duplication --- client/src/adapters/project.ts | 138 ++++------------- client/src/adapters/task.ts | 131 +++++----------- client/src/adapters/team.ts | 266 +++++++-------------------------- client/src/adapters/user.ts | 88 +++-------- client/src/adapters/util.ts | 41 +++++ 5 files changed, 184 insertions(+), 480 deletions(-) create mode 100644 client/src/adapters/util.ts diff --git a/client/src/adapters/project.ts b/client/src/adapters/project.ts index a325024..38c62e5 100644 --- a/client/src/adapters/project.ts +++ b/client/src/adapters/project.ts @@ -1,7 +1,5 @@ -import { apiRoot } from 'config'; - -import { getAuthHeader } from './auth'; +import { executeApiGet, executeApiPost, executeApiPut } from './util'; import { Task } from './task'; import { User } from './user'; import { Work } from './work'; @@ -22,84 +20,38 @@ export interface AssignedUser extends User { export type ReducedProject = Exclude<Project, 'teams'>; -export async function getProjects(): Promise<ReducedProject[]> { - try { - const response = await fetch(`${apiRoot}/project/`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).projects.map((project: any) => ({ - ...project, - deadline: project.deadline ? new Date(project.deadline) : undefined, - })); - } else { - throw new Error("Failed to get projects"); - } - } catch (e) { - throw e; - } +export function getProjects(): Promise<ReducedProject[]> { + return executeApiGet(`project`, ({ projects }) => projects.map((project: any) => ({ + ...project, + deadline: project.deadline ? new Date(project.deadline) : undefined, + })), "Failed to get projects"); } -export async function getProject(uuid: string): Promise<Project> { - try { - const response = await fetch(`${apiRoot}/project/${uuid}`, { headers: getAuthHeader() }); - if (response.ok) { - const project = (await response.json()).project; - return { - ...project, - deadline: project.deadline ? new Date(project.deadline) : undefined, - } - } else { - throw new Error("Failed to get project"); - } - } catch (e) { - throw e; - } +export function getProject(uuid: string): Promise<Project> { + return executeApiGet(`project/${uuid}`, ({ project }) => ({ + ...project, + deadline: project.deadline ? new Date(project.deadline) : undefined, + }), "Failed to get project"); } -export async function getProjectTasks(uuid: string): Promise<Task[]> { - try { - const response = await fetch(`${apiRoot}/project/${uuid}/tasks`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).tasks.map((task: any) => ({ - ...task, - edited: new Date(task.edited), - created: new Date(task.created), - })); - } else { - throw new Error("Failed to get project tasks"); - } - } catch (e) { - throw e; - } +export function getProjectTasks(uuid: string): Promise<Task[]> { + return executeApiGet(`project/${uuid}/tasks`, ({ tasks }) => tasks.map((task: any) => ({ + ...task, + edited: new Date(task.edited), + created: new Date(task.created), + })), "Failed to get project tasks"); } -export async function getProjectAssignees(uuid: string): Promise<AssignedUser[]> { - try { - const response = await fetch(`${apiRoot}/project/${uuid}/assigned`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).assigned; - } else { - throw new Error("Failed to get project assignees"); - } - } catch (e) { - throw e; - } +export function getProjectAssignees(uuid: string): Promise<AssignedUser[]> { + return executeApiGet(`project/${uuid}/assigned`, ({ assigned }) => assigned, "Failed to get project assignees"); } -export async function getProjectWork(uuid: string): Promise<Work[]> { - try { - const response = await fetch(`${apiRoot}/project/${uuid}/work`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).work.map((work: any) => ({ - ...work, - started: new Date(work.started), - finished: work.finished ? new Date(work.finished) : undefined, - })); - } else { - throw new Error("Failed to get project work"); - } - } catch (e) { - throw e; - } +export function getProjectWork(uuid: string): Promise<Work[]> { + return executeApiGet(`project/${uuid}/work`, ({ work }) => work.map((work: any) => ({ + ...work, + started: new Date(work.started), + finished: work.finished ? new Date(work.finished) : undefined, + })), "Failed to get project work"); } interface NewTeamData { @@ -110,24 +62,8 @@ interface NewTeamData { deadline?: Date; } -export async function createProject(project: NewTeamData): Promise<string> { - try { - const response = await fetch(`${apiRoot}/project/`, { - method: 'POST', - headers: { - ...getAuthHeader(), - 'Content-Type': 'application/json', - }, - body: JSON.stringify(project), - }); - if (response.ok) { - return (await response.json()).id; - } else { - throw new Error("Failed to create project"); - } - } catch (e) { - throw e; - } +export function createProject(project: NewTeamData): Promise<string> { + return executeApiPost(`project`, project, ({ id }) => id, "Failed to create project"); } interface UpdateTeamData { @@ -140,24 +76,8 @@ interface UpdateTeamData { deadline?: string; } -export async function updateProject(uuid: string, project: UpdateTeamData) { - try { - const response = await fetch(`${apiRoot}/project/${uuid}`, { - method: 'PUT', - headers: { - ...getAuthHeader(), - 'Content-Type': 'application/json', - }, - body: JSON.stringify(project), - }); - if (response.ok) { - return (await response.json()).id; - } else { - throw new Error("Failed to update project"); - } - } catch (e) { - throw e; - } +export function updateProject(uuid: string, project: UpdateTeamData) { + return executeApiPut(`project/${uuid}`, project, () => {}, "Failed to update project"); } diff --git a/client/src/adapters/task.ts b/client/src/adapters/task.ts index 51c55d0..bbf0d34 100644 --- a/client/src/adapters/task.ts +++ b/client/src/adapters/task.ts @@ -1,7 +1,5 @@ -import { apiRoot } from 'config'; - -import { getAuthHeader } from './auth'; +import { executeApiGet } from './util'; import { Comment } from './comment'; import { Work } from './work'; @@ -31,106 +29,51 @@ export interface Task { edited: Date; } -export async function getTasks(): Promise<Task[]> { - try { - const response = await fetch(`${apiRoot}/task`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).tasks.map((task: any) => ({ - ...task, - edited: new Date(task.edited), - created: new Date(task.created), - })); - } else { - throw new Error("Failed to get tasks"); - } - } catch (e) { - throw e; - } +export function getTasks(): Promise<Task[]> { + return executeApiGet(`task`, ({ tasks }) => tasks.map((task: any) => ({ + ...task, + edited: new Date(task.edited), + created: new Date(task.created), + })), "Failed to get tasks"); } -export async function getTasksWithStatus(status: 'open' | 'closed' | 'suspended'): Promise<Task[]> { - try { - const response = await fetch(`${apiRoot}/task/${status}`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).tasks.map((task: any) => ({ - ...task, - edited: new Date(task.edited), - created: new Date(task.created), - })); - } else { - throw new Error("Failed to get tasks with status"); - } - } catch (e) { - throw e; - } +export function getTasksWithStatus(status: 'open' | 'closed' | 'suspended'): Promise<Task[]> { + return executeApiGet(`task/${status}`, ({ tasks }) => tasks.map((task: any) => ({ + ...task, + edited: new Date(task.edited), + created: new Date(task.created), + })), "Failed to get tasks with status"); } -export async function getPossibleTasks(): Promise<Task[]> { - try { - const response = await fetch(`${apiRoot}/task/possible`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).tasks.map((task: any) => ({ - ...task, - edited: new Date(task.edited), - created: new Date(task.created), - })); - } else { - throw new Error("Failed to get possible tasks"); - } - } catch (e) { - throw e; - } +export function getPossibleTasks(): Promise<Task[]> { + return executeApiGet(`task/possible`, ({ tasks }) => tasks.map((task: any) => ({ + ...task, + edited: new Date(task.edited), + created: new Date(task.created), + })), "Failed to get possible tasks"); } -export async function getTask(uuid: string): Promise<Task> { - try { - const response = await fetch(`${apiRoot}/task/${uuid}`, { headers: getAuthHeader() }); - if (response.ok) { - const task = (await response.json()).task; - return { - ...task, - edited: new Date(task.edited), - created: new Date(task.created), - }; - } else { - throw new Error("Failed to get task"); - } - } catch (e) { - throw e; - } +export function getTask(uuid: string): Promise<Task> { + return executeApiGet(`task/${uuid}`, ({ task }) => ({ + ...task, + edited: new Date(task.edited), + created: new Date(task.created), + }), "Failed to get task"); } -export async function getTaskComments(uuid: string): Promise<Comment[]> { - try { - const response = await fetch(`${apiRoot}/task/${uuid}/comments`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).comments.map((comment: any) => ({ - ...comment, - edited: new Date(comment.edited), - created: new Date(comment.created), - })); - } else { - throw new Error("Failed to get task comments"); - } - } catch (e) { - throw e; - } +export function getTaskComments(uuid: string): Promise<Comment[]> { + return executeApiGet(`task/${uuid}/comments`, ({ comments }) => comments.map((comment: any) => ({ + ...comment, + edited: new Date(comment.edited), + created: new Date(comment.created), + })), "Failed to get task comments"); } -export async function getTaskWork(uuid: string): Promise<Work[]> { - try { - const response = await fetch(`${apiRoot}/task/${uuid}/work`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).work.map((work: any) => ({ - ...work, - started: new Date(work.started), - finished: work.finished ? new Date(work.finished) : undefined, - })); - } else { - throw new Error("Failed to get task work"); - } - } catch (e) { - throw e; - } +export function getTaskWork(uuid: string): Promise<Work[]> { + return executeApiGet(`task/${uuid}/work`, ({ work }) => work.map((work: any) => ({ + ...work, + started: new Date(work.started), + finished: work.finished ? new Date(work.finished) : undefined, + })), "Failed to get task work"); } diff --git a/client/src/adapters/team.ts b/client/src/adapters/team.ts index 271087c..6bf0efa 100644 --- a/client/src/adapters/team.ts +++ b/client/src/adapters/team.ts @@ -1,7 +1,5 @@ -import { apiRoot } from 'config'; - -import { getAuthHeader } from './auth'; +import { executeApiDelete, executeApiGet, executeApiPost, executeApiPut } from './util'; import { User } from './user'; import { ReducedProject } from './project'; import { Work } from './work'; @@ -21,210 +19,62 @@ export interface TeamMember extends User { role: TeamRole; } -export async function getTeams(): Promise<Team[]> { - try { - const response = await fetch(`${apiRoot}/team/`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).teams; - } else { - throw new Error("Failed to get teams"); - } - } catch (e) { - throw e; - } -} - -export async function getTeam(uuid: string): Promise<Team> { - try { - const response = await fetch(`${apiRoot}/team/${uuid}`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).team; - } else { - throw new Error("Failed to get team"); - } - } catch (e) { - throw e; - } -} - -export async function getTeamMembers(uuid: string): Promise<TeamMember[]> { - try { - const response = await fetch(`${apiRoot}/team/${uuid}/members`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).members; - } else { - throw new Error("Failed to get team members"); - } - } catch (e) { - throw e; - } -} - -export async function getTeamRoles(uuid: string): Promise<TeamRole[]> { - try { - const response = await fetch(`${apiRoot}/team/${uuid}/roles`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).roles; - } else { - throw new Error("Failed to get team roles"); - } - } catch (e) { - throw e; - } -} - -export async function getTeamProjects(uuid: string): Promise<ReducedProject[]> { - try { - const response = await fetch(`${apiRoot}/team/${uuid}/projects`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).projects.map((project: any) => ({ - ...project, - deadline: new Date(project.deadline), - })); - } else { - throw new Error("Failed to get team projects"); - } - } catch (e) { - throw e; - } -} - -export async function getTeamWork(uuid: string): Promise<Work[]> { - try { - const response = await fetch(`${apiRoot}/team/${uuid}/work`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).work.map((work: any) => ({ - ...work, - started: new Date(work.started), - finished: work.finished ? new Date(work.finished) : undefined, - })); - } else { - throw new Error("Failed to get team work"); - } - } catch (e) { - throw e; - } -} - -export async function createTeam(name: string): Promise<string> { - try { - const response = await fetch(`${apiRoot}/team/`, { - method: 'POST', - headers: { - ...getAuthHeader(), - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - name: name, - }), - }); - if (response.ok) { - return (await response.json()).id; - } else { - throw new Error("Failed to create team"); - } - } catch (e) { - throw e; - } -} - -export async function removeTeamMember(team: string, user: string) { - try { - const response = await fetch(`${apiRoot}/team/${team}/members/${user}`, { - method: 'DELETE', - headers: getAuthHeader(), - }); - if (!response.ok) { - throw new Error("Failed to create team"); - } - } catch (e) { - throw e; - } -} - -export async function createTeamRole(team: string, name: string): Promise<TeamRole> { - try { - const response = await fetch(`${apiRoot}/team/${team}/roles`, { - method: 'POST', - headers: { - ...getAuthHeader(), - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - name: name, - }), - }); - if (response.ok) { - return (await response.json()).role; - } else { - throw new Error("Failed to create team role"); - } - } catch (e) { - throw e; - } -} - -export async function deleteTeamRole(team: string, role: string) { - try { - const response = await fetch(`${apiRoot}/team/${team}/roles/${role}`, { - method: 'DELETE', - headers: getAuthHeader(), - }); - if (!response.ok) { - throw new Error("Failed to delete team role"); - } - } catch (e) { - throw e; - } -} - -export async function addTeamMember(team: string, member: { user: string, role: string }) { - try { - const response = await fetch(`${apiRoot}/team/${team}/members`, { - method: 'POST', - headers: { - ...getAuthHeader(), - 'Content-Type': 'application/json', - }, - body: JSON.stringify(member), - }); - if (!response.ok) { - throw new Error("Failed to add team member"); - } - } catch (e) { - throw e; - } -} - -export async function updateTeamMember(team: string, member: { user: string, role: string }) { - try { - const response = await fetch(`${apiRoot}/team/${team}/members`, { - method: 'PUT', - headers: { - ...getAuthHeader(), - 'Content-Type': 'application/json', - }, - body: JSON.stringify(member), - }); - if (!response.ok) { - throw new Error("Failed to update team member"); - } - } catch (e) { - throw e; - } -} - -export async function leaveTeam(team: string) { - try { - const response = await fetch(`${apiRoot}/team/${team}`, { - method: 'DELETE', - headers: getAuthHeader(), - }); - if (!response.ok) { - throw new Error("Failed to leave team"); - } - } catch (e) { - throw e; - } +export function getTeams(): Promise<Team[]> { + return executeApiGet(`team`, ({ teams }) => teams, "Failed to get teams"); +} + +export function getTeam(uuid: string): Promise<Team> { + return executeApiGet(`team/${uuid}`, ({ team }) => team, "Failed to get team"); +} + +export function getTeamMembers(uuid: string): Promise<TeamMember[]> { + return executeApiGet(`team/${uuid}/members`, ({ members }) => members, "Failed to get team members"); +} + +export function getTeamRoles(uuid: string): Promise<TeamRole[]> { + return executeApiGet(`team/${uuid}/roles`, ({ roles }) => roles, "Failed to get team roles"); +} + +export function getTeamProjects(uuid: string): Promise<ReducedProject[]> { + return executeApiGet(`team/${uuid}/projects`, ({ projects }) => projects.map((project: any) => ({ + ...project, + deadline: new Date(project.deadline), + })), "Failed to get team projects"); +} + +export function getTeamWork(uuid: string): Promise<Work[]> { + return executeApiGet(`team/${uuid}/work`, ({ work }) => work.map((work: any) => ({ + ...work, + started: new Date(work.started), + finished: work.finished ? new Date(work.finished) : undefined, + })), "Failed to get team work"); +} + +export function createTeam(name: string): Promise<string> { + return executeApiPost(`team`, { name: name }, ({ id }) => id, "Failed to create team"); +} + +export function removeTeamMember(team: string, user: string) { + return executeApiDelete(`team/${team}/members/${user}`, () => {}, "Failed to remove team member"); +} + +export function createTeamRole(team: string, name: string): Promise<TeamRole> { + return executeApiPost(`team/${team}/roles`, { name: name }, ({ role }) => role, "Failed to create team role"); +} + +export function deleteTeamRole(team: string, role: string) { + return executeApiDelete(`team/${team}/roles/${role}`, () => {}, "Failed to delete team role"); +} + +export function addTeamMember(team: string, member: { user: string, role: string }) { + return executeApiPost(`team/${team}/members`, member, () => {}, "Failed to add team member"); +} + +export function updateTeamMember(team: string, member: { user: string, role: string }) { + return executeApiPut(`team/${team}/members`, member, () => {}, "Failed to update team member"); +} + +export function leaveTeam(team: string) { + return executeApiDelete(`team/${team}`, () => {}, "Failed to leave team"); } diff --git a/client/src/adapters/user.ts b/client/src/adapters/user.ts index 7f6ccf6..1eaf9f0 100644 --- a/client/src/adapters/user.ts +++ b/client/src/adapters/user.ts @@ -1,7 +1,7 @@ import { apiRoot } from 'config'; -import { getAuthHeader } from './auth'; +import { executeApiGet, executeApiPut } from './util'; import { Task } from './task'; import { Work } from './work'; @@ -22,82 +22,32 @@ export async function exists(username: string) { } } -export async function getCurrentUser(): Promise<User> { - try { - const response = await fetch(`${apiRoot}/user/`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).user; - } else { - throw new Error("Failed to get user"); - } - } catch (e) { - throw e; - } +export function getCurrentUser(): Promise<User> { + return executeApiGet(`user`, ({ user }) => user, "Failed to get user"); } -export async function getUserTasks(): Promise<Array<Task>> { - try { - const response = await fetch(`${apiRoot}/user/tasks`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).tasks.map((task: any) => ({ - ...task, - edited: new Date(task.edited), - created: new Date(task.created), - })); - } else { - throw new Error("Failed to get user tasks"); - } - } catch (e) { - throw e; - } +export function getUserTasks(): Promise<Array<Task>> { + return executeApiGet(`user/tasks`, ({ tasks }) => tasks.map((task: any) => ({ + ...task, + edited: new Date(task.edited), + created: new Date(task.created), + })), "Failed to get user tasks"); } -export async function getUserWork(): Promise<Work> { - try { - const response = await fetch(`${apiRoot}/user/work`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).work.map((work: any) => ({ - ...work, - started: new Date(work.started), - finished: work.finished ? new Date(work.finished) : undefined, - })); - } else { - throw new Error("Failed to get user work"); - } - } catch (e) { - throw e; - } +export function getUserWork(): Promise<Work> { + return executeApiGet(`user/work`, ({ work }) => work.map((work: any) => ({ + ...work, + started: new Date(work.started), + finished: work.finished ? new Date(work.finished) : undefined, + })), "Failed to get user work"); } -export async function getUser(uuid: string): Promise<User> { - try { - const response = await fetch(`${apiRoot}/user/${uuid}`, { headers: getAuthHeader() }); - if (response.ok) { - return (await response.json()).user; - } else { - throw new Error("Failed to get user"); - } - } catch (e) { - throw e; - } +export function getUser(uuid: string): Promise<User> { + return executeApiGet(`user/${uuid}`, ({ user }) => user, "Failed to get user"); } -export async function updateUser(user: { realname?: string, email?: string }) { - try { - const response = await fetch(`${apiRoot}/user/`, { - method: 'PUT', - headers: { - ...getAuthHeader(), - 'Content-Type': 'application/json', - }, - body: JSON.stringify(user), - }); - if (!response.ok) { - throw new Error("Failed to update user"); - } - } catch (e) { - throw e; - } +export function updateUser(user: { realname?: string, email?: string }) { + return executeApiPut(`user`, user, () => {}, "Failed to update user"); } export function getUserImageUri(uuid: string): string { diff --git a/client/src/adapters/util.ts b/client/src/adapters/util.ts new file mode 100644 index 0000000..08a6b61 --- /dev/null +++ b/client/src/adapters/util.ts @@ -0,0 +1,41 @@ + +import { apiRoot } from 'config'; + +import { getAuthHeader } from './auth'; + +async function executeApiRequest<T>(path: string, method: string, body: any, onSuccess: (data: any) => T, errorMessage: string): Promise<T> { + try { + const response = await fetch(`${apiRoot}/${path}`, { + method: method, + headers: { + ...getAuthHeader(), + ...(body ? { 'Content-Type': 'application/json' } : { }), + }, + body: body ? JSON.stringify(body) : undefined, + }); + if (response.ok) { + return onSuccess(await response.json()); + } else { + throw new Error(errorMessage); + } + } catch (e) { + throw new Error(errorMessage); + } +} + +export function executeApiGet<T>(path: string, onSuccess: (data: any) => T, errorMessage: string): Promise<T> { + return executeApiRequest(path, 'GET', undefined, onSuccess, errorMessage); +} + +export function executeApiDelete<T>(path: string, onSuccess: (data: any) => T, errorMessage: string): Promise<T> { + return executeApiRequest(path, 'DELETE', undefined, onSuccess, errorMessage); +} + +export function executeApiPost<T>(path: string, body: any, onSuccess: (data: any) => T, errorMessage: string): Promise<T> { + return executeApiRequest(path, 'POST', body, onSuccess, errorMessage); +} + +export function executeApiPut<T>(path: string, body: any, onSuccess: (data: any) => T, errorMessage: string): Promise<T> { + return executeApiRequest(path, 'PUT', body, onSuccess, errorMessage); +} + -- GitLab