aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-10-27 18:52:01 +0800
committercrupest <crupest@outlook.com>2020-10-27 18:52:01 +0800
commit986c6f2e3b858d6332eba0b42acc6861cd4d0227 (patch)
treef0c1a71eb855ad2b3f2640c54b38ecd6cffd79d8
parentf88f9e7281c63da6a3d2c87be439fbcb30f6fe20 (diff)
downloadtimeline-986c6f2e3b858d6332eba0b42acc6861cd4d0227.tar.gz
timeline-986c6f2e3b858d6332eba0b42acc6861cd4d0227.tar.bz2
timeline-986c6f2e3b858d6332eba0b42acc6861cd4d0227.zip
refactor: Remove mock backend.
-rw-r--r--Timeline/ClientApp/.pnp.js30
-rw-r--r--Timeline/ClientApp/package.json3
-rw-r--r--Timeline/ClientApp/src/app/http/mock/common.ts78
-rw-r--r--Timeline/ClientApp/src/app/http/mock/default-avatar.pngbin26442 -> 0 bytes
-rw-r--r--Timeline/ClientApp/src/app/http/mock/install.ts11
-rw-r--r--Timeline/ClientApp/src/app/http/mock/timeline.ts660
-rw-r--r--Timeline/ClientApp/src/app/http/mock/token.ts53
-rw-r--r--Timeline/ClientApp/src/app/http/mock/user.ts139
-rw-r--r--Timeline/ClientApp/webpack.config.dev.js10
-rw-r--r--Timeline/ClientApp/yarn.lock16
10 files changed, 1 insertions, 999 deletions
diff --git a/Timeline/ClientApp/.pnp.js b/Timeline/ClientApp/.pnp.js
index c696f50e..af643e73 100644
--- a/Timeline/ClientApp/.pnp.js
+++ b/Timeline/ClientApp/.pnp.js
@@ -74,10 +74,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"npm:2.2.10::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fclassnames%2Fdownload%2F%40types%2Fclassnames-2.2.10.tgz"
],
[
- "@types/crypto-js",
- "npm:4.0.1"
- ],
- [
"@types/lodash",
"npm:4.14.162"
],
@@ -170,10 +166,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"npm:3.6.5::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-3.6.5.tgz"
],
[
- "crypto-js",
- "npm:4.0.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcrypto-js%2Fdownload%2Fcrypto-js-4.0.0.tgz"
- ],
- [
"css-loader",
"virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:5.0.0"
],
@@ -384,7 +376,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@babel/preset-typescript", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:7.12.1"],
["@hot-loader/react-dom", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:17.0.0"],
["@types/classnames", "npm:2.2.10::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fclassnames%2Fdownload%2F%40types%2Fclassnames-2.2.10.tgz"],
- ["@types/crypto-js", "npm:4.0.1"],
["@types/lodash", "npm:4.14.162"],
["@types/node", "npm:14.14.5"],
["@types/react", "npm:16.9.53"],
@@ -408,7 +399,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["clsx", "npm:1.1.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fclsx%2Fdownload%2Fclsx-1.1.1.tgz"],
["copy-webpack-plugin", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:6.2.1"],
["core-js", "npm:3.6.5::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-3.6.5.tgz"],
- ["crypto-js", "npm:4.0.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcrypto-js%2Fdownload%2Fcrypto-js-4.0.0.tgz"],
["css-loader", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:5.0.0"],
["eslint", "npm:7.12.1"],
["eslint-config-prettier", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:6.14.0"],
@@ -3388,15 +3378,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD",
}]
]],
- ["@types/crypto-js", [
- ["npm:4.0.1", {
- "packageLocation": "./.yarn/cache/@types-crypto-js-npm-4.0.1-4f7dc14813-6b81c4d064.zip/node_modules/@types/crypto-js/",
- "packageDependencies": [
- ["@types/crypto-js", "npm:4.0.1"]
- ],
- "linkType": "HARD",
- }]
- ]],
["@types/emscripten", [
["npm:1.39.4::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Femscripten%2Fdownload%2F%40types%2Femscripten-1.39.4.tgz", {
"packageLocation": "./.yarn/cache/@types-emscripten-npm-1.39.4-9fa9d5794b-b848421e25.zip/node_modules/@types/emscripten/",
@@ -6106,15 +6087,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD",
}]
]],
- ["crypto-js", [
- ["npm:4.0.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcrypto-js%2Fdownload%2Fcrypto-js-4.0.0.tgz", {
- "packageLocation": "./.yarn/cache/crypto-js-npm-4.0.0-1dd4e6fa8d-fdd1415b9e.zip/node_modules/crypto-js/",
- "packageDependencies": [
- ["crypto-js", "npm:4.0.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcrypto-js%2Fdownload%2Fcrypto-js-4.0.0.tgz"]
- ],
- "linkType": "HARD",
- }]
- ]],
["crypto-random-string", [
["npm:1.0.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcrypto-random-string%2Fdownload%2Fcrypto-random-string-1.0.0.tgz", {
"packageLocation": "./.yarn/cache/crypto-random-string-npm-1.0.0-ec63a18cda-0876b316cc.zip/node_modules/crypto-random-string/",
@@ -13813,7 +13785,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@babel/preset-typescript", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:7.12.1"],
["@hot-loader/react-dom", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:17.0.0"],
["@types/classnames", "npm:2.2.10::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fclassnames%2Fdownload%2F%40types%2Fclassnames-2.2.10.tgz"],
- ["@types/crypto-js", "npm:4.0.1"],
["@types/lodash", "npm:4.14.162"],
["@types/node", "npm:14.14.5"],
["@types/react", "npm:16.9.53"],
@@ -13837,7 +13808,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["clsx", "npm:1.1.1::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fclsx%2Fdownload%2Fclsx-1.1.1.tgz"],
["copy-webpack-plugin", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:6.2.1"],
["core-js", "npm:3.6.5::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-3.6.5.tgz"],
- ["crypto-js", "npm:4.0.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcrypto-js%2Fdownload%2Fcrypto-js-4.0.0.tgz"],
["css-loader", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:5.0.0"],
["eslint", "npm:7.12.1"],
["eslint-config-prettier", "virtual:71f98ed0939a4e8e7ea376e302a494701bc5b6aa7a7eb81870139ee3950a7c417a3d13b346b5b526d93952a598dffe628a0fac2148047debade23536cb3d7957#npm:6.14.0"],
diff --git a/Timeline/ClientApp/package.json b/Timeline/ClientApp/package.json
index 84b5b7d5..65c5cbe2 100644
--- a/Timeline/ClientApp/package.json
+++ b/Timeline/ClientApp/package.json
@@ -37,7 +37,6 @@
},
"scripts": {
"start": "webpack-dev-server --config ./webpack.config.dev.js",
- "start:mock": "webpack-dev-server --config ./webpack.config.dev.js --env.TIMELINE_USE_MOCK_BACKEND",
"build": "webpack --config ./webpack.config.prod.js",
"lint": "eslint src/ --ext .js --ext .jsx --ext .ts --ext .tsx"
},
@@ -65,7 +64,6 @@
"@babel/preset-typescript": "^7.12.1",
"@hot-loader/react-dom": "^17.0.0",
"@types/classnames": "^2.2.10",
- "@types/crypto-js": "^4.0.1",
"@types/lodash": "^4.14.162",
"@types/node": "^14.14.5",
"@types/react": "^16.9.53",
@@ -83,7 +81,6 @@
"babel-plugin-transform-builtin-extend": "^1.1.2",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^6.2.1",
- "crypto-js": "^4.0.0",
"css-loader": "^5.0.0",
"eslint": "^7.12.1",
"eslint-config-prettier": "^6.14.0",
diff --git a/Timeline/ClientApp/src/app/http/mock/common.ts b/Timeline/ClientApp/src/app/http/mock/common.ts
deleted file mode 100644
index 787d81bd..00000000
--- a/Timeline/ClientApp/src/app/http/mock/common.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import localforage from "localforage";
-import { SHA1 } from "crypto-js";
-
-import { HttpNetworkError } from "../common";
-
-export const mockStorage = localforage.createInstance({
- name: "mock-backend",
- description: "Database for mock back end.",
- driver: localforage.INDEXEDDB,
-});
-
-export async function sha1(data: Blob): Promise<string> {
- const s = await new Promise<string>((resolve) => {
- const fileReader = new FileReader();
- fileReader.readAsBinaryString(data);
- fileReader.onload = () => {
- resolve(fileReader.result as string);
- };
- });
-
- return SHA1(s).toString();
-}
-
-const disableNetworkKey = "mockServer.disableNetwork";
-const networkLatencyKey = "mockServer.networkLatency";
-
-let disableNetwork: boolean =
- localStorage.getItem(disableNetworkKey) === "true" ? true : false;
-
-const savedNetworkLatency = localStorage.getItem(networkLatencyKey);
-
-let networkLatency: number | null =
- savedNetworkLatency != null ? Number(savedNetworkLatency) : null;
-
-Object.defineProperty(window, "disableNetwork", {
- get: () => disableNetwork,
- set: (value) => {
- if (value) {
- disableNetwork = true;
- localStorage.setItem(disableNetworkKey, "true");
- } else {
- disableNetwork = false;
- localStorage.setItem(disableNetworkKey, "false");
- }
- },
-});
-
-Object.defineProperty(window, "networkLatency", {
- get: () => networkLatency,
- set: (value) => {
- if (typeof value === "number") {
- networkLatency = value;
- localStorage.setItem(networkLatencyKey, value.toString());
- } else if (value == null) {
- networkLatency = null;
- localStorage.removeItem(networkLatencyKey);
- }
- },
-});
-
-export async function mockPrepare(key: string): Promise<void> {
- console.log(`Recieve request: ${key}`);
-
- if (disableNetwork) {
- console.warn("Network is disabled for mock server.");
- throw new HttpNetworkError();
- }
- if (networkLatency != null) {
- await new Promise((resolve) => {
- window.setTimeout(() => {
- resolve();
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- }, networkLatency! * 1000);
- });
- }
-
- await Promise.resolve();
-}
diff --git a/Timeline/ClientApp/src/app/http/mock/default-avatar.png b/Timeline/ClientApp/src/app/http/mock/default-avatar.png
deleted file mode 100644
index 4086e1d2..00000000
--- a/Timeline/ClientApp/src/app/http/mock/default-avatar.png
+++ /dev/null
Binary files differ
diff --git a/Timeline/ClientApp/src/app/http/mock/install.ts b/Timeline/ClientApp/src/app/http/mock/install.ts
deleted file mode 100644
index 17b7cc13..00000000
--- a/Timeline/ClientApp/src/app/http/mock/install.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { setHttpTokenClient } from "../token";
-import { setHttpUserClient } from "../user";
-import { setHttpTimelineClient } from "../timeline";
-
-import { MockHttpTokenClient } from "./token";
-import { MockHttpUserClient } from "./user";
-import { MockHttpTimelineClient } from "./timeline";
-
-setHttpTokenClient(new MockHttpTokenClient());
-setHttpUserClient(new MockHttpUserClient());
-setHttpTimelineClient(new MockHttpTimelineClient());
diff --git a/Timeline/ClientApp/src/app/http/mock/timeline.ts b/Timeline/ClientApp/src/app/http/mock/timeline.ts
deleted file mode 100644
index 27addd61..00000000
--- a/Timeline/ClientApp/src/app/http/mock/timeline.ts
+++ /dev/null
@@ -1,660 +0,0 @@
-import { random, without, range } from "lodash";
-
-import { BlobWithEtag, NotModified } from "../common";
-import {
- IHttpTimelineClient,
- HttpTimelineInfo,
- TimelineVisibility,
- HttpTimelineListQuery,
- HttpTimelineNotExistError,
- HttpTimelinePostRequest,
- HttpTimelineNameConflictError,
- HttpTimelinePatchRequest,
- HttpTimelinePostInfo,
- HttpTimelinePostContent,
- HttpTimelinePostPostRequest,
- HttpTimelinePostNotExistError,
- HttpTimelineGenericPostInfo,
-} from "../timeline";
-import { HttpUser } from "../user";
-
-import { mockStorage, sha1, mockPrepare } from "./common";
-import { getUser, MockUserNotExistError, checkToken } from "./user";
-
-async function getTimelineNameList(): Promise<string[]> {
- return (await mockStorage.getItem<string[]>("timelines")) ?? [];
-}
-
-async function setTimelineNameList(newOne: string[]): Promise<void> {
- await mockStorage.setItem<string[]>("timelines", newOne);
-}
-
-type TimelinePropertyKey =
- | "uniqueId"
- | "lastModified"
- | "owner"
- | "description"
- | "visibility"
- | "members"
- | "currentPostId";
-
-function getTimelinePropertyKey(
- name: string,
- property: TimelinePropertyKey
-): string {
- return `timeline.${name}.${property}`;
-}
-
-function getTimelinePropertyValue<T>(
- name: string,
- property: TimelinePropertyKey
-): Promise<T> {
- return mockStorage.getItem<T>(
- getTimelinePropertyKey(name, property)
- ) as Promise<T>;
-}
-
-function setTimelinePropertyValue<T>(
- name: string,
- property: TimelinePropertyKey,
- value: T
-): Promise<void> {
- return mockStorage
- .setItem<T>(getTimelinePropertyKey(name, property), value)
- .then();
-}
-
-function updateTimelineLastModified(name: string): Promise<void> {
- return setTimelinePropertyValue(
- name,
- "lastModified",
- new Date().toISOString()
- );
-}
-
-interface HttpTimelineInfoEx extends HttpTimelineInfo {
- memberUsernames: string[];
-}
-
-function createUniqueId(): string {
- const s = "abcdefghijklmnopqrstuvwxz0123456789";
- let result = "";
- for (let i = 0; i < 16; i++) {
- result += s[random(0, s.length - 1)];
- }
- return result;
-}
-
-class MockTimelineNotExistError extends Error {
- constructor() {
- super("Timeline not exist.");
- }
-}
-
-class MockTimelineAlreadyExistError extends Error {
- constructor() {
- super("Timeline already exist.");
- }
-}
-
-async function getTimelineInfo(name: string): Promise<HttpTimelineInfoEx> {
- let owner: HttpUser;
- if (name.startsWith("@")) {
- const ownerUsername = name.substr(1);
- owner = await getUser(ownerUsername);
- const optionalUniqueId = await getTimelinePropertyValue<string | null>(
- name,
- "uniqueId"
- );
- if (optionalUniqueId == null) {
- await setTimelineNameList([...(await getTimelineNameList()), name]);
- await setTimelinePropertyValue(name, "uniqueId", createUniqueId());
- await updateTimelineLastModified(name);
- }
- } else {
- const optionalOwnerUsername = await getTimelinePropertyValue<string | null>(
- name,
- "owner"
- );
- if (optionalOwnerUsername == null) {
- throw new MockTimelineNotExistError();
- } else {
- owner = await getUser(optionalOwnerUsername);
- }
- }
-
- const memberUsernames =
- (await getTimelinePropertyValue<string[] | null>(name, "members")) ?? [];
- const members = await Promise.all(
- memberUsernames.map(async (username) => {
- return await getUser(username);
- })
- );
-
- return {
- name,
- uniqueId: await getTimelinePropertyValue<string>(name, "uniqueId"),
- owner,
- description:
- (await getTimelinePropertyValue<string | null>(name, "description")) ??
- "",
- visibility:
- (await getTimelinePropertyValue<TimelineVisibility | null>(
- name,
- "visibility"
- )) ?? "Register",
- lastModified: new Date(
- await getTimelinePropertyValue<string>(name, "lastModified")
- ),
- members,
- memberUsernames,
- };
-}
-
-async function createTimeline(name: string, owner: string): Promise<void> {
- const optionalOwnerUsername = await getTimelinePropertyValue<string | null>(
- name,
- "owner"
- );
- if (optionalOwnerUsername != null) {
- throw new MockTimelineAlreadyExistError();
- }
-
- await setTimelineNameList([...(await getTimelineNameList()), name]);
- await setTimelinePropertyValue(name, "uniqueId", createUniqueId());
- await setTimelinePropertyValue(name, "owner", owner);
- await updateTimelineLastModified(name);
-}
-
-type TimelinePostPropertyKey =
- | "type"
- | "data"
- | "etag"
- | "author"
- | "time"
- | "lastUpdated";
-
-function getTimelinePostPropertyKey(
- timelineName: string,
- id: number,
- propertyKey: TimelinePostPropertyKey
-): string {
- return `timeline.${timelineName}.posts.${id}.${propertyKey}`;
-}
-
-function getTimelinePostPropertyValue<T>(
- timelineName: string,
- id: number,
- propertyKey: TimelinePostPropertyKey
-): Promise<T> {
- return mockStorage.getItem<T>(
- getTimelinePostPropertyKey(timelineName, id, propertyKey)
- ) as Promise<T>;
-}
-
-function setTimelinePostPropertyValue<T>(
- timelineName: string,
- id: number,
- propertyKey: TimelinePostPropertyKey,
- value: T
-): Promise<T> {
- return mockStorage.setItem(
- getTimelinePostPropertyKey(timelineName, id, propertyKey),
- value
- );
-}
-
-function removeTimelinePostProperty(
- timelineName: string,
- id: number,
- propertyKey: TimelinePostPropertyKey
-): Promise<void> {
- return mockStorage.removeItem(
- getTimelinePostPropertyKey(timelineName, id, propertyKey)
- );
-}
-
-async function getTimelinePostInfo(
- timelineName: string,
- id: number
-): Promise<HttpTimelineGenericPostInfo> {
- const currentPostId = await getTimelinePropertyValue<number | null>(
- timelineName,
- "currentPostId"
- );
- if (currentPostId == null || id > currentPostId) {
- throw new HttpTimelinePostNotExistError();
- }
-
- const type = await getTimelinePostPropertyValue<string | null>(
- timelineName,
- id,
- "type"
- );
-
- if (type == null) {
- return {
- id,
- author: await getUser(
- await getTimelinePostPropertyValue<string>(timelineName, id, "author")
- ),
- time: new Date(
- await getTimelinePostPropertyValue<string>(timelineName, id, "time")
- ),
- lastUpdated: new Date(
- await getTimelinePostPropertyValue<string>(
- timelineName,
- id,
- "lastUpdated"
- )
- ),
- deleted: true,
- };
- } else {
- let content: HttpTimelinePostContent;
- if (type === "text") {
- content = {
- type: "text",
- text: await getTimelinePostPropertyValue(timelineName, id, "data"),
- };
- } else {
- content = {
- type: "image",
- };
- }
-
- return {
- id,
- author: await getUser(
- await getTimelinePostPropertyValue<string>(timelineName, id, "author")
- ),
- time: new Date(
- await getTimelinePostPropertyValue<string>(timelineName, id, "time")
- ),
- lastUpdated: new Date(
- await getTimelinePostPropertyValue<string>(
- timelineName,
- id,
- "lastUpdated"
- )
- ),
- content,
- deleted: false,
- };
- }
-}
-
-export class MockHttpTimelineClient implements IHttpTimelineClient {
- async listTimeline(
- query: HttpTimelineListQuery
- ): Promise<HttpTimelineInfo[]> {
- await mockPrepare("timeline.list");
- return (
- await Promise.all(
- (await getTimelineNameList()).map((name) => getTimelineInfo(name))
- )
- ).filter((timeline) => {
- if (
- query.visibility != null &&
- query.visibility !== timeline.visibility
- ) {
- return false;
- }
- if (query.relate != null) {
- if (query.relateType === "own") {
- if (timeline.owner.username !== query.relate) {
- return false;
- }
- } else if (query.relateType === "join") {
- if (!timeline.memberUsernames.includes(query.relate)) {
- return false;
- }
- } else if (
- timeline.owner.username !== query.relate &&
- !timeline.memberUsernames.includes(query.relate)
- ) {
- return false;
- }
- }
- return true;
- });
- }
-
- getTimeline(timelineName: string): Promise<HttpTimelineInfo>;
- getTimeline(
- timelineName: string,
- query: {
- checkUniqueId?: string;
- }
- ): Promise<HttpTimelineInfo>;
- getTimeline(
- timelineName: string,
- query: {
- checkUniqueId?: string;
- ifModifiedSince: Date;
- }
- ): Promise<HttpTimelineInfo | NotModified>;
- async getTimeline(
- timelineName: string,
- query?: {
- checkUniqueId?: string;
- ifModifiedSince?: Date;
- }
- ): Promise<HttpTimelineInfo | NotModified> {
- await mockPrepare("timeline.get");
- try {
- const timeline = await getTimelineInfo(timelineName);
- if (query != null && query.ifModifiedSince != null) {
- if (timeline.lastModified >= query.ifModifiedSince) {
- return timeline;
- } else {
- if (
- query.checkUniqueId != null &&
- timeline.uniqueId != query.checkUniqueId
- ) {
- return timeline;
- } else {
- return new NotModified();
- }
- }
- }
-
- return timeline;
- } catch (e) {
- if (
- e instanceof MockTimelineNotExistError ||
- e instanceof MockUserNotExistError
- ) {
- throw new HttpTimelineNotExistError();
- }
- throw e;
- }
- }
-
- async postTimeline(
- req: HttpTimelinePostRequest,
- token: string
- ): Promise<HttpTimelineInfo> {
- await mockPrepare("timeline.post");
- const user = checkToken(token);
- try {
- await createTimeline(req.name, user);
- } catch (e) {
- if (e instanceof MockTimelineAlreadyExistError) {
- throw new HttpTimelineNameConflictError();
- }
- throw e;
- }
- return await getTimelineInfo(req.name);
- }
-
- async patchTimeline(
- timelineName: string,
- req: HttpTimelinePatchRequest,
- _token: string
- ): Promise<HttpTimelineInfo> {
- await mockPrepare("timeline.patch");
- let modified = false;
- if (req.description != null) {
- modified = true;
- await setTimelinePropertyValue(
- timelineName,
- "description",
- req.description
- );
- }
- if (req.visibility != null) {
- modified = true;
- await setTimelinePropertyValue(
- timelineName,
- "visibility",
- req.visibility
- );
- }
- if (modified) {
- await updateTimelineLastModified(timelineName);
- }
- return await getTimelineInfo(timelineName);
- }
-
- async deleteTimeline(timelineName: string, _token: string): Promise<void> {
- await mockPrepare("timeline.delete");
- await setTimelineNameList(
- without(await getTimelineNameList(), timelineName)
- );
- await mockStorage.removeItem(
- getTimelinePropertyKey(timelineName, "uniqueId")
- );
-
- // TODO: remove other things
- }
-
- async memberPut(
- timelineName: string,
- username: string,
- _token: string
- ): Promise<void> {
- await mockPrepare("timeline.member.put");
- const oldMembers =
- (await getTimelinePropertyValue<string[] | null>(
- timelineName,
- "members"
- )) ?? [];
- if (!oldMembers.includes(username)) {
- await setTimelinePropertyValue(timelineName, "members", [
- ...oldMembers,
- username,
- ]);
- await updateTimelineLastModified(timelineName);
- }
- }
-
- async memberDelete(
- timelineName: string,
- username: string,
- _token: string
- ): Promise<void> {
- await mockPrepare("timeline.member.delete");
- const oldMembers =
- (await getTimelinePropertyValue<string[] | null>(
- timelineName,
- "members"
- )) ?? [];
- if (oldMembers.includes(username)) {
- await setTimelinePropertyValue(
- timelineName,
- "members",
- without(oldMembers, username)
- );
- await updateTimelineLastModified(timelineName);
- }
- }
-
- listPost(
- timelineName: string,
- token?: string
- ): Promise<HttpTimelinePostInfo[]>;
- listPost(
- timelineName: string,
- token: string | undefined,
- query: {
- modifiedSince?: Date;
- includeDeleted?: false;
- }
- ): Promise<HttpTimelinePostInfo[]>;
- listPost(
- timelineName: string,
- token: string | undefined,
- query: {
- modifiedSince?: Date;
- includeDeleted: true;
- }
- ): Promise<HttpTimelineGenericPostInfo[]>;
- async listPost(
- timelineName: string,
- _token?: string,
- query?: {
- modifiedSince?: Date;
- includeDeleted?: boolean;
- }
- ): Promise<HttpTimelineGenericPostInfo[]> {
- await mockPrepare("timeline.post.list");
- // TODO: Permission check.
-
- const currentPostId = await getTimelinePropertyValue<number | null>(
- timelineName,
- "currentPostId"
- );
-
- return (
- await Promise.all(
- range(1, currentPostId == null ? 1 : currentPostId + 1).map(
- async (id) => {
- return await getTimelinePostInfo(timelineName, id);
- }
- )
- )
- )
- .filter((post) => {
- if (query?.includeDeleted !== true && post.deleted) {
- return false;
- }
- return true;
- })
- .filter((post) => {
- if (query?.modifiedSince != null) {
- return post.lastUpdated >= query.modifiedSince;
- }
- return true;
- });
- }
-
- getPostData(
- timelineName: string,
- postId: number,
- token: string
- ): Promise<BlobWithEtag>;
- async getPostData(
- timelineName: string,
- postId: number,
- _token?: string,
- etag?: string
- ): Promise<BlobWithEtag | NotModified> {
- await mockPrepare("timeline.post.data.get");
- // TODO: Permission check.
-
- const optionalSavedEtag = await getTimelinePostPropertyValue<string>(
- timelineName,
- postId,
- "etag"
- );
-
- if (optionalSavedEtag == null) {
- const optionalType = await getTimelinePostPropertyValue<string>(
- timelineName,
- postId,
- "type"
- );
-
- if (optionalType != null) {
- throw new Error("Post of this type has no data.");
- } else {
- throw new HttpTimelinePostNotExistError();
- }
- }
-
- if (etag === optionalSavedEtag) {
- return new NotModified();
- }
-
- return {
- data: await getTimelinePostPropertyValue<Blob>(
- timelineName,
- postId,
- "data"
- ),
- etag: optionalSavedEtag,
- };
- }
-
- async postPost(
- timelineName: string,
- req: HttpTimelinePostPostRequest,
- token: string
- ): Promise<HttpTimelinePostInfo> {
- await mockPrepare("timeline.post.post");
- const user = checkToken(token);
-
- const savedId = await getTimelinePropertyValue<number | null>(
- timelineName,
- "currentPostId"
- );
- const id = savedId ? savedId + 1 : 1;
- await setTimelinePropertyValue(timelineName, "currentPostId", id);
-
- await setTimelinePostPropertyValue(timelineName, id, "author", user);
-
- const currentTimeString = new Date().toISOString();
- await setTimelinePostPropertyValue(
- timelineName,
- id,
- "lastUpdated",
- currentTimeString
- );
-
- await setTimelinePostPropertyValue(
- timelineName,
- id,
- "time",
- req.time != null ? req.time.toISOString() : currentTimeString
- );
-
- const { content } = req;
- if (content.type === "text") {
- await setTimelinePostPropertyValue(timelineName, id, "type", "text");
- await setTimelinePostPropertyValue(
- timelineName,
- id,
- "data",
- content.text
- );
- } else {
- await setTimelinePostPropertyValue(timelineName, id, "type", "image");
- await setTimelinePostPropertyValue(
- timelineName,
- id,
- "data",
- content.data
- );
- await setTimelinePostPropertyValue(
- timelineName,
- id,
- "etag",
- await sha1(content.data)
- );
- }
-
- return (await getTimelinePostInfo(
- timelineName,
- id
- )) as HttpTimelinePostInfo;
- }
-
- async deletePost(
- timelineName: string,
- postId: number,
- _token: string
- ): Promise<void> {
- await mockPrepare("timeline.post.delete");
- // TODO: permission check
- await removeTimelinePostProperty(timelineName, postId, "type");
- await removeTimelinePostProperty(timelineName, postId, "data");
- await removeTimelinePostProperty(timelineName, postId, "etag");
- await setTimelinePostPropertyValue(
- timelineName,
- postId,
- "lastUpdated",
- new Date().toISOString()
- );
- }
-}
diff --git a/Timeline/ClientApp/src/app/http/mock/token.ts b/Timeline/ClientApp/src/app/http/mock/token.ts
deleted file mode 100644
index 0a350894..00000000
--- a/Timeline/ClientApp/src/app/http/mock/token.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { AxiosError } from "axios";
-
-import {
- IHttpTokenClient,
- HttpCreateTokenRequest,
- HttpCreateTokenResponse,
- HttpVerifyTokenRequest,
- HttpVerifyTokenResponse,
-} from "../token";
-
-import { mockPrepare } from "./common";
-import { getUser, MockUserNotExistError, checkToken } from "./user";
-
-export class MockHttpTokenClient implements IHttpTokenClient {
- // TODO: Mock bad credentials error.
- async create(req: HttpCreateTokenRequest): Promise<HttpCreateTokenResponse> {
- await mockPrepare("token.create");
- try {
- const user = await getUser(req.username);
- return {
- user,
- token: `token-${req.username}`,
- };
- } catch (e) {
- if (e instanceof MockUserNotExistError) {
- throw {
- isAxiosError: true,
- response: {
- status: 400,
- },
- } as Partial<AxiosError>;
- }
- throw e;
- }
- }
-
- async verify(req: HttpVerifyTokenRequest): Promise<HttpVerifyTokenResponse> {
- await mockPrepare("token.verify");
- try {
- const user = await getUser(checkToken(req.token));
- return {
- user,
- };
- } catch (e) {
- throw {
- isAxiosError: true,
- response: {
- status: 400,
- },
- } as Partial<AxiosError>;
- }
- }
-}
diff --git a/Timeline/ClientApp/src/app/http/mock/user.ts b/Timeline/ClientApp/src/app/http/mock/user.ts
deleted file mode 100644
index 7948da11..00000000
--- a/Timeline/ClientApp/src/app/http/mock/user.ts
+++ /dev/null
@@ -1,139 +0,0 @@
-import axios from "axios";
-
-import { BlobWithEtag, NotModified } from "../common";
-import {
- IHttpUserClient,
- HttpUser,
- HttpUserNotExistError,
- HttpUserPatchRequest,
- HttpChangePasswordRequest,
-} from "../user";
-
-import { mockStorage, sha1, mockPrepare } from "./common";
-import defaultAvatarUrl from "./default-avatar.png";
-
-let _defaultAvatar: BlobWithEtag | undefined = undefined;
-
-async function getDefaultAvatar(): Promise<BlobWithEtag> {
- if (_defaultAvatar == null) {
- const blob = (
- await axios.get<Blob>(defaultAvatarUrl, {
- responseType: "blob",
- })
- ).data;
- const etag = await sha1(blob);
- _defaultAvatar = {
- data: blob,
- etag,
- };
- }
- return _defaultAvatar;
-}
-
-export class MockTokenError extends Error {
- constructor() {
- super("Token bad format.");
- }
-}
-
-export class MockUserNotExistError extends Error {
- constructor() {
- super('Only two user "user" and "admin".');
- }
-}
-
-export function checkUsername(
- username: string
-): asserts username is "user" | "admin" {
- if (!["user", "admin"].includes(username)) throw new MockUserNotExistError();
-}
-
-export function checkToken(token: string): string {
- if (!token.startsWith("token-")) {
- throw new MockTokenError();
- }
- return token.substr(6);
-}
-
-const uniqueIdMap = {
- user: "e4c80127d092d9b2fc19c5e04612d4c0",
- admin: "5640fa45435f9a55077b9f77c42a77bb",
-};
-
-export async function getUser(
- username: "user" | "admin" | string
-): Promise<HttpUser> {
- checkUsername(username);
- const savedNickname = await mockStorage.getItem<string>(
- `user.${username}.nickname`
- );
- return {
- uniqueId: uniqueIdMap[username],
- username: username,
- nickname:
- savedNickname == null || savedNickname === "" ? username : savedNickname,
- administrator: username === "admin",
- };
-}
-
-export class MockHttpUserClient implements IHttpUserClient {
- async get(username: string): Promise<HttpUser> {
- await mockPrepare("user.get");
- return await getUser(username).catch((e) => {
- if (e instanceof MockUserNotExistError) {
- throw new HttpUserNotExistError();
- } else {
- throw e;
- }
- });
- }
-
- async patch(
- username: string,
- req: HttpUserPatchRequest,
- _token: string
- ): Promise<HttpUser> {
- await mockPrepare("user.patch");
- if (req.nickname != null) {
- await mockStorage.setItem(`user.${username}.nickname`, req.nickname);
- }
- return await getUser(username);
- }
-
- getAvatar(username: string): Promise<BlobWithEtag>;
- async getAvatar(
- username: string,
- etag?: string
- ): Promise<BlobWithEtag | NotModified> {
- await mockPrepare("user.avatar.get");
-
- const savedEtag = await mockStorage.getItem(`user.${username}.avatar.etag`);
- if (savedEtag == null) {
- return await getDefaultAvatar();
- }
-
- if (savedEtag === etag) {
- return new NotModified();
- }
-
- return {
- data: await mockStorage.getItem<Blob>(`user.${username}.avatar.data`),
- etag: await mockStorage.getItem<string>(`user.${username}.avatar.etag`),
- };
- }
-
- async putAvatar(username: string, data: Blob, _token: string): Promise<void> {
- await mockPrepare("user.avatar.put");
- const etag = await sha1(data);
- await mockStorage.setItem<Blob>(`user.${username}.avatar.data`, data);
- await mockStorage.setItem<string>(`user.${username}.avatar.etag`, etag);
- }
-
- async changePassword(
- _req: HttpChangePasswordRequest,
- _token: string
- ): Promise<void> {
- await mockPrepare("userop.changepassowrd");
- throw new Error("Not Implemented.");
- }
-}
diff --git a/Timeline/ClientApp/webpack.config.dev.js b/Timeline/ClientApp/webpack.config.dev.js
index fea5a2c5..c88e1aaf 100644
--- a/Timeline/ClientApp/webpack.config.dev.js
+++ b/Timeline/ClientApp/webpack.config.dev.js
@@ -49,12 +49,4 @@ config.devServer
config.plugin("hot").use(webpack.HotModuleReplacementPlugin);
-module.exports = (env) => {
- if (env && env.TIMELINE_USE_MOCK_BACKEND) {
- config
- .entry("index")
- .add(path.join(__dirname, "src/app/http/mock/install.ts"));
- }
-
- return config.toConfig();
-};
+module.exports = config.toConfig();
diff --git a/Timeline/ClientApp/yarn.lock b/Timeline/ClientApp/yarn.lock
index 5dc25b9a..5d5a9e4d 100644
--- a/Timeline/ClientApp/yarn.lock
+++ b/Timeline/ClientApp/yarn.lock
@@ -2437,13 +2437,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/crypto-js@npm:^4.0.1":
- version: 4.0.1
- resolution: "@types/crypto-js@npm:4.0.1"
- checksum: 6b81c4d064931ef697a8896f09e1290cfb2e59420522f7f6ce443646f768d25a767e15763853007eae8abfb298c6853bdb17fb2c894ed7ddf651337912526d7a
- languageName: node
- linkType: hard
-
"@types/emscripten@npm:^1.38.0":
version: 1.39.4
resolution: "@types/emscripten@npm:1.39.4::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Femscripten%2Fdownload%2F%40types%2Femscripten-1.39.4.tgz"
@@ -4850,13 +4843,6 @@ __metadata:
languageName: node
linkType: hard
-"crypto-js@npm:^4.0.0":
- version: 4.0.0
- resolution: "crypto-js@npm:4.0.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcrypto-js%2Fdownload%2Fcrypto-js-4.0.0.tgz"
- checksum: fdd1415b9e4b317f6ac7f055a00495dabea6aa93ab82ccd63866b0a76d2da9587942764816a8a7976cb23b8bbfd7eea23ccb852b3fef218d166cc5db8c008ab3
- languageName: node
- linkType: hard
-
"crypto-random-string@npm:^1.0.0":
version: 1.0.0
resolution: "crypto-random-string@npm:1.0.0::__archiveUrl=https%3A%2F%2Fregistry.npm.taobao.org%2Fcrypto-random-string%2Fdownload%2Fcrypto-random-string-1.0.0.tgz"
@@ -11830,7 +11816,6 @@ fsevents@~2.1.2:
"@babel/preset-typescript": ^7.12.1
"@hot-loader/react-dom": ^17.0.0
"@types/classnames": ^2.2.10
- "@types/crypto-js": ^4.0.1
"@types/lodash": ^4.14.162
"@types/node": ^14.14.5
"@types/react": ^16.9.53
@@ -11854,7 +11839,6 @@ fsevents@~2.1.2:
clsx: ^1.1.1
copy-webpack-plugin: ^6.2.1
core-js: ^3.6.5
- crypto-js: ^4.0.0
css-loader: ^5.0.0
eslint: ^7.12.1
eslint-config-prettier: ^6.14.0