diff options
Diffstat (limited to 'FrontEnd/src/app/http')
-rw-r--r-- | FrontEnd/src/app/http/bookmark.ts | 49 | ||||
-rw-r--r-- | FrontEnd/src/app/http/common.ts | 214 | ||||
-rw-r--r-- | FrontEnd/src/app/http/highlight.ts | 49 | ||||
-rw-r--r-- | FrontEnd/src/app/http/search.ts | 36 | ||||
-rw-r--r-- | FrontEnd/src/app/http/timeline.ts | 234 | ||||
-rw-r--r-- | FrontEnd/src/app/http/token.ts | 71 | ||||
-rw-r--r-- | FrontEnd/src/app/http/user.ts | 161 |
7 files changed, 0 insertions, 814 deletions
diff --git a/FrontEnd/src/app/http/bookmark.ts b/FrontEnd/src/app/http/bookmark.ts deleted file mode 100644 index 3e5be229..00000000 --- a/FrontEnd/src/app/http/bookmark.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { axios, apiBaseUrl, extractResponseData } from "./common"; - -import { HttpTimelineInfo } from "./timeline"; - -export interface HttpHighlightMoveRequest { - timeline: string; - newPosition: number; -} - -export interface IHttpBookmarkClient { - list(): Promise<HttpTimelineInfo[]>; - put(timeline: string): Promise<void>; - delete(timeline: string): Promise<void>; - move(req: HttpHighlightMoveRequest): Promise<void>; -} - -export class HttpHighlightClient implements IHttpBookmarkClient { - list(): Promise<HttpTimelineInfo[]> { - return axios - .get<HttpTimelineInfo[]>(`${apiBaseUrl}/bookmarks`) - .then(extractResponseData); - } - - put(timeline: string): Promise<void> { - return axios.put(`${apiBaseUrl}/bookmarks/${timeline}`).then(); - } - - delete(timeline: string): Promise<void> { - return axios.delete(`${apiBaseUrl}/bookmarks/${timeline}`).then(); - } - - move(req: HttpHighlightMoveRequest): Promise<void> { - return axios.post(`${apiBaseUrl}/bookmarkop/move`, req).then(); - } -} - -let client: IHttpBookmarkClient = new HttpHighlightClient(); - -export function getHttpBookmarkClient(): IHttpBookmarkClient { - return client; -} - -export function setHttpBookmarkClient( - newClient: IHttpBookmarkClient -): IHttpBookmarkClient { - const old = client; - client = newClient; - return old; -} diff --git a/FrontEnd/src/app/http/common.ts b/FrontEnd/src/app/http/common.ts deleted file mode 100644 index e1672985..00000000 --- a/FrontEnd/src/app/http/common.ts +++ /dev/null @@ -1,214 +0,0 @@ -import rawAxios, { AxiosError, AxiosResponse } from "axios"; -import { Base64 } from "js-base64"; -import { BehaviorSubject, Observable } from "rxjs"; - -export const apiBaseUrl = "/api"; - -export const axios = rawAxios.create(); - -function convertToNetworkError(error: AxiosError): never { - if (error.isAxiosError && error.response == null) { - throw new HttpNetworkError(error); - } else { - throw error; - } -} - -function convertToForbiddenError(error: AxiosError): never { - if ( - error.isAxiosError && - error.response != null && - (error.response.status == 401 || error.response.status == 403) - ) { - throw new HttpForbiddenError(error); - } else { - throw error; - } -} - -function convertToNotFoundError(error: AxiosError): never { - if ( - error.isAxiosError && - error.response != null && - error.response.status == 404 - ) { - throw new HttpNotFoundError(error); - } else { - throw error; - } -} - -rawAxios.interceptors.response.use(undefined, convertToNetworkError); -rawAxios.interceptors.response.use(undefined, convertToForbiddenError); -rawAxios.interceptors.response.use(undefined, convertToNotFoundError); -axios.interceptors.response.use(undefined, convertToNetworkError); -axios.interceptors.response.use(undefined, convertToForbiddenError); -axios.interceptors.response.use(undefined, convertToNotFoundError); - -const tokenSubject = new BehaviorSubject<string | null>(null); - -export function getHttpToken(): string | null { - return tokenSubject.value; -} - -export function setHttpToken(token: string | null): void { - tokenSubject.next(token); - - if (token == null) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - delete axios.defaults.headers.common["Authorization"]; - } else { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - axios.defaults.headers.common["Authorization"] = `Bearer ${token}`; - } -} - -export const token$: Observable<string | null> = tokenSubject.asObservable(); - -export function base64(blob: Blob | string): Promise<string> { - if (typeof blob === "string") { - return Promise.resolve(Base64.encode(blob)); - } - - return new Promise<string>((resolve) => { - const reader = new FileReader(); - reader.onload = function () { - resolve((reader.result as string).replace(/^data:.*;base64,/, "")); - }; - reader.readAsDataURL(blob); - }); -} - -export function extractStatusCode(error: AxiosError): number | null { - if (error.isAxiosError) { - const code = error?.response?.status; - if (typeof code === "number") { - return code; - } - } - return null; -} - -export interface CommonErrorResponse { - code: number; - message: string; -} - -export function extractErrorCode( - error: AxiosError<CommonErrorResponse> -): number | null { - if (error.isAxiosError) { - const code = error.response?.data?.code; - if (typeof code === "number") { - return code; - } - } - return null; -} - -export class HttpNetworkError extends Error { - constructor(public innerError?: AxiosError) { - super(); - } -} - -export class HttpForbiddenError extends Error { - constructor(public innerError?: AxiosError) { - super(); - } -} - -export class HttpNotFoundError extends Error { - constructor(public innerError?: AxiosError) { - super(); - } -} - -export class NotModified {} - -export interface BlobWithEtag { - data: Blob; - etag: string; -} - -export function extractResponseData<T>(res: AxiosResponse<T>): T { - return res.data; -} - -export function catchIfStatusCodeIs< - TResult, - TErrorHandlerResult extends TResult | PromiseLike<TResult> | null | undefined ->( - statusCode: number, - errorHandler: (error: AxiosError<CommonErrorResponse>) => TErrorHandlerResult -): (error: AxiosError<CommonErrorResponse>) => TErrorHandlerResult { - return (error: AxiosError<CommonErrorResponse>) => { - if (extractStatusCode(error) == statusCode) { - return errorHandler(error); - } else { - throw error; - } - }; -} - -export function convertToIfStatusCodeIs<NewError>( - statusCode: number, - newErrorType: { - new (innerError: AxiosError): NewError; - } -): (error: AxiosError<CommonErrorResponse>) => never { - return catchIfStatusCodeIs(statusCode, (error) => { - throw new newErrorType(error); - }); -} - -export function catchIfErrorCodeIs< - TResult, - TErrorHandlerResult extends TResult | PromiseLike<TResult> | null | undefined ->( - errorCode: number, - errorHandler: (error: AxiosError<CommonErrorResponse>) => TErrorHandlerResult -): (error: AxiosError<CommonErrorResponse>) => TErrorHandlerResult { - return (error: AxiosError<CommonErrorResponse>) => { - if (extractErrorCode(error) == errorCode) { - return errorHandler(error); - } else { - throw error; - } - }; -} -export function convertToIfErrorCodeIs<NewError>( - errorCode: number, - newErrorType: { - new (innerError: AxiosError): NewError; - } -): (error: AxiosError<CommonErrorResponse>) => never { - return catchIfErrorCodeIs(errorCode, (error) => { - throw new newErrorType(error); - }); -} - -export function convertToNotModified( - error: AxiosError<CommonErrorResponse> -): NotModified { - if ( - error.isAxiosError && - error.response != null && - error.response.status == 304 - ) { - return new NotModified(); - } else { - throw error; - } -} - -export function convertToBlobWithEtag(res: AxiosResponse<Blob>): BlobWithEtag { - return { - data: res.data, - etag: (res.headers as Record<"etag", string>)["etag"], - }; -} - -export function extractEtag(res: AxiosResponse): string { - return (res.headers as Record<"etag", string>)["etag"]; -} diff --git a/FrontEnd/src/app/http/highlight.ts b/FrontEnd/src/app/http/highlight.ts deleted file mode 100644 index fddf0729..00000000 --- a/FrontEnd/src/app/http/highlight.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { axios, apiBaseUrl, extractResponseData } from "./common"; - -import { HttpTimelineInfo } from "./timeline"; - -export interface HttpHighlightMoveRequest { - timeline: string; - newPosition: number; -} - -export interface IHttpHighlightClient { - list(): Promise<HttpTimelineInfo[]>; - put(timeline: string): Promise<void>; - delete(timeline: string): Promise<void>; - move(req: HttpHighlightMoveRequest): Promise<void>; -} - -export class HttpHighlightClient implements IHttpHighlightClient { - list(): Promise<HttpTimelineInfo[]> { - return axios - .get<HttpTimelineInfo[]>(`${apiBaseUrl}/highlights`) - .then(extractResponseData); - } - - put(timeline: string): Promise<void> { - return axios.put(`${apiBaseUrl}/highlights/${timeline}`).then(); - } - - delete(timeline: string): Promise<void> { - return axios.delete(`${apiBaseUrl}/highlights/${timeline}`).then(); - } - - move(req: HttpHighlightMoveRequest): Promise<void> { - return axios.post(`${apiBaseUrl}/highlightop/move`, req).then(); - } -} - -let client: IHttpHighlightClient = new HttpHighlightClient(); - -export function getHttpHighlightClient(): IHttpHighlightClient { - return client; -} - -export function setHttpHighlightClient( - newClient: IHttpHighlightClient -): IHttpHighlightClient { - const old = client; - client = newClient; - return old; -} diff --git a/FrontEnd/src/app/http/search.ts b/FrontEnd/src/app/http/search.ts deleted file mode 100644 index 8ca48fe9..00000000 --- a/FrontEnd/src/app/http/search.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { apiBaseUrl, axios, extractResponseData } from "./common"; -import { HttpTimelineInfo } from "./timeline"; -import { HttpUser } from "./user"; - -export interface IHttpSearchClient { - searchTimelines(query: string): Promise<HttpTimelineInfo[]>; - searchUsers(query: string): Promise<HttpUser[]>; -} - -export class HttpSearchClient implements IHttpSearchClient { - searchTimelines(query: string): Promise<HttpTimelineInfo[]> { - return axios - .get<HttpTimelineInfo[]>(`${apiBaseUrl}/search/timelines?q=${query}`) - .then(extractResponseData); - } - - searchUsers(query: string): Promise<HttpUser[]> { - return axios - .get<HttpUser[]>(`${apiBaseUrl}/search/users?q=${query}`) - .then(extractResponseData); - } -} - -let client: IHttpSearchClient = new HttpSearchClient(); - -export function getHttpSearchClient(): IHttpSearchClient { - return client; -} - -export function setHttpSearchClient( - newClient: IHttpSearchClient -): IHttpSearchClient { - const old = client; - client = newClient; - return old; -} diff --git a/FrontEnd/src/app/http/timeline.ts b/FrontEnd/src/app/http/timeline.ts deleted file mode 100644 index 9697c1a0..00000000 --- a/FrontEnd/src/app/http/timeline.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { AxiosError } from "axios"; - -import { applyQueryParameters } from "../utilities/url"; - -import { - axios, - apiBaseUrl, - extractResponseData, - convertToIfErrorCodeIs, - getHttpToken, -} from "./common"; -import { HttpUser } from "./user"; - -export const kTimelineVisibilities = ["Public", "Register", "Private"] as const; - -export type TimelineVisibility = typeof kTimelineVisibilities[number]; - -export interface HttpTimelineInfo { - uniqueId: string; - title: string; - name: string; - description: string; - owner: HttpUser; - visibility: TimelineVisibility; - color: string; - lastModified: string; - members: HttpUser[]; - isHighlight: boolean; - isBookmark: boolean; - manageable: boolean; - postable: boolean; -} - -export interface HttpTimelineListQuery { - visibility?: TimelineVisibility; - relate?: string; - relateType?: "own" | "join"; -} - -export interface HttpTimelinePostRequest { - name: string; -} - -export interface HttpTimelinePostDataDigest { - kind: string; - eTag: string; - lastUpdated: string; -} - -export interface HttpTimelinePostInfo { - id: number; - time: string; - author: HttpUser; - dataList: HttpTimelinePostDataDigest[]; - color: string; - lastUpdated: string; - timelineName: string; - editable: boolean; -} - -export interface HttpTimelinePostPostRequestData { - contentType: string; - data: string; -} - -export interface HttpTimelinePostPostRequest { - time?: string; - color?: string; - dataList: HttpTimelinePostPostRequestData[]; -} - -export interface HttpTimelinePatchRequest { - name?: string; - title?: string; - color?: string; - visibility?: TimelineVisibility; - description?: string; -} - -export interface HttpTimelinePostPatchRequest { - time?: string; - color?: string; -} - -export class HttpTimelineNameConflictError extends Error { - constructor(public innerError?: AxiosError) { - super(); - } -} - -export interface IHttpTimelineClient { - listTimeline(query: HttpTimelineListQuery): Promise<HttpTimelineInfo[]>; - getTimeline(timelineName: string): Promise<HttpTimelineInfo>; - postTimeline(req: HttpTimelinePostRequest): Promise<HttpTimelineInfo>; - patchTimeline( - timelineName: string, - req: HttpTimelinePatchRequest - ): Promise<HttpTimelineInfo>; - deleteTimeline(timelineName: string): Promise<void>; - memberPut(timelineName: string, username: string): Promise<void>; - memberDelete(timelineName: string, username: string): Promise<void>; - listPost(timelineName: string): Promise<HttpTimelinePostInfo[]>; - generatePostDataUrl(timelineName: string, postId: number): string; - getPostDataAsString(timelineName: string, postId: number): Promise<string>; - postPost( - timelineName: string, - req: HttpTimelinePostPostRequest - ): Promise<HttpTimelinePostInfo>; - patchPost( - timelineName: string, - postId: number, - req: HttpTimelinePostPatchRequest - ): Promise<HttpTimelinePostInfo>; - deletePost(timelineName: string, postId: number): Promise<void>; -} - -export class HttpTimelineClient implements IHttpTimelineClient { - listTimeline(query: HttpTimelineListQuery): Promise<HttpTimelineInfo[]> { - return axios - .get<HttpTimelineInfo[]>( - applyQueryParameters(`${apiBaseUrl}/timelines`, query) - ) - .then(extractResponseData); - } - - getTimeline(timelineName: string): Promise<HttpTimelineInfo> { - return axios - .get<HttpTimelineInfo>(`${apiBaseUrl}/timelines/${timelineName}`) - .then(extractResponseData); - } - - postTimeline(req: HttpTimelinePostRequest): Promise<HttpTimelineInfo> { - return axios - .post<HttpTimelineInfo>(`${apiBaseUrl}/timelines`, req) - .then(extractResponseData) - .catch(convertToIfErrorCodeIs(11040101, HttpTimelineNameConflictError)); - } - - patchTimeline( - timelineName: string, - req: HttpTimelinePatchRequest - ): Promise<HttpTimelineInfo> { - return axios - .patch<HttpTimelineInfo>(`${apiBaseUrl}/timelines/${timelineName}`, req) - .then(extractResponseData); - } - - deleteTimeline(timelineName: string): Promise<void> { - return axios.delete(`${apiBaseUrl}/timelines/${timelineName}`).then(); - } - - memberPut(timelineName: string, username: string): Promise<void> { - return axios - .put(`${apiBaseUrl}/timelines/${timelineName}/members/${username}`) - .then(); - } - - memberDelete(timelineName: string, username: string): Promise<void> { - return axios - .delete(`${apiBaseUrl}/timelines/${timelineName}/members/${username}`) - .then(); - } - - listPost(timelineName: string): Promise<HttpTimelinePostInfo[]> { - return axios - .get<HttpTimelinePostInfo[]>( - `${apiBaseUrl}/timelines/${timelineName}/posts` - ) - .then(extractResponseData); - } - - generatePostDataUrl(timelineName: string, postId: number): string { - return applyQueryParameters( - `${apiBaseUrl}/timelines/${timelineName}/posts/${postId}/data`, - { token: getHttpToken() } - ); - } - - getPostDataAsString(timelineName: string, postId: number): Promise<string> { - return axios - .get<string>( - `${apiBaseUrl}/timelines/${timelineName}/posts/${postId}/data`, - { - responseType: "text", - } - ) - .then(extractResponseData); - } - - postPost( - timelineName: string, - req: HttpTimelinePostPostRequest - ): Promise<HttpTimelinePostInfo> { - return axios - .post<HttpTimelinePostInfo>( - `${apiBaseUrl}/timelines/${timelineName}/posts`, - req - ) - .then(extractResponseData); - } - - patchPost( - timelineName: string, - postId: number, - req: HttpTimelinePostPatchRequest - ): Promise<HttpTimelinePostInfo> { - return axios - .patch<HttpTimelinePostInfo>( - `${apiBaseUrl}/timelines/${timelineName}/posts/${postId}`, - req - ) - .then(extractResponseData); - } - - deletePost(timelineName: string, postId: number): Promise<void> { - return axios - .delete(`${apiBaseUrl}/timelines/${timelineName}/posts/${postId}`) - .then(); - } -} - -let client: IHttpTimelineClient = new HttpTimelineClient(); - -export function getHttpTimelineClient(): IHttpTimelineClient { - return client; -} - -export function setHttpTimelineClient( - newClient: IHttpTimelineClient -): IHttpTimelineClient { - const old = client; - client = newClient; - return old; -} diff --git a/FrontEnd/src/app/http/token.ts b/FrontEnd/src/app/http/token.ts deleted file mode 100644 index f8b09d63..00000000 --- a/FrontEnd/src/app/http/token.ts +++ /dev/null @@ -1,71 +0,0 @@ -// Don't use axios in common because it will contains -// authorization header, which shouldn't be used in token apis. -import axios, { AxiosError } from "axios"; - -import { - apiBaseUrl, - convertToIfErrorCodeIs, - extractResponseData, -} from "./common"; -import { HttpUser } from "./user"; - -export interface HttpCreateTokenRequest { - username: string; - password: string; - expire: number; -} - -export interface HttpCreateTokenResponse { - token: string; - user: HttpUser; -} - -export interface HttpVerifyTokenRequest { - token: string; -} - -export interface HttpVerifyTokenResponse { - user: HttpUser; -} - -export class HttpCreateTokenBadCredentialError extends Error { - constructor(public innerError?: AxiosError) { - super(); - } -} - -export interface IHttpTokenClient { - create(req: HttpCreateTokenRequest): Promise<HttpCreateTokenResponse>; - verify(req: HttpVerifyTokenRequest): Promise<HttpVerifyTokenResponse>; -} - -export class HttpTokenClient implements IHttpTokenClient { - create(req: HttpCreateTokenRequest): Promise<HttpCreateTokenResponse> { - return axios - .post<HttpCreateTokenResponse>(`${apiBaseUrl}/token/create`, req) - .then(extractResponseData) - .catch( - convertToIfErrorCodeIs(11010101, HttpCreateTokenBadCredentialError) - ); - } - - verify(req: HttpVerifyTokenRequest): Promise<HttpVerifyTokenResponse> { - return axios - .post<HttpVerifyTokenResponse>(`${apiBaseUrl}/token/verify`, req) - .then(extractResponseData); - } -} - -let client: IHttpTokenClient = new HttpTokenClient(); - -export function getHttpTokenClient(): IHttpTokenClient { - return client; -} - -export function setHttpTokenClient( - newClient: IHttpTokenClient -): IHttpTokenClient { - const old = client; - client = newClient; - return old; -} diff --git a/FrontEnd/src/app/http/user.ts b/FrontEnd/src/app/http/user.ts deleted file mode 100644 index dcf24cba..00000000 --- a/FrontEnd/src/app/http/user.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { AxiosError } from "axios"; - -import { - axios, - apiBaseUrl, - extractResponseData, - convertToIfStatusCodeIs, - convertToIfErrorCodeIs, - extractEtag, -} from "./common"; - -export const kUserManagement = "UserManagement"; -export const kAllTimelineManagement = "AllTimelineManagement"; -export const kHighlightTimelineManagement = "HighlightTimelineManagement"; - -export const kUserPermissionList = [ - kUserManagement, - kAllTimelineManagement, - kHighlightTimelineManagement, -] as const; - -export type UserPermission = typeof kUserPermissionList[number]; - -export interface HttpUser { - uniqueId: string; - username: string; - permissions: UserPermission[]; - nickname: string; -} - -export interface HttpUserPatchRequest { - username?: string; - password?: string; - nickname?: string; -} - -export interface HttpChangePasswordRequest { - oldPassword: string; - newPassword: string; -} - -export interface HttpCreateUserRequest { - username: string; - password: string; -} - -export class HttpUserNotExistError extends Error { - constructor(public innerError?: AxiosError) { - super(); - } -} - -export class HttpChangePasswordBadCredentialError extends Error { - constructor(public innerError?: AxiosError) { - super(); - } -} - -export interface IHttpUserClient { - list(): Promise<HttpUser[]>; - get(username: string): Promise<HttpUser>; - post(req: HttpCreateUserRequest): Promise<HttpUser>; - patch(username: string, req: HttpUserPatchRequest): Promise<HttpUser>; - delete(username: string): Promise<void>; - generateAvatarUrl(username: string): string; - putAvatar(username: string, data: Blob): Promise<string>; - changePassword(req: HttpChangePasswordRequest): Promise<void>; - putUserPermission( - username: string, - permission: UserPermission - ): Promise<void>; - deleteUserPermission( - username: string, - permission: UserPermission - ): Promise<void>; -} - -export class HttpUserClient implements IHttpUserClient { - list(): Promise<HttpUser[]> { - return axios - .get<HttpUser[]>(`${apiBaseUrl}/users`) - .then(extractResponseData); - } - - get(username: string): Promise<HttpUser> { - return axios - .get<HttpUser>(`${apiBaseUrl}/users/${username}`) - .then(extractResponseData) - .catch(convertToIfStatusCodeIs(404, HttpUserNotExistError)); - } - - post(req: HttpCreateUserRequest): Promise<HttpUser> { - return axios - .post<HttpUser>(`${apiBaseUrl}/users`, req) - .then(extractResponseData) - .then(); - } - - patch(username: string, req: HttpUserPatchRequest): Promise<HttpUser> { - return axios - .patch<HttpUser>(`${apiBaseUrl}/users/${username}`, req) - .then(extractResponseData); - } - - delete(username: string): Promise<void> { - return axios.delete(`${apiBaseUrl}/users/${username}`).then(); - } - - generateAvatarUrl(username: string): string { - return `${apiBaseUrl}/users/${username}/avatar`; - } - - putAvatar(username: string, data: Blob): Promise<string> { - return axios - .put(`${apiBaseUrl}/users/${username}/avatar`, data, { - headers: { - "Content-Type": data.type, - }, - }) - .then(extractEtag); - } - - changePassword(req: HttpChangePasswordRequest): Promise<void> { - return axios - .post(`${apiBaseUrl}/userop/changepassword`, req) - .catch( - convertToIfErrorCodeIs(11020201, HttpChangePasswordBadCredentialError) - ) - .then(); - } - - putUserPermission( - username: string, - permission: UserPermission - ): Promise<void> { - return axios - .put(`${apiBaseUrl}/users/${username}/permissions/${permission}`) - .then(); - } - - deleteUserPermission( - username: string, - permission: UserPermission - ): Promise<void> { - return axios - .delete(`${apiBaseUrl}/users/${username}/permissions/${permission}`) - .then(); - } -} - -let client: IHttpUserClient = new HttpUserClient(); - -export function getHttpUserClient(): IHttpUserClient { - return client; -} - -export function setHttpUserClient(newClient: IHttpUserClient): IHttpUserClient { - const old = client; - client = newClient; - return old; -} |