From e0c28055b9faa62233fefc5e2522c37920b1ba32 Mon Sep 17 00:00:00 2001 From: morvanzhou Date: Thu, 30 Nov 2023 01:21:21 +0800 Subject: [PATCH] change to httpx --- src/rethink/dist-local/css/app.09f0dec8.css | 6 -- src/rethink/dist-local/js/app.js | 10 +-- src/rethink/models/files/upload.py | 42 ++++++++---- src/rethink/models/search_engine/engine.py | 9 +++ src/rethink/models/utils.py | 46 ++++++++++--- tests/test_api.py | 7 +- tests/test_models_local.py | 25 +++++-- tests/test_models_utils.py | 73 +++++++++++++++++---- 8 files changed, 165 insertions(+), 53 deletions(-) diff --git a/src/rethink/dist-local/css/app.09f0dec8.css b/src/rethink/dist-local/css/app.09f0dec8.css index de447d2..19bb3fb 100644 --- a/src/rethink/dist-local/css/app.09f0dec8.css +++ b/src/rethink/dist-local/css/app.09f0dec8.css @@ -3175,7 +3175,6 @@ img[data-v-4f42ee16] { .at-search-result[data-v-5527cb1e]:hover { background-color: #eeeeee; } - .result-hl[data-v-5527cb1e] { font-size: 0.8em; color: #666; @@ -3196,15 +3195,12 @@ img[data-v-4f42ee16] { height: 100%; margin: 0 auto; } - .circle-bg[data-v-1bc9a6f2] { background: #FEFEFE; } - .circle[data-v-1bc9a6f2] { height: 50px; } - .dots[data-v-1bc9a6f2] { width: 60px; } @@ -3219,11 +3215,9 @@ img[data-v-4f42ee16] { max-height: 400px; overflow-y: auto; } - .at-search-height-sm[data-v-e789ed84] { max-height: 600px !important; } - .at-search-result-group-label[data-v-e789ed84] { font-weight: 500; font-size: 0.9em; diff --git a/src/rethink/dist-local/js/app.js b/src/rethink/dist-local/js/app.js index c6829c1..f2573f9 100644 --- a/src/rethink/dist-local/js/app.js +++ b/src/rethink/dist-local/js/app.js @@ -188,7 +188,7 @@ \********************************************************************************************************************************************************************************************************************************************************************/ /***/ (function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { - eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n/* harmony import */ var _utils_app_editor_atSearch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/utils/app/editor/atSearch */ \"./src/utils/app/editor/atSearch.ts\");\n/* harmony import */ var _components_app_tools_ResultTitleHeader_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @/components/app/tools/ResultTitleHeader.vue */ \"./src/components/app/tools/ResultTitleHeader.vue\");\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.defineComponent)({\n __name: 'SearchResults',\n props: {\n nid: {\n type: String,\n required: true\n },\n atSearchNodes: {\n type: Array,\n required: true\n }\n },\n setup(__props, {\n expose: __expose\n }) {\n __expose();\n const props = __props;\n // TODO: sanitize\n // textHTML = Lute.Sanitize(textHTML)\n const __returned__ = {\n props,\n get selectAtSearch() {\n return _utils_app_editor_atSearch__WEBPACK_IMPORTED_MODULE_1__.selectAtSearch;\n },\n ResultTitleHeader: _components_app_tools_ResultTitleHeader_vue__WEBPACK_IMPORTED_MODULE_2__[\"default\"]\n };\n Object.defineProperty(__returned__, '__isScriptSetup', {\n enumerable: false,\n value: true\n });\n return __returned__;\n }\n}));\n\n//# sourceURL=webpack://rethink/./src/components/app/editor/cursorSearch/SearchResults.vue?./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js??clonedRuleSet-41.use%5B1%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D"); + eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n/* harmony import */ var _utils_app_editor_atSearch__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/utils/app/editor/atSearch */ \"./src/utils/app/editor/atSearch.ts\");\n/* harmony import */ var _components_app_tools_ResultTitleHeader_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @/components/app/tools/ResultTitleHeader.vue */ \"./src/components/app/tools/ResultTitleHeader.vue\");\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.defineComponent)({\n __name: 'SearchResults',\n props: {\n nid: {\n type: String,\n required: true\n },\n atSearchNodes: {\n type: Array,\n required: true\n }\n },\n setup(__props, {\n expose: __expose\n }) {\n __expose();\n const props = __props;\n const __returned__ = {\n props,\n get selectAtSearch() {\n return _utils_app_editor_atSearch__WEBPACK_IMPORTED_MODULE_1__.selectAtSearch;\n },\n ResultTitleHeader: _components_app_tools_ResultTitleHeader_vue__WEBPACK_IMPORTED_MODULE_2__[\"default\"]\n };\n Object.defineProperty(__returned__, '__isScriptSetup', {\n enumerable: false,\n value: true\n });\n return __returned__;\n }\n}));\n\n//# sourceURL=webpack://rethink/./src/components/app/editor/cursorSearch/SearchResults.vue?./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js??clonedRuleSet-41.use%5B1%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D"); /***/ }), @@ -944,7 +944,7 @@ \*******************************************************************************************************************************************************************************************************************************************************************************************************************************/ /***/ (function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { - eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ render: function() { return /* binding */ render; }\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n\nconst _withScopeId = n => ((0,vue__WEBPACK_IMPORTED_MODULE_0__.pushScopeId)(\"data-v-1bc9a6f2\"), n = n(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.popScopeId)(), n);\nconst _hoisted_1 = [\"src\"];\nconst _hoisted_2 = [\"src\"];\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return $setup.props.loading ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: 0,\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)([\"loading\", $setup.bgClass])\n }, [$setup.props.circle ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"img\", {\n key: 0,\n src: $setup.LoadingGIF,\n alt: \"loading\",\n class: \"circle\"\n }, null, 8 /* PROPS */, _hoisted_1)) : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"img\", {\n key: 1,\n src: $setup.LoadingDotsGIF,\n alt: \"loading\",\n class: \"dots\"\n }, null, 8 /* PROPS */, _hoisted_2))], 2 /* CLASS */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true);\n}\n\n//# sourceURL=webpack://rethink/./src/components/WaitLoading.vue?./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js??clonedRuleSet-41.use%5B1%5D!./node_modules/vue-loader/dist/templateLoader.js??ruleSet%5B1%5D.rules%5B4%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D"); + eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ render: function() { return /* binding */ render; }\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n\nconst _withScopeId = n => ((0,vue__WEBPACK_IMPORTED_MODULE_0__.pushScopeId)(\"data-v-1bc9a6f2\"), n = n(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.popScopeId)(), n);\nconst _hoisted_1 = [\"src\"];\nconst _hoisted_2 = [\"src\"];\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return $setup.props.loading ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: 0,\n class: (0,vue__WEBPACK_IMPORTED_MODULE_0__.normalizeClass)([$setup.bgClass, \"loading\"])\n }, [$setup.props.circle ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"img\", {\n key: 0,\n src: $setup.LoadingGIF,\n alt: \"loading\",\n class: \"circle\"\n }, null, 8 /* PROPS */, _hoisted_1)) : ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"img\", {\n key: 1,\n src: $setup.LoadingDotsGIF,\n alt: \"loading\",\n class: \"dots\"\n }, null, 8 /* PROPS */, _hoisted_2))], 2 /* CLASS */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true);\n}\n\n//# sourceURL=webpack://rethink/./src/components/WaitLoading.vue?./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js??clonedRuleSet-41.use%5B1%5D!./node_modules/vue-loader/dist/templateLoader.js??ruleSet%5B1%5D.rules%5B4%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D"); /***/ }), @@ -1268,7 +1268,7 @@ \******************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ /***/ (function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { - eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ render: function() { return /* binding */ render; }\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n\nconst _withScopeId = n => ((0,vue__WEBPACK_IMPORTED_MODULE_0__.pushScopeId)(\"data-v-19c64c31\"), n = n(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.popScopeId)(), n);\nconst _hoisted_1 = [\"onClick\"];\nconst _hoisted_2 = {\n class: \"node-time\"\n};\nconst _hoisted_3 = [\"innerHTML\"];\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"no-search-result\"\n }, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.mLang.get('noSearchResult')), 513 /* TEXT, NEED_PATCH */), [[vue__WEBPACK_IMPORTED_MODULE_0__.vShow, $setup.props.searchResult.nodes.length === 0]]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"search-results\",\n onScroll: _cache[0] || (_cache[0] = $event => $setup.emit('searchMore', $event))\n }, [((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($props.searchResult.nodes, result => {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: result.id,\n class: \"search-result hover-node-bg\",\n onClick: $event => $setup.emit('selectResult', result.id)\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)($setup[\"ResultTitleHeader\"], {\n title: result.titleHighlight\n }, null, 8 /* PROPS */, [\"title\"]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", _hoisted_2, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.utc2local(result.modifiedAt)), 1 /* TEXT */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"node-hl\",\n innerHTML: result.bodyHighlights[0]\n }, null, 8 /* PROPS */, _hoisted_3)], 8 /* PROPS */, _hoisted_1);\n }), 128 /* KEYED_FRAGMENT */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)($setup[\"WaitLoading\"], {\n loading: $props.isSearching,\n circle: false,\n style: {\n \"border\": \"none\"\n }\n }, null, 8 /* PROPS */, [\"loading\"])], 544 /* HYDRATE_EVENTS, NEED_PATCH */), [[vue__WEBPACK_IMPORTED_MODULE_0__.vShow, $setup.props.searchResult.nodes.length > 0]])], 64 /* STABLE_FRAGMENT */);\n}\n\n//# sourceURL=webpack://rethink/./src/components/app/nav/top/search/SMSearchResults.vue?./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js??clonedRuleSet-41.use%5B1%5D!./node_modules/vue-loader/dist/templateLoader.js??ruleSet%5B1%5D.rules%5B4%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D"); + eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ render: function() { return /* binding */ render; }\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n\nconst _withScopeId = n => ((0,vue__WEBPACK_IMPORTED_MODULE_0__.pushScopeId)(\"data-v-19c64c31\"), n = n(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.popScopeId)(), n);\nconst _hoisted_1 = [\"onClick\"];\nconst _hoisted_2 = {\n class: \"node-time\"\n};\nconst _hoisted_3 = [\"innerHTML\"];\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"no-search-result\"\n }, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.mLang.get('noSearchResult')), 513 /* TEXT, NEED_PATCH */), [[vue__WEBPACK_IMPORTED_MODULE_0__.vShow, $setup.props.searchResult.nodes.length === 0]]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"search-results\",\n onScroll: _cache[0] || (_cache[0] = $event => $setup.emit('searchMore', $event))\n }, [((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($props.searchResult.nodes, result => {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: result.id,\n class: \"search-result hover-node-bg\",\n onClick: $event => $setup.emit('selectResult', result.id)\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)($setup[\"ResultTitleHeader\"], {\n title: result.titleHighlight\n }, null, 8 /* PROPS */, [\"title\"]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", _hoisted_2, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.utc2local(result.modifiedAt)), 1 /* TEXT */), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"node-hl\",\n innerHTML: result.bodyHighlights[0]\n }, null, 8 /* PROPS */, _hoisted_3)], 8 /* PROPS */, _hoisted_1);\n }), 128 /* KEYED_FRAGMENT */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)($setup[\"WaitLoading\"], {\n circle: false,\n loading: $props.isSearching,\n style: {\n \"border\": \"none\"\n }\n }, null, 8 /* PROPS */, [\"loading\"])], 544 /* HYDRATE_EVENTS, NEED_PATCH */), [[vue__WEBPACK_IMPORTED_MODULE_0__.vShow, $setup.props.searchResult.nodes.length > 0]])], 64 /* STABLE_FRAGMENT */);\n}\n\n//# sourceURL=webpack://rethink/./src/components/app/nav/top/search/SMSearchResults.vue?./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js??clonedRuleSet-41.use%5B1%5D!./node_modules/vue-loader/dist/templateLoader.js??ruleSet%5B1%5D.rules%5B4%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D"); /***/ }), @@ -1280,7 +1280,7 @@ \*************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ /***/ (function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { - eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ render: function() { return /* binding */ render; }\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n\nconst _withScopeId = n => ((0,vue__WEBPACK_IMPORTED_MODULE_0__.pushScopeId)(\"data-v-48038053\"), n = n(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.popScopeId)(), n);\nconst _hoisted_1 = {\n class: \"search-wrapper\"\n};\nconst _hoisted_2 = [\"src\"];\nconst _hoisted_3 = [\"placeholder\"];\nconst _hoisted_4 = [\"onClick\"];\nconst _hoisted_5 = [\"innerHTML\"];\nconst _hoisted_6 = {\n key: 1,\n class: \"search-results no-result\"\n};\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", _hoisted_1, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"img\", {\n src: $setup.SearchIcon,\n alt: \"search\",\n class: \"search-icon\"\n }, null, 8 /* PROPS */, _hoisted_2), (0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"input\", {\n \"onUpdate:modelValue\": _cache[0] || (_cache[0] = $event => $setup.searchVal = $event),\n placeholder: $setup.mLang.get('searchBarPlaceholder'),\n class: \"search-input\",\n type: \"search\",\n onKeydown: [_cache[1] || (_cache[1] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withKeys)($event => $setup.searchVal = '', [\"esc\"])), _cache[2] || (_cache[2] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withKeys)(\n //@ts-ignore\n (...args) => $setup.entrySearch && $setup.entrySearch(...args), [\"enter\"])), _cache[3] || (_cache[3] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withKeys)((0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)(\n //@ts-ignore\n (...args) => $setup.keyArrowUpDown && $setup.keyArrowUpDown(...args), [\"prevent\", \"stop\"]), [\"up\"])), _cache[4] || (_cache[4] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withKeys)((0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)(\n //@ts-ignore\n (...args) => $setup.keyArrowUpDown && $setup.keyArrowUpDown(...args), [\"prevent\", \"stop\"]), [\"down\"])), _cache[5] || (_cache[5] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withKeys)((0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)(\n //@ts-ignore\n (...args) => $setup.keyTab && $setup.keyTab(...args), [\"prevent\", \"stop\"]), [\"tab\"]))]\n }, null, 40 /* PROPS, HYDRATE_EVENTS */, _hoisted_3), [[vue__WEBPACK_IMPORTED_MODULE_0__.vModelText, $setup.searchVal, void 0, {\n trim: true\n }]])]), $setup.searched && $setup.searchResult.nodes.length > 0 ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: 0,\n class: \"search-results\",\n onScroll: _cache[6] || (_cache[6] =\n //@ts-ignore\n (...args) => $setup.searchMore && $setup.searchMore(...args))\n }, [((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($setup.searchResult.nodes, result => {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: result.id,\n class: \"search-result hover-node-bg\",\n onClick: $event => $setup.selectResult(result.id)\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)($setup[\"ResultTitleHeader\"], {\n title: result.titleHighlight\n }, null, 8 /* PROPS */, [\"title\"]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"node-hl\",\n innerHTML: result.bodyHighlights[0]\n }, null, 8 /* PROPS */, _hoisted_5)], 8 /* PROPS */, _hoisted_4);\n }), 128 /* KEYED_FRAGMENT */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)($setup[\"WaitLoading\"], {\n loading: $setup.isSearching,\n circle: false,\n style: {\n \"border\": \"none\"\n }\n }, null, 8 /* PROPS */, [\"loading\"])], 32 /* HYDRATE_EVENTS */)) : $setup.searched && $setup.searchResult.nodes.length === 0 ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_6, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.mLang.get(\"noSearchResult\")), 1 /* TEXT */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true)], 64 /* STABLE_FRAGMENT */);\n}\n\n//# sourceURL=webpack://rethink/./src/components/app/nav/top/search/SearchTool.vue?./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js??clonedRuleSet-41.use%5B1%5D!./node_modules/vue-loader/dist/templateLoader.js??ruleSet%5B1%5D.rules%5B4%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D"); + eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ render: function() { return /* binding */ render; }\n/* harmony export */ });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n\nconst _withScopeId = n => ((0,vue__WEBPACK_IMPORTED_MODULE_0__.pushScopeId)(\"data-v-48038053\"), n = n(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.popScopeId)(), n);\nconst _hoisted_1 = {\n class: \"search-wrapper\"\n};\nconst _hoisted_2 = [\"src\"];\nconst _hoisted_3 = [\"placeholder\"];\nconst _hoisted_4 = [\"onClick\"];\nconst _hoisted_5 = [\"innerHTML\"];\nconst _hoisted_6 = {\n key: 1,\n class: \"search-results no-result\"\n};\nfunction render(_ctx, _cache, $props, $setup, $data, $options) {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", _hoisted_1, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"img\", {\n src: $setup.SearchIcon,\n alt: \"search\",\n class: \"search-icon\"\n }, null, 8 /* PROPS */, _hoisted_2), (0,vue__WEBPACK_IMPORTED_MODULE_0__.withDirectives)((0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"input\", {\n \"onUpdate:modelValue\": _cache[0] || (_cache[0] = $event => $setup.searchVal = $event),\n placeholder: $setup.mLang.get('searchBarPlaceholder'),\n class: \"search-input\",\n type: \"search\",\n onKeydown: [_cache[1] || (_cache[1] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withKeys)($event => $setup.searchVal = '', [\"esc\"])), _cache[2] || (_cache[2] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withKeys)(\n //@ts-ignore\n (...args) => $setup.entrySearch && $setup.entrySearch(...args), [\"enter\"])), _cache[3] || (_cache[3] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withKeys)((0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)(\n //@ts-ignore\n (...args) => $setup.keyArrowUpDown && $setup.keyArrowUpDown(...args), [\"prevent\", \"stop\"]), [\"up\"])), _cache[4] || (_cache[4] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withKeys)((0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)(\n //@ts-ignore\n (...args) => $setup.keyArrowUpDown && $setup.keyArrowUpDown(...args), [\"prevent\", \"stop\"]), [\"down\"])), _cache[5] || (_cache[5] = (0,vue__WEBPACK_IMPORTED_MODULE_0__.withKeys)((0,vue__WEBPACK_IMPORTED_MODULE_0__.withModifiers)(\n //@ts-ignore\n (...args) => $setup.keyTab && $setup.keyTab(...args), [\"prevent\", \"stop\"]), [\"tab\"]))]\n }, null, 40 /* PROPS, HYDRATE_EVENTS */, _hoisted_3), [[vue__WEBPACK_IMPORTED_MODULE_0__.vModelText, $setup.searchVal, void 0, {\n trim: true\n }]])]), $setup.searched && $setup.searchResult.nodes.length > 0 ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: 0,\n class: \"search-results\",\n onScroll: _cache[6] || (_cache[6] =\n //@ts-ignore\n (...args) => $setup.searchMore && $setup.searchMore(...args))\n }, [((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.renderList)($setup.searchResult.nodes, result => {\n return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", {\n key: result.id,\n class: \"search-result hover-node-bg\",\n onClick: $event => $setup.selectResult(result.id)\n }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)($setup[\"ResultTitleHeader\"], {\n title: result.titleHighlight\n }, null, 8 /* PROPS */, [\"title\"]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)(\"div\", {\n class: \"node-hl\",\n innerHTML: result.bodyHighlights[0]\n }, null, 8 /* PROPS */, _hoisted_5)], 8 /* PROPS */, _hoisted_4);\n }), 128 /* KEYED_FRAGMENT */)), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)($setup[\"WaitLoading\"], {\n circle: false,\n loading: $setup.isSearching,\n style: {\n \"border\": \"none\"\n }\n }, null, 8 /* PROPS */, [\"loading\"])], 32 /* HYDRATE_EVENTS */)) : $setup.searched && $setup.searchResult.nodes.length === 0 ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(\"div\", _hoisted_6, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($setup.mLang.get(\"noSearchResult\")), 1 /* TEXT */)) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)(\"v-if\", true)], 64 /* STABLE_FRAGMENT */);\n}\n\n//# sourceURL=webpack://rethink/./src/components/app/nav/top/search/SearchTool.vue?./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js??clonedRuleSet-41.use%5B1%5D!./node_modules/vue-loader/dist/templateLoader.js??ruleSet%5B1%5D.rules%5B4%5D!./node_modules/vue-loader/dist/index.js??ruleSet%5B0%5D.use%5B0%5D"); /***/ }), @@ -1928,7 +1928,7 @@ \****************************************/ /***/ (function (__unused_webpack_module, __webpack_exports__, __webpack_require__) { - eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vditor__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vditor */ \"./node_modules/vditor/dist/index.min.js\");\n/* harmony import */ var vditor__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(vditor__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _assets_css_vditor_vditor_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/assets/css/vditor/vditor.css */ \"./src/assets/css/vditor/vditor.css\");\n/* harmony import */ var vue_router__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! vue-router */ \"./node_modules/vue-router/dist/vue-router.mjs\");\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n/* harmony import */ var _utils_app_node__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @/utils/app/node */ \"./src/utils/app/node.ts\");\n/* harmony import */ var _router__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @/router */ \"./src/router/index.ts\");\n/* harmony import */ var _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @/utils/multiLang */ \"./src/utils/multiLang.ts\");\n/* harmony import */ var _utils_configs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @/utils/configs */ \"./src/utils/configs.ts\");\n/* harmony import */ var _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @/utils/app/editor/refs */ \"./src/utils/app/editor/refs.ts\");\n/* harmony import */ var _utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @/utils/app/editor/utils */ \"./src/utils/app/editor/utils.ts\");\n/* harmony import */ var _utils_app_editor_atTag__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @/utils/app/editor/atTag */ \"./src/utils/app/editor/atTag.ts\");\n/* harmony import */ var _utils_mq__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @/utils/mq */ \"./src/utils/mq.ts\");\n/* harmony import */ var _utils_app_editor_keyEvent__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @/utils/app/editor/keyEvent */ \"./src/utils/app/editor/keyEvent.ts\");\n/* harmony import */ var _utils_account_token__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @/utils/account/token */ \"./src/utils/account/token.ts\");\n/* harmony import */ var _utils_meta__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @/utils/meta */ \"./src/utils/meta.ts\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst ready = (0,vue__WEBPACK_IMPORTED_MODULE_2__.ref)(false);\nasync function updateTextEl() {\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value || !_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) return;\n (0,_utils_app_editor_atTag__WEBPACK_IMPORTED_MODULE_9__.replaceATag)();\n}\nconst syncTimeString = utcDateStr => {\n // var utcDate = \"2022-03-19T20:15:50.000Z\";\n const utcDate = new Date(utcDateStr);\n const now = new Date();\n const year = utcDate.getFullYear();\n const month = `0${utcDate.getMonth() + 1}`.slice(-2);\n const day = `0${utcDate.getDate()}`.slice(-2);\n const hour = `0${utcDate.getHours()}`.slice(-2);\n const minute = `0${utcDate.getMinutes()}`.slice(-2);\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const dayDelta = (today.getTime() - utcDate.getTime()) / 1000 / 60 / 60 / 24;\n if (dayDelta >= 365) {\n // >= 1 year\n return `${year}-${month}-${day}`;\n } else if (dayDelta >= 0) {\n // >= 1 day\n return `${month}-${day}`;\n } else {\n // today\n return `${hour}:${minute}`;\n }\n};\nfunction updateSyncStatue() {\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editorSyncStatus.value = _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].get(\"editorSyncStatusSaved\");\n // 5 seconds later, update the editorSyncStatus\n setInterval(() => {\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) return;\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editorSyncStatus.value = _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].get(\"editorSyncStatusLastSaved\") + syncTimeString(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.modifiedAt);\n }, 5000);\n}\nfunction createEditor(id) {\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) return;\n const text = (0,_utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__.stripWhitespace)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.md);\n let height, toolbar;\n if ((0,_utils_mq__WEBPACK_IMPORTED_MODULE_10__.getMQ)() === \"sm\") {\n height = \"calc(100% - 180px)\";\n toolbar = [\"|\", \"undo\", \"redo\", \"|\", \"upload\"];\n } else {\n height = \"calc(100% - 60px)\";\n toolbar = [\"|\", \"outline\", \"|\", \"undo\", \"redo\", \"|\", \"code\", \"table\", \"upload\", \"|\", \"fullscreen\"];\n }\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value = new (vditor__WEBPACK_IMPORTED_MODULE_0___default())(id, {\n // minHeight: 200,\n icon: \"material\",\n height: height,\n width: \"98vw\",\n lang: _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].getGlobalLang() === \"zh\" ? \"zh_CN\" : \"en_US\",\n mode: \"wysiwyg\",\n placeholder: _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].get(\"editorContentPlaceholder\"),\n outline: {\n enable: false,\n position: \"left\"\n },\n tab: \" \",\n // comment: {enable: true,},\n toolbar: [{\n name: _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].get(\"goBackIcon\"),\n tipPosition: \"nw\",\n tip: _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].get(\"goBackIcon\"),\n icon: '\\n' + ' \\n' + ' \\n' + '',\n click: () => _router__WEBPACK_IMPORTED_MODULE_4__[\"default\"].go(-1)\n }, ...toolbar],\n toolbarConfig: {\n hide: false,\n pin: true\n },\n undoDelay: 500,\n upload: {\n accept: 'image/*',\n max: 10 * 1024 * 1024,\n headers: {\n token: (0,_utils_account_token__WEBPACK_IMPORTED_MODULE_12__.getToken)()\n },\n multiple: false,\n url: `${_utils_configs__WEBPACK_IMPORTED_MODULE_6__[\"default\"].apiUrl}/api/files/imageUploadVditor`,\n linkToImgUrl: `${_utils_configs__WEBPACK_IMPORTED_MODULE_6__[\"default\"].apiUrl}/api/files/imageFetchVditor`,\n filename(name) {\n // eslint-disable-next-line no-useless-escape\n return name.replace(/[^(a-zA-Z0-9\\u4e00-\\u9fa5\\.)]/g, '').\n // eslint-disable-next-line no-useless-escape\n replace(/[\\?\\\\/:|<>\\*\\[\\]\\(\\)\\$%\\{\\}@~]/g, '').replace('/\\\\s/g', '');\n }\n },\n preview: {\n markdown: {\n sanitize: true,\n // gfmAutoLink: true,\n mark: true,\n codeBlockPreview: true\n // linkPrefix: \"https://\",\n },\n\n hljs: {\n enable: true,\n lineNumber: true,\n defaultLang: \"python\",\n // style: \"github\",\n style: \"dracula\"\n }\n },\n cache: {\n enable: true,\n id: _utils_configs__WEBPACK_IMPORTED_MODULE_6__[\"default\"].mdCacheId,\n after: async md => {\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) return;\n md = (0,_utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__.stripWhitespace)(md.trim());\n // skip if not changed\n const oldMd = (0,_utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__.stripWhitespace)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.md.trim());\n if (oldMd === md) return;\n debugger;\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value = await (0,_utils_app_node__WEBPACK_IMPORTED_MODULE_3__.updateNode)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.id, md);\n await updateTextEl();\n updateSyncStatue();\n }\n },\n after: async () => {\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value || !_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) return;\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.setValue(text);\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.md = _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.getValue();\n await updateTextEl();\n const el = _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.vditor.element;\n el.addEventListener(\"mouseup\", _utils_app_editor_atTag__WEBPACK_IMPORTED_MODULE_9__.moveCursorOutATag);\n el.addEventListener(\"keyup\", _utils_app_editor_keyEvent__WEBPACK_IMPORTED_MODULE_11__.onKeyup);\n // check @ input\n el.addEventListener(\"beforeinput\", _utils_app_editor_keyEvent__WEBPACK_IMPORTED_MODULE_11__.beforeInput);\n if ((0,_utils_mq__WEBPACK_IMPORTED_MODULE_10__.getMQ)() === \"sm\") {\n el.blur();\n }\n ready.value = true;\n }\n });\n}\nfunction useEditor(id, nid) {\n (0,vue__WEBPACK_IMPORTED_MODULE_2__.onBeforeMount)(() => {\n ready.value = false;\n });\n (0,vue__WEBPACK_IMPORTED_MODULE_2__.onMounted)(async () => {\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value = await (0,_utils_app_node__WEBPACK_IMPORTED_MODULE_3__.getNode)(nid);\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) {\n _router__WEBPACK_IMPORTED_MODULE_4__[\"default\"].go(-1);\n return;\n }\n createEditor(id);\n (0,_utils_meta__WEBPACK_IMPORTED_MODULE_13__[\"default\"])(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.title + \" - Rethink\", _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.title, _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.snippet);\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editorSyncStatus.value = _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].get(\"editorSyncStatusLastSaved\") + syncTimeString(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.modifiedAt);\n });\n (0,vue_router__WEBPACK_IMPORTED_MODULE_14__.onBeforeRouteUpdate)(async (to, from, next) => {\n if (to.params.id === from.params.id) return next();\n // for the case that the node is changed\n // hide the at-search-result\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.isAtSearch.value = false;\n // reset the linedNodeExpanded\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.linedNodeExpanded.value.forEach((_, i) => {\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.linedNodeExpanded.value[i] = false;\n });\n if (typeof to.params.id !== \"string\") return next(false);\n // get new node\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value = await (0,_utils_app_node__WEBPACK_IMPORTED_MODULE_3__.getNode)(to.params.id);\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) {\n _router__WEBPACK_IMPORTED_MODULE_4__[\"default\"].go(-1);\n return next(false);\n }\n // reset editor\n if (_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value) {\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.setValue((0,_utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__.stripWhitespace)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.md));\n const e = _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.vditor.element.querySelector(\".vditor-reset\");\n if (e) {\n e.scrollTop = 0;\n }\n // change HTML document\n (0,_utils_meta__WEBPACK_IMPORTED_MODULE_13__[\"default\"])(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.title + \" - Rethink\", _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.title, _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.snippet);\n await updateTextEl();\n }\n return next();\n });\n (0,vue__WEBPACK_IMPORTED_MODULE_2__.onUnmounted)(async () => {\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value) return;\n if (_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) {\n const md = (0,_utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__.stripWhitespace)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.getValue().trim());\n // skip if not changed\n const oldMd = (0,_utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__.stripWhitespace)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.md.trim());\n if (oldMd !== md) {\n await (0,_utils_app_node__WEBPACK_IMPORTED_MODULE_3__.updateNode)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.id, md);\n }\n }\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.vditor.element.removeEventListener(\"selectionchange\", _utils_app_editor_atTag__WEBPACK_IMPORTED_MODULE_9__.moveCursorOutATag);\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.vditor.element.removeEventListener(\"keyup\", _utils_app_editor_keyEvent__WEBPACK_IMPORTED_MODULE_11__.onKeyup);\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.vditor.element.removeEventListener(\"beforeinput\", _utils_app_editor_keyEvent__WEBPACK_IMPORTED_MODULE_11__.beforeInput);\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.destroy();\n });\n return {\n node: _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node,\n ready\n };\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (useEditor);\n\n//# sourceURL=webpack://rethink/./src/utils/app/editor/editor.ts?"); + eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vditor__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vditor */ \"./node_modules/vditor/dist/index.min.js\");\n/* harmony import */ var vditor__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(vditor__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _assets_css_vditor_vditor_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/assets/css/vditor/vditor.css */ \"./src/assets/css/vditor/vditor.css\");\n/* harmony import */ var vue_router__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! vue-router */ \"./node_modules/vue-router/dist/vue-router.mjs\");\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm-bundler.js\");\n/* harmony import */ var _utils_app_node__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @/utils/app/node */ \"./src/utils/app/node.ts\");\n/* harmony import */ var _router__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @/router */ \"./src/router/index.ts\");\n/* harmony import */ var _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @/utils/multiLang */ \"./src/utils/multiLang.ts\");\n/* harmony import */ var _utils_configs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @/utils/configs */ \"./src/utils/configs.ts\");\n/* harmony import */ var _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @/utils/app/editor/refs */ \"./src/utils/app/editor/refs.ts\");\n/* harmony import */ var _utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @/utils/app/editor/utils */ \"./src/utils/app/editor/utils.ts\");\n/* harmony import */ var _utils_app_editor_atTag__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @/utils/app/editor/atTag */ \"./src/utils/app/editor/atTag.ts\");\n/* harmony import */ var _utils_mq__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @/utils/mq */ \"./src/utils/mq.ts\");\n/* harmony import */ var _utils_app_editor_keyEvent__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @/utils/app/editor/keyEvent */ \"./src/utils/app/editor/keyEvent.ts\");\n/* harmony import */ var _utils_account_token__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @/utils/account/token */ \"./src/utils/account/token.ts\");\n/* harmony import */ var _utils_meta__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @/utils/meta */ \"./src/utils/meta.ts\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst ready = (0,vue__WEBPACK_IMPORTED_MODULE_2__.ref)(false);\nasync function updateTextEl() {\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value || !_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) return;\n (0,_utils_app_editor_atTag__WEBPACK_IMPORTED_MODULE_9__.replaceATag)();\n}\nconst syncTimeString = utcDateStr => {\n // var utcDate = \"2022-03-19T20:15:50.000Z\";\n const utcDate = new Date(utcDateStr);\n const now = new Date();\n const year = utcDate.getFullYear();\n const month = `0${utcDate.getMonth() + 1}`.slice(-2);\n const day = `0${utcDate.getDate()}`.slice(-2);\n const hour = `0${utcDate.getHours()}`.slice(-2);\n const minute = `0${utcDate.getMinutes()}`.slice(-2);\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const dayDelta = (today.getTime() - utcDate.getTime()) / 1000 / 60 / 60 / 24;\n if (dayDelta >= 365) {\n // >= 1 year\n return `${year}-${month}-${day}`;\n } else if (dayDelta >= 0) {\n // >= 1 day\n return `${month}-${day}`;\n } else {\n // today\n return `${hour}:${minute}`;\n }\n};\nfunction updateSyncStatue() {\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editorSyncStatus.value = _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].get(\"editorSyncStatusSaved\");\n // 5 seconds later, update the editorSyncStatus\n setInterval(() => {\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) return;\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editorSyncStatus.value = _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].get(\"editorSyncStatusLastSaved\") + syncTimeString(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.modifiedAt);\n }, 5000);\n}\nfunction createEditor(id) {\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) return;\n const text = (0,_utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__.stripWhitespace)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.md);\n let height, toolbar;\n if ((0,_utils_mq__WEBPACK_IMPORTED_MODULE_10__.getMQ)() === \"sm\") {\n height = \"calc(100% - 180px)\";\n toolbar = [\"|\", \"undo\", \"redo\", \"|\", \"upload\"];\n } else {\n height = \"calc(100% - 60px)\";\n toolbar = [\"|\", \"outline\", \"|\", \"undo\", \"redo\", \"|\", \"code\", \"table\", \"upload\", \"|\", \"fullscreen\"];\n }\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value = new (vditor__WEBPACK_IMPORTED_MODULE_0___default())(id, {\n // minHeight: 200,\n icon: \"material\",\n height: height,\n width: \"98vw\",\n lang: _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].getGlobalLang() === \"zh\" ? \"zh_CN\" : \"en_US\",\n mode: \"wysiwyg\",\n placeholder: _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].get(\"editorContentPlaceholder\"),\n outline: {\n enable: false,\n position: \"left\"\n },\n tab: \" \",\n // comment: {enable: true,},\n toolbar: [{\n name: _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].get(\"goBackIcon\"),\n tipPosition: \"nw\",\n tip: _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].get(\"goBackIcon\"),\n icon: '\\n' + ' \\n' + ' \\n' + '',\n click: () => _router__WEBPACK_IMPORTED_MODULE_4__[\"default\"].go(-1)\n }, ...toolbar],\n toolbarConfig: {\n hide: false,\n pin: true\n },\n undoDelay: 500,\n upload: {\n accept: 'image/*',\n max: 10 * 1024 * 1024,\n headers: {\n token: (0,_utils_account_token__WEBPACK_IMPORTED_MODULE_12__.getToken)()\n },\n multiple: false,\n url: `${_utils_configs__WEBPACK_IMPORTED_MODULE_6__[\"default\"].apiUrl}/api/files/imageUploadVditor`,\n linkToImgUrl: `${_utils_configs__WEBPACK_IMPORTED_MODULE_6__[\"default\"].apiUrl}/api/files/imageFetchVditor`,\n filename(name) {\n // eslint-disable-next-line no-useless-escape\n return name.replace(/[^(a-zA-Z0-9\\u4e00-\\u9fa5\\.)]/g, '').\n // eslint-disable-next-line no-useless-escape\n replace(/[\\?\\\\/:|<>\\*\\[\\]\\(\\)\\$%\\{\\}@~]/g, '').replace('/\\\\s/g', '');\n }\n },\n preview: {\n markdown: {\n sanitize: true,\n // gfmAutoLink: true,\n mark: true,\n codeBlockPreview: true\n // linkPrefix: \"https://\",\n },\n\n hljs: {\n enable: true,\n lineNumber: true,\n defaultLang: \"python\",\n // style: \"github\",\n style: \"dracula\"\n }\n },\n cache: {\n enable: true,\n id: _utils_configs__WEBPACK_IMPORTED_MODULE_6__[\"default\"].mdCacheId,\n after: async md => {\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) return;\n md = (0,_utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__.stripWhitespace)(md.trim());\n // skip if not changed\n const oldMd = (0,_utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__.stripWhitespace)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.md.trim());\n if (oldMd === md) return;\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value = await (0,_utils_app_node__WEBPACK_IMPORTED_MODULE_3__.updateNode)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.id, md);\n await updateTextEl();\n updateSyncStatue();\n }\n },\n after: async () => {\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value || !_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) return;\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.setValue(text);\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.md = _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.getValue();\n await updateTextEl();\n const el = _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.vditor.element;\n el.addEventListener(\"mouseup\", _utils_app_editor_atTag__WEBPACK_IMPORTED_MODULE_9__.moveCursorOutATag);\n el.addEventListener(\"keyup\", _utils_app_editor_keyEvent__WEBPACK_IMPORTED_MODULE_11__.onKeyup);\n // check @ input\n el.addEventListener(\"beforeinput\", _utils_app_editor_keyEvent__WEBPACK_IMPORTED_MODULE_11__.beforeInput);\n if ((0,_utils_mq__WEBPACK_IMPORTED_MODULE_10__.getMQ)() === \"sm\") {\n el.blur();\n }\n ready.value = true;\n }\n });\n}\nfunction useEditor(id, nid) {\n (0,vue__WEBPACK_IMPORTED_MODULE_2__.onBeforeMount)(() => {\n ready.value = false;\n });\n (0,vue__WEBPACK_IMPORTED_MODULE_2__.onMounted)(async () => {\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value = await (0,_utils_app_node__WEBPACK_IMPORTED_MODULE_3__.getNode)(nid);\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) {\n _router__WEBPACK_IMPORTED_MODULE_4__[\"default\"].go(-1);\n return;\n }\n createEditor(id);\n (0,_utils_meta__WEBPACK_IMPORTED_MODULE_13__[\"default\"])(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.title + \" - Rethink\", _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.title, _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.snippet);\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editorSyncStatus.value = _utils_multiLang__WEBPACK_IMPORTED_MODULE_5__[\"default\"].get(\"editorSyncStatusLastSaved\") + syncTimeString(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.modifiedAt);\n });\n (0,vue_router__WEBPACK_IMPORTED_MODULE_14__.onBeforeRouteUpdate)(async (to, from, next) => {\n if (to.params.id === from.params.id) return next();\n // for the case that the node is changed\n // hide the at-search-result\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.isAtSearch.value = false;\n // reset the linedNodeExpanded\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.linedNodeExpanded.value.forEach((_, i) => {\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.linedNodeExpanded.value[i] = false;\n });\n if (typeof to.params.id !== \"string\") return next(false);\n // get new node\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value = await (0,_utils_app_node__WEBPACK_IMPORTED_MODULE_3__.getNode)(to.params.id);\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) {\n _router__WEBPACK_IMPORTED_MODULE_4__[\"default\"].go(-1);\n return next(false);\n }\n // reset editor\n if (_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value) {\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.setValue((0,_utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__.stripWhitespace)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.md));\n const e = _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.vditor.element.querySelector(\".vditor-reset\");\n if (e) {\n e.scrollTop = 0;\n }\n // change HTML document\n (0,_utils_meta__WEBPACK_IMPORTED_MODULE_13__[\"default\"])(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.title + \" - Rethink\", _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.title, _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.snippet);\n await updateTextEl();\n }\n return next();\n });\n (0,vue__WEBPACK_IMPORTED_MODULE_2__.onUnmounted)(async () => {\n if (!_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value) return;\n if (_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value) {\n const md = (0,_utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__.stripWhitespace)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.getValue().trim());\n // skip if not changed\n const oldMd = (0,_utils_app_editor_utils__WEBPACK_IMPORTED_MODULE_8__.stripWhitespace)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.md.trim());\n if (oldMd !== md) {\n await (0,_utils_app_node__WEBPACK_IMPORTED_MODULE_3__.updateNode)(_utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node.value.id, md);\n }\n }\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.vditor.element.removeEventListener(\"selectionchange\", _utils_app_editor_atTag__WEBPACK_IMPORTED_MODULE_9__.moveCursorOutATag);\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.vditor.element.removeEventListener(\"keyup\", _utils_app_editor_keyEvent__WEBPACK_IMPORTED_MODULE_11__.onKeyup);\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.vditor.element.removeEventListener(\"beforeinput\", _utils_app_editor_keyEvent__WEBPACK_IMPORTED_MODULE_11__.beforeInput);\n _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.editor.value.destroy();\n });\n return {\n node: _utils_app_editor_refs__WEBPACK_IMPORTED_MODULE_7__.node,\n ready\n };\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (useEditor);\n\n//# sourceURL=webpack://rethink/./src/utils/app/editor/editor.ts?"); /***/ }), diff --git a/src/rethink/models/files/upload.py b/src/rethink/models/files/upload.py index 7f7c0e4..91e8913 100644 --- a/src/rethink/models/files/upload.py +++ b/src/rethink/models/files/upload.py @@ -7,8 +7,8 @@ import zipfile from typing import List, Tuple, Optional +import httpx import pymongo.errors -import requests from bson import ObjectId from bson.tz_util import utc from fastapi import UploadFile @@ -630,20 +630,34 @@ async def fetch_image_vditor(uid: str, url: str) -> Tuple[str, const.Code]: return "", code if await models.user.user_space_not_enough(u=u): return "", const.Code.USER_SPACE_NOT_ENOUGH + async with httpx.AsyncClient() as client: + try: + response = await client.get( + url=url, + headers=models.utils.ASYNC_CLIENT_HEADERS, + timeout=5. + ) + except ( + httpx.ConnectTimeout, + RuntimeError, + httpx.ConnectError, + httpx.ReadTimeout, + httpx.HTTPError + ) as e: + logger.info(f"failed to get {url}: {e}") + return "", const.Code.FILE_OPEN_ERROR + if response.status_code != 200: + return "", const.Code.FILE_OPEN_ERROR + + content = response.content + + file = UploadFile( + filename=url.split("/")[-1], + file=io.BytesIO(content), + headers=Headers(response.headers), + size=len(content) + ) - try: - r = requests.get(url) - except requests.exceptions.RequestException: - return url, const.Code.OK - - if r.status_code != 200: - return "", const.Code.FILE_OPEN_ERROR - file = UploadFile( - filename=url.split("/")[-1], - file=io.BytesIO(r.content), - headers=Headers(r.headers), - size=len(r.content) - ) res = await file_ops.save_upload_files( uid=uid, files=[file], diff --git a/src/rethink/models/search_engine/engine.py b/src/rethink/models/search_engine/engine.py index 3cc5c66..7fef782 100644 --- a/src/rethink/models/search_engine/engine.py +++ b/src/rethink/models/search_engine/engine.py @@ -4,6 +4,7 @@ from typing import List, Tuple, Sequence from rethink import const +from rethink.models.utils import strip_html_tags @dataclass @@ -12,6 +13,10 @@ class SearchDoc: title: str body: str + def __post_init__(self): + self.title = strip_html_tags(self.title) + self.body = strip_html_tags(self.body) + @dataclass class RestoreSearchDoc: @@ -23,6 +28,10 @@ class RestoreSearchDoc: disabled: bool inTrash: bool + def __post_init__(self): + self.title = strip_html_tags(self.title) + self.body = strip_html_tags(self.body) + @dataclass class SearchResult: diff --git a/src/rethink/models/utils.py b/src/rethink/models/utils.py index fd9c1cc..f803f38 100644 --- a/src/rethink/models/utils.py +++ b/src/rethink/models/utils.py @@ -3,6 +3,8 @@ import math import re import uuid +from html.parser import HTMLParser +from io import StringIO from typing import Tuple import httpx @@ -68,7 +70,7 @@ def preprocess_md(md: str, snippet_len: int = 200) -> Tuple[str, str, str]: title, body = split_title_body(fulltext=md) title = md2txt(title.strip()) body = md2txt(body.strip()) - snippet = body[:snippet_len] + snippet = strip_html_tags(body)[:snippet_len] return title, body, snippet @@ -156,14 +158,14 @@ def contain_only_http_link(md: str) -> str: async def get_title_description_from_link(url: str, language: str) -> Tuple[str, str]: if language == const.Language.ZH.value: - title = "网址没发现标题" - description = "网址没发现描述" + no_title = "网址没发现标题" + no_description = "网址没发现描述" elif language == const.Language.EN.value: - title = "No title found" - description = "No description found" + no_title = "No title found" + no_description = "No description found" else: - title = "No title found" - description = "No description found" + no_title = "No title found" + no_description = "No description found" async with httpx.AsyncClient() as client: try: response = await client.get( @@ -179,14 +181,15 @@ async def get_title_description_from_link(url: str, language: str) -> Tuple[str, httpx.HTTPError ) as e: logger.info(f"failed to get {url}: {e}") - return title, description + return no_title, no_description if response.status_code in [302, 301]: url = response.headers["Location"] return await get_title_description_from_link(url=url, language=language) if response.status_code != 200: - return title, description + return no_title, no_description html = response.text + title, description = "", "" found = re.search(r']*name="title"[^>]*content="([^"]*)"[^>]*>', html, re.DOTALL) if found is None: found = re.search(r']*content="([^"]*)"[^>]*name="title"[^>]*>', html, re.DOTALL) @@ -200,4 +203,29 @@ async def get_title_description_from_link(url: str, language: str) -> Tuple[str, found = re.search(r']*content="([^"]*)"[^>]*name="description"[^>]*>', html, re.DOTALL) if found: description = found.group(1).strip()[:400] + if title == "": + title = no_title + if description == "": + description = no_description return title, description + + +class MLStripper(HTMLParser): + def __init__(self): + super().__init__() + self.reset() + self.strict = False + self.convert_charrefs = True + self.text = StringIO() + + def handle_data(self, d): + self.text.write(d) + + def get_data(self): + return self.text.getvalue() + + +def strip_html_tags(html): + s = MLStripper() + s.feed(html) + return s.get_data() diff --git a/tests/test_api.py b/tests/test_api.py index 78672cf..673ab61 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -6,6 +6,7 @@ import unittest from pathlib import Path from typing import Dict +from unittest.mock import patch from zipfile import ZipFile from PIL import Image @@ -513,7 +514,11 @@ def test_upload_image(self): f1.close() shutil.rmtree("temp", ignore_errors=True) - def test_put_quick_node(self): + @patch( + "rethink.models.utils.httpx.AsyncClient.get", + return_value=Response(200, content="百度一下".encode("utf-8")) + ) + def test_put_quick_node(self, mocker): resp = self.client.put( "/api/node/quick", json={ diff --git a/tests/test_models_local.py b/tests/test_models_local.py index 5e94b54..ce4428d 100644 --- a/tests/test_models_local.py +++ b/tests/test_models_local.py @@ -4,8 +4,9 @@ from io import BytesIO from pathlib import Path from textwrap import dedent +from unittest.mock import patch -import requests +import httpx from PIL import Image from bson import ObjectId from bson.tz_util import utc @@ -351,7 +352,7 @@ async def test_files_upload_process(self): "startAt": now, "running": True, "obsidian": {}, - "problemFiles": [], + "msg": "", "code": const.Code.OK.value, } res = await models.database.COLL.import_data.insert_one(doc) @@ -409,22 +410,32 @@ async def test_upload_image_vditor(self): u, code = await models.user.get(self.uid) self.assertEqual(used_space + size, u["usedSpace"]) - async def test_fetch_image_vditor(self): + @patch( + "rethink.models.files.upload.httpx.AsyncClient.get", + ) + async def test_fetch_image_vditor(self, mock_get): + f = open(Path(__file__).parent.parent / "img" / "phone-notes.png", "rb") + mock_get.return_value = httpx.Response( + 200, + content=f.read(), + headers={"content-type": "image/png"} + ) + u, code = await models.user.get(self.uid) used_space = u["usedSpace"] - url = "https://rethink.run/favicon.ico" + url = "https://rethink.run/favicon.png" new_url, code = await models.files.fetch_image_vditor(self.uid, url) self.assertEqual(const.Code.OK, code) - self.assertTrue(new_url.endswith(".ico")) + self.assertTrue(new_url.endswith(".png")) self.assertTrue(new_url.startswith("/")) local_file = Path(__file__).parent / "tmp" / ".data" / new_url[1:] self.assertTrue(local_file.exists()) local_file.unlink() u, code = await models.user.get(self.uid) - r = requests.get(url) - self.assertEqual(used_space + len(r.content), u["usedSpace"]) + self.assertEqual(used_space + f.tell(), u["usedSpace"]) + f.close() async def test_update_used_space(self): u, code = await models.user.get(self.uid) diff --git a/tests/test_models_utils.py b/tests/test_models_utils.py index e0514fb..4798ddc 100644 --- a/tests/test_models_utils.py +++ b/tests/test_models_utils.py @@ -1,5 +1,8 @@ import unittest from textwrap import dedent +from unittest.mock import patch + +import httpx from rethink import const, config from rethink.models import utils @@ -92,18 +95,66 @@ def setUpClass(cls) -> None: def tearDownClass(cls) -> None: config.get_settings.cache_clear() - @unittest.skip("skip outer connection test") - async def test_get_title_description_from_link(self): - for url, res in [ - ("https://github.com/MorvanZhou/rethink", True), - # ("https://zhuanlan.zhihu.com/p/610939462?utm_id=0", True), - ("https://waqwe12f2f2fa.fffffffff", False), - ("https://baidu.com", True), - ("https://rethink.run", True), - ("https://rethink.run/about", True), - ("https://baidu.com/wqwqqqqq", False), - ("https://mp.weixin.qq.com/s/jbB0GXbjHpFR8m1-6TSASw", True), + # @unittest.skip("skip outer connection test") + @patch( + "rethink.models.utils.httpx.AsyncClient.get", + ) + async def test_get_title_description_from_link(self, mock_get): + for url, content, res in [ + ( + "https://github.com/MorvanZhou/rethink", + "MorvanZhou/rethink: Rethink: a note taking web app" + """""", + True + ), + ( + "https://zhuanlan.zhihu.com/p/610939462?utm_id=0", + """ + + python的httpx库如何使用 - 知乎 + """, + True + ), + ( + "https://waqwe12f2f2fa.fffffffff", + "", + False + ), + ( + "https://baidu.com", + """百度一下,你就知道 + """, + True + ), + ( + "https://rethink.run", + """rethink""", + True + ), + ( + "https://baidu.com/wqwqqqqq", + "", + False + ), + ( + "https://mp.weixin.qq.com/s/jbB0GXbjHpFR8m1-6TSASw", + """""", + False), ]: + if res: + mock_get.return_value = httpx.Response( + status_code=200, + content=content.encode("utf-8"), + ) + else: + mock_get.return_value = httpx.Response( + status_code=404, + content=content.encode("utf-8"), + ) title, desc = await utils.get_title_description_from_link( url, language=const.Language.EN.value) if res: