Manage display of book covers
This commit is contained in:
306
front/package-lock.json
generated
306
front/package-lock.json
generated
@@ -23,7 +23,7 @@
|
||||
"globals": "^16.3.0",
|
||||
"prettier": "3.6.2",
|
||||
"vite": "^7.0.6",
|
||||
"vite-plugin-vue-devtools": "^8.0.0"
|
||||
"vite-plugin-vue-devtools": ">=8.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
@@ -1577,26 +1577,6 @@
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@sec-ant/readable-stream": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
|
||||
"integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@sindresorhus/merge-streams": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
|
||||
"integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
@@ -1738,14 +1718,14 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vue/devtools-core": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-8.0.1.tgz",
|
||||
"integrity": "sha512-Lf/+ambV3utWJ18r5TnpePbJ60IcIcqeZSQYLyNcFw2sFel0tGMnMyCdDtR1JNIdVZGAVaksTLhGh0FlrNu+sw==",
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-8.0.3.tgz",
|
||||
"integrity": "sha512-gCEQN7aMmeaigEWJQ2Z2o3g7/CMqGTPvNS1U3n/kzpLoAZ1hkAHNgi4ml/POn/9uqGILBk65GGOUdrraHXRj5Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-kit": "^8.0.1",
|
||||
"@vue/devtools-shared": "^8.0.1",
|
||||
"@vue/devtools-kit": "^8.0.3",
|
||||
"@vue/devtools-shared": "^8.0.3",
|
||||
"mitt": "^3.0.1",
|
||||
"nanoid": "^5.1.5",
|
||||
"pathe": "^2.0.3",
|
||||
@@ -1756,9 +1736,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-core/node_modules/nanoid": {
|
||||
"version": "5.1.5",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz",
|
||||
"integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==",
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz",
|
||||
"integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -1775,25 +1755,32 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-kit": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.0.1.tgz",
|
||||
"integrity": "sha512-7kiPhgTKNtNeXltEHnJJjIDlndlJP4P+UJvCw54uVHNDlI6JzwrSiRmW4cxKTug2wDbc/dkGaMnlZghcwV+aWA==",
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.0.3.tgz",
|
||||
"integrity": "sha512-UF4YUOVGdfzXLCv5pMg2DxocB8dvXz278fpgEE+nJ/DRALQGAva7sj9ton0VWZ9hmXw+SV8yKMrxP2MpMhq9Wg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-shared": "^8.0.1",
|
||||
"birpc": "^2.5.0",
|
||||
"@vue/devtools-shared": "^8.0.3",
|
||||
"birpc": "^2.6.1",
|
||||
"hookable": "^5.5.3",
|
||||
"mitt": "^3.0.1",
|
||||
"perfect-debounce": "^1.0.0",
|
||||
"perfect-debounce": "^2.0.0",
|
||||
"speakingurl": "^14.0.1",
|
||||
"superjson": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-kit/node_modules/perfect-debounce": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.0.0.tgz",
|
||||
"integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vue/devtools-shared": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.0.1.tgz",
|
||||
"integrity": "sha512-PqtWqPPRpMwZ9FjTzyugb5KeV9kmg2C3hjxZHwjl0lijT4QIJDd0z6AWcnbM9w2nayjDymyTt0+sbdTv3pVeNg==",
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.0.3.tgz",
|
||||
"integrity": "sha512-s/QNll7TlpbADFZrPVsaUNPCOF8NvQgtgmmB7Tip6pLf/HcOvBTly0lfLQ0Eylu9FQ4OqBhFpLyBgwykiSf8zw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1947,9 +1934,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/birpc": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/birpc/-/birpc-2.5.0.tgz",
|
||||
"integrity": "sha512-VSWO/W6nNQdyP520F1mhf+Lc2f8pjGQOtoHHm7Ze8Go1kX7akpVIrtTa0fn+HB0QJEDVacl6aO08YE0PgXfdnQ==",
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/birpc/-/birpc-2.6.1.tgz",
|
||||
"integrity": "sha512-LPnFhlDpdSH6FJhJyn4M0kFO7vtQ5iPw24FnG0y21q09xC7e8+1LeR31S1MAIrDAHp4m7aas4bEkTDTvMAtebQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
@@ -2560,33 +2547,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/execa": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-9.6.0.tgz",
|
||||
"integrity": "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sindresorhus/merge-streams": "^4.0.0",
|
||||
"cross-spawn": "^7.0.6",
|
||||
"figures": "^6.1.0",
|
||||
"get-stream": "^9.0.0",
|
||||
"human-signals": "^8.0.1",
|
||||
"is-plain-obj": "^4.1.0",
|
||||
"is-stream": "^4.0.1",
|
||||
"npm-run-path": "^6.0.0",
|
||||
"pretty-ms": "^9.2.0",
|
||||
"signal-exit": "^4.1.0",
|
||||
"strip-final-newline": "^4.0.0",
|
||||
"yoctocolors": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.19.0 || >=20.5.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
@@ -2633,22 +2593,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/figures": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
|
||||
"integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-unicode-supported": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/file-entry-cache": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
|
||||
@@ -2725,23 +2669,6 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/get-stream": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
|
||||
"integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sec-ant/readable-stream": "^0.4.1",
|
||||
"is-stream": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
@@ -2784,16 +2711,6 @@
|
||||
"integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/human-signals": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz",
|
||||
"integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=18.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||
@@ -2889,45 +2806,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-obj": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
|
||||
"integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-stream": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
|
||||
"integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-unicode-supported": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
|
||||
"integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-what": {
|
||||
"version": "4.1.16",
|
||||
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
|
||||
@@ -3171,36 +3049,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/npm-run-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
|
||||
"integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-key": "^4.0.0",
|
||||
"unicorn-magic": "^0.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-run-path/node_modules/path-key": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
|
||||
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/nth-check": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
||||
@@ -3303,19 +3151,6 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-ms": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz",
|
||||
"integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
@@ -3504,22 +3339,6 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-ms": {
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz",
|
||||
"integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"parse-ms": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
@@ -3636,19 +3455,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/sirv": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
|
||||
@@ -3682,19 +3488,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-final-newline": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
|
||||
"integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-json-comments": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
||||
@@ -3789,19 +3582,6 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unicorn-magic": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
|
||||
"integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin-utils": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.0.tgz",
|
||||
@@ -4013,18 +3793,17 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vite-plugin-vue-devtools": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-8.0.1.tgz",
|
||||
"integrity": "sha512-ecm/Xvtg5xsFPfY7SJ38Zb6NfmVrHxBhLMk/3nm5ZDAd7n8Dk2BV8JBuq1L5wRMVfvCth01vtzJViZC9TAC6qg==",
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-8.0.3.tgz",
|
||||
"integrity": "sha512-yIi3u31xUi28HcLlTpV0BvSLQHgZ2dA8Zqa59kWfIeMdHqbsunt6TCjq4wCNfOcGSju+E7qyHyI09EjRRFMbuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vue/devtools-core": "^8.0.1",
|
||||
"@vue/devtools-kit": "^8.0.1",
|
||||
"@vue/devtools-shared": "^8.0.1",
|
||||
"execa": "^9.6.0",
|
||||
"sirv": "^3.0.1",
|
||||
"vite-plugin-inspect": "^11.3.0",
|
||||
"@vue/devtools-core": "^8.0.3",
|
||||
"@vue/devtools-kit": "^8.0.3",
|
||||
"@vue/devtools-shared": "^8.0.3",
|
||||
"sirv": "^3.0.2",
|
||||
"vite-plugin-inspect": "^11.3.3",
|
||||
"vite-plugin-vue-inspector": "^5.3.2"
|
||||
},
|
||||
"engines": {
|
||||
@@ -4208,19 +3987,6 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/yoctocolors": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz",
|
||||
"integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,6 @@
|
||||
"globals": "^16.3.0",
|
||||
"prettier": "3.6.2",
|
||||
"vite": "^7.0.6",
|
||||
"vite-plugin-vue-devtools": "^8.0.0"
|
||||
"vite-plugin-vue-devtools": ">=8.0.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
const book = ref({
|
||||
title: "",
|
||||
author: ""
|
||||
author: "",
|
||||
coverId: null
|
||||
});
|
||||
const errors = ref(null)
|
||||
const titleError = computed(() => {
|
||||
@@ -50,7 +51,7 @@
|
||||
</div>
|
||||
<p v-if="authorError" class="help is-danger">{{authorError}}</p>
|
||||
</div>
|
||||
<CoverUpload name="cover"/>
|
||||
<CoverUpload name="cover" @on-image-upload="(id) => book.coverId = id"/>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<button class="button is-link">{{$t('addbook.submit')}}</button>
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { getImagePathOrDefault } from './api.js'
|
||||
|
||||
const props = defineProps({
|
||||
id: Number,
|
||||
title: String,
|
||||
author: String,
|
||||
imagePath: String,
|
||||
coverPath: String,
|
||||
rating: Number,
|
||||
read: Boolean
|
||||
});
|
||||
const imagePathOrDefault = (props.imagePath == "" || typeof props.imagePath === 'undefined') ? "defaultbook.png" : props.imagePath;
|
||||
const imagePathOrDefault = computed(() => getImagePathOrDefault(props.coverPath));
|
||||
const router = useRouter();
|
||||
|
||||
function openBook() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup>
|
||||
import { getBook } from './api.js'
|
||||
import { computed } from 'vue'
|
||||
import { getBook, getImagePathOrDefault } from './api.js'
|
||||
import { onBeforeRouteUpdate } from 'vue-router'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -7,7 +8,7 @@
|
||||
});
|
||||
|
||||
let { data, error } = getBook(props.id);
|
||||
const imagePathOrDefault = "../defaultbook.png"
|
||||
const imagePathOrDefault = computed(() => getImagePathOrDefault(data.value.coverPath));
|
||||
onBeforeRouteUpdate(async (to, from) => {
|
||||
let res = getBook(to.params.id);
|
||||
data = res.data;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { postReadBook } from './api.js'
|
||||
import { ref, computed } from 'vue'
|
||||
import { postReadBook, getImagePathOrDefault } from './api.js'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter();
|
||||
@@ -10,9 +10,9 @@
|
||||
title: String,
|
||||
author: String,
|
||||
id: Number,
|
||||
imagePath: String,
|
||||
coverPath: String,
|
||||
});
|
||||
const imagePathOrDefault = (props.imagePath == "" || typeof props.imagePath === 'undefined') ? "../defaultbook.png" : props.imagePath;
|
||||
const imagePathOrDefault = computed(() => getImagePathOrDefault(props.coverPath));
|
||||
const error = ref(null)
|
||||
|
||||
async function onUserBookRead() {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { postImage } from './api.js'
|
||||
|
||||
const emit = defineEmits(['OnImageUpload'])
|
||||
const props = defineProps({
|
||||
name: String
|
||||
});
|
||||
@@ -12,10 +13,15 @@
|
||||
function onFileChanged(e) {
|
||||
postImage(e.target.files[0])
|
||||
.then((res) => res.json())
|
||||
.then((json) => (imagePath.value = json["filepath"]))
|
||||
.then((json) => onJsonResult(json))
|
||||
.catch((err) => (error.value = err["error"]));
|
||||
}
|
||||
|
||||
function onJsonResult(json) {
|
||||
imagePath.value = json["filepath"];
|
||||
emit('OnImageUpload', json["fileId"])
|
||||
}
|
||||
|
||||
function unsetImage() {
|
||||
imagePath.value = null;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ import { useAuthStore } from './auth.store.js'
|
||||
|
||||
const baseUrl = "http://localhost:8080"
|
||||
|
||||
export function getImagePathOrDefault(path) {
|
||||
return (path == "" || typeof path === 'undefined') ?
|
||||
"../defaultbook.png" : "http://localhost:8080" + path;
|
||||
}
|
||||
|
||||
function useFetch(url) {
|
||||
const data = ref(null);
|
||||
const error = ref(null);
|
||||
|
||||
@@ -14,9 +14,11 @@ import (
|
||||
)
|
||||
|
||||
type bookUserGet struct {
|
||||
BookId uint `json:"id"`
|
||||
Title string `json:"title" binding:"required,max=300"`
|
||||
Author string `json:"author" binding:"max=100"`
|
||||
Rating int `json:"rating" binding:"min=0,max=10"`
|
||||
Read bool `json:"read"`
|
||||
}
|
||||
|
||||
func TestGetBooksHandler_Demo(t *testing.T) {
|
||||
@@ -35,6 +37,27 @@ func TestGetBooksHandler_Demo2(t *testing.T) {
|
||||
assert.Equal(t, 2, len(books))
|
||||
}
|
||||
|
||||
func TestGetBooksHandler_CheckOneBook(t *testing.T) {
|
||||
router := testutils.TestSetup()
|
||||
|
||||
token := testutils.ConnectDemo2User(router)
|
||||
books := testGetbooksHandler(t, router, token, 200)
|
||||
var book bookUserGet
|
||||
for _, b := range books {
|
||||
if b.Title == "De sang-froid" {
|
||||
book = b
|
||||
}
|
||||
}
|
||||
assert.Equal(t,
|
||||
bookUserGet{
|
||||
BookId: 18,
|
||||
Title: "De sang-froid",
|
||||
Author: "Truman Capote",
|
||||
Rating: 6,
|
||||
Read: true,
|
||||
}, book)
|
||||
}
|
||||
|
||||
func testGetbooksHandler(t *testing.T, router *gin.Engine, userToken string, expectedCode int) []bookUserGet {
|
||||
req, _ := http.NewRequest("GET", "/mybooks", nil)
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", userToken))
|
||||
|
||||
@@ -21,6 +21,7 @@ func Initdb(databasePath string, demoDataPath string) *gorm.DB {
|
||||
db.AutoMigrate(&model.Book{})
|
||||
db.AutoMigrate(&model.User{})
|
||||
db.AutoMigrate(&model.UserBook{})
|
||||
db.AutoMigrate(&model.StaticFile{})
|
||||
var book model.Book
|
||||
queryResult := db.Limit(1).Find(&book)
|
||||
if queryResult.RowsAffected == 0 && demoDataPath != "" {
|
||||
|
||||
42
internal/fileutils/fileutils.go
Normal file
42
internal/fileutils/fileutils.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package fileutils
|
||||
|
||||
import (
|
||||
"mime/multipart"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/appcontext"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/model"
|
||||
)
|
||||
|
||||
func SaveStaticFile(ac *appcontext.AppContext, file *multipart.FileHeader) (model.StaticFile, error) {
|
||||
filename := file.Filename
|
||||
filepath := computePathFromName(ac, filename)
|
||||
err := ac.C.SaveUploadedFile(file, ac.Config.ImageFolderPath+"/"+filepath)
|
||||
if err != nil {
|
||||
return model.StaticFile{}, err
|
||||
}
|
||||
staticFile := model.StaticFile{
|
||||
Name: filename,
|
||||
Path: filepath,
|
||||
}
|
||||
ac.Db.Save(&staticFile)
|
||||
return staticFile, nil
|
||||
}
|
||||
|
||||
func computePathFromName(ac *appcontext.AppContext, filename string) string {
|
||||
var existingFiles []model.StaticFile
|
||||
ac.Db.Where("name = ?", filename).Find(&existingFiles)
|
||||
l := len(existingFiles)
|
||||
if l == 0 {
|
||||
return filename
|
||||
} else {
|
||||
extension := filepath.Ext(filename)
|
||||
basename := filename[:len(filename)-len(extension)]
|
||||
return basename + "-" + strconv.Itoa(l) + extension
|
||||
}
|
||||
}
|
||||
|
||||
func GetWsLinkPrefix() string {
|
||||
return "/bookcover/"
|
||||
}
|
||||
@@ -8,4 +8,6 @@ type Book struct {
|
||||
Author string `json:"author"`
|
||||
AddedBy User
|
||||
AddedByID uint
|
||||
Cover StaticFile
|
||||
CoverID uint
|
||||
}
|
||||
|
||||
9
internal/model/file.go
Normal file
9
internal/model/file.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package model
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type StaticFile struct {
|
||||
gorm.Model
|
||||
Name string `gorm:"not null"`
|
||||
Path string `gorm:"not null;index;uniqueIndex"`
|
||||
}
|
||||
@@ -18,6 +18,10 @@ type HttpError struct {
|
||||
}
|
||||
|
||||
func ValidateId(db *gorm.DB, id uint, value any) error {
|
||||
//id = 0 means empty id, so no check
|
||||
if id == 0 {
|
||||
return nil
|
||||
}
|
||||
record := map[string]any{}
|
||||
result := db.Model(value).First(&record, id)
|
||||
if result.Error == nil {
|
||||
|
||||
69
internal/query/query.go
Normal file
69
internal/query/query.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/fileutils"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type BookGet struct {
|
||||
Title string `json:"title" binding:"required,max=300"`
|
||||
Author string `json:"author" binding:"max=100"`
|
||||
Rating int `json:"rating"`
|
||||
Read bool `json:"read"`
|
||||
CoverPath string `json:"coverPath"`
|
||||
}
|
||||
|
||||
func FetchBookGet(db *gorm.DB, userId uint, bookId uint64) (BookGet, error) {
|
||||
var book BookGet
|
||||
query := db.Model(&model.Book{})
|
||||
query = query.Select("books.title, books.author, user_books.rating, user_books.read, " + selectStaticFilesPath())
|
||||
query = query.Joins("left join user_books on (user_books.book_id = books.id and user_books.user_id = ?)", userId)
|
||||
query = query.Joins("left join static_files on (static_files.id = books.cover_id)")
|
||||
query = query.Where("books.id = ?", bookId)
|
||||
res := query.First(&book)
|
||||
return book, res.Error
|
||||
}
|
||||
|
||||
type BookSearchGet struct {
|
||||
Title string `json:"title" binding:"required,max=300"`
|
||||
Author string `json:"author" binding:"max=100"`
|
||||
ID uint `json:"id"`
|
||||
CoverPath string `json:"coverPath"`
|
||||
}
|
||||
|
||||
func FetchBookSearchGet(db *gorm.DB, searchterm string) ([]BookSearchGet, error) {
|
||||
var books []BookSearchGet
|
||||
query := db.Model(&model.Book{})
|
||||
query = query.Select("books.title, books.author, books.id," + selectStaticFilesPath())
|
||||
query = query.Joins("left join static_files on (static_files.id = books.cover_id)")
|
||||
query = query.Where("LOWER(title) LIKE ?", "%"+strings.ToLower(searchterm)+"%")
|
||||
res := query.Find(&books)
|
||||
return books, res.Error
|
||||
}
|
||||
|
||||
type BookUserGet struct {
|
||||
ID uint `json:"id"`
|
||||
Title string `json:"title" binding:"required,max=300"`
|
||||
Author string `json:"author" binding:"max=100"`
|
||||
Rating int `json:"rating" binding:"min=0,max=10"`
|
||||
Read bool `json:"read" binding:"boolean"`
|
||||
CoverPath string `json:"coverPath"`
|
||||
}
|
||||
|
||||
func FetchBookUserGet(db *gorm.DB, userId uint) ([]BookUserGet, error) {
|
||||
var books []BookUserGet
|
||||
query := db.Model(&model.UserBook{})
|
||||
query = query.Select("books.id, books.title, books.author, user_books.rating, user_books.read," + selectStaticFilesPath())
|
||||
query = query.Joins("left join books on (books.id = user_books.book_id)")
|
||||
query = query.Joins("left join static_files on (static_files.id = books.cover_id)")
|
||||
query = query.Where("user_id = ?", userId)
|
||||
res := query.Find(&books)
|
||||
return books, res.Error
|
||||
}
|
||||
|
||||
func selectStaticFilesPath() string {
|
||||
return "(CASE COALESCE(static_files.path, '') WHEN '' THEN '' ELSE concat('" + fileutils.GetWsLinkPrefix() + "', static_files.path) END) as CoverPath"
|
||||
}
|
||||
@@ -7,16 +7,10 @@ import (
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/appcontext"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/model"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/myvalidator"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/query"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type bookGet struct {
|
||||
Title string `json:"title" binding:"required,max=300"`
|
||||
Author string `json:"author" binding:"max=100"`
|
||||
Rating int `json:"rating"`
|
||||
Read bool `json:"read"`
|
||||
}
|
||||
|
||||
func GetBookHandler(ac appcontext.AppContext) {
|
||||
bookId, err := strconv.ParseUint(ac.C.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
@@ -33,13 +27,8 @@ func GetBookHandler(ac appcontext.AppContext) {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
var book bookGet
|
||||
query := ac.Db.Model(&model.Book{})
|
||||
query = query.Select("books.title, books.author, user_books.rating, user_books.read")
|
||||
query = query.Joins("left join user_books on (user_books.book_id = books.id and user_books.user_id = ?)", user.ID)
|
||||
query = query.Where("books.id = ?", bookId)
|
||||
res := query.First(&book)
|
||||
if res.Error != nil {
|
||||
book, queryErr := query.FetchBookGet(ac.Db, user.ID, bookId)
|
||||
if queryErr != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
type bookPostCreate struct {
|
||||
Title string `json:"title" binding:"required,max=300"`
|
||||
Author string `json:"author" binding:"max=100"`
|
||||
CoverID uint `json:"coverId"`
|
||||
}
|
||||
|
||||
func PostBookHandler(ac appcontext.AppContext) {
|
||||
@@ -18,6 +19,11 @@ func PostBookHandler(ac appcontext.AppContext) {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
err = myvalidator.ValidateId(ac.Db, book.CoverID, &model.StaticFile{})
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
user, fetchUserErr := ac.GetAuthenticatedUser()
|
||||
if fetchUserErr != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
@@ -33,9 +39,13 @@ func PostBookHandler(ac appcontext.AppContext) {
|
||||
}
|
||||
|
||||
func bookWsToDb(b bookPostCreate, user *model.User) model.Book {
|
||||
return model.Book{
|
||||
book := model.Book{
|
||||
Title: b.Title,
|
||||
Author: b.Author,
|
||||
AddedBy: *user,
|
||||
}
|
||||
if b.CoverID > 0 {
|
||||
book.CoverID = b.CoverID
|
||||
}
|
||||
return book
|
||||
}
|
||||
|
||||
@@ -2,33 +2,18 @@ package routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/appcontext"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/model"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/myvalidator"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/query"
|
||||
)
|
||||
|
||||
type bookSearchGet struct {
|
||||
Title string `json:"title" binding:"required,max=300"`
|
||||
Author string `json:"author" binding:"max=100"`
|
||||
ID uint `json:"id"`
|
||||
}
|
||||
|
||||
func GetSearchBooksHandler(ac appcontext.AppContext) {
|
||||
searchterm := ac.C.Param("searchterm")
|
||||
var booksDb []model.Book
|
||||
ac.Db.Where("LOWER(title) LIKE ?", "%"+strings.ToLower(searchterm)+"%").Find(&booksDb)
|
||||
books := make([]bookSearchGet, 0)
|
||||
for _, b := range booksDb {
|
||||
books = append(books, bookDbToWs(&b))
|
||||
books, err := query.FetchBookSearchGet(ac.Db, searchterm)
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
ac.C.JSON(http.StatusOK, books)
|
||||
}
|
||||
|
||||
func bookDbToWs(b *model.Book) bookSearchGet {
|
||||
return bookSearchGet{
|
||||
Title: b.Title,
|
||||
Author: b.Author,
|
||||
ID: b.ID,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,39 +4,16 @@ import (
|
||||
"net/http"
|
||||
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/appcontext"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/model"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/myvalidator"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/query"
|
||||
)
|
||||
|
||||
type bookUserGet struct {
|
||||
BookID uint `json:"id"`
|
||||
Title string `json:"title" binding:"required,max=300"`
|
||||
Author string `json:"author" binding:"max=100"`
|
||||
Rating int `json:"rating" binding:"min=0,max=10"`
|
||||
Read bool `json:"read" binding:"boolean"`
|
||||
}
|
||||
|
||||
func GetMyBooksHanderl(ac appcontext.AppContext) {
|
||||
var userbooks []model.UserBook
|
||||
user, err := ac.GetAuthenticatedUser()
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
ac.Db.Preload("Book").Where("user_id = ?", user.ID).Find(&userbooks)
|
||||
booksDto := make([]bookUserGet, 0)
|
||||
for _, userbook := range userbooks {
|
||||
booksDto = append(booksDto, userBookDbToWs(&userbook))
|
||||
}
|
||||
ac.C.JSON(http.StatusOK, booksDto)
|
||||
}
|
||||
|
||||
func userBookDbToWs(b *model.UserBook) bookUserGet {
|
||||
return bookUserGet{
|
||||
BookID: b.BookID,
|
||||
Title: b.Book.Title,
|
||||
Author: b.Book.Author,
|
||||
Rating: b.Rating,
|
||||
Read: b.Read,
|
||||
}
|
||||
userbooks, err := query.FetchBookUserGet(ac.Db, user.ID)
|
||||
ac.C.JSON(http.StatusOK, userbooks)
|
||||
}
|
||||
|
||||
@@ -4,21 +4,33 @@ import (
|
||||
"net/http"
|
||||
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/appcontext"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/fileutils"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/model"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/myvalidator"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type fileInfoPost struct {
|
||||
FileID uint `json:"fileId"`
|
||||
FilePath string `json:"filepath"`
|
||||
}
|
||||
|
||||
func PostUploadBookCoverHandler(ac appcontext.AppContext) {
|
||||
file, err := ac.C.FormFile("file")
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
filepath := file.Filename
|
||||
err = ac.C.SaveUploadedFile(file, ac.Config.ImageFolderPath+"/"+filepath)
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
staticFile, saveErr := fileutils.SaveStaticFile(&ac, file)
|
||||
if saveErr != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, saveErr)
|
||||
return
|
||||
}
|
||||
ac.C.JSON(http.StatusOK, gin.H{"filepath": "/bookcover/" + filepath})
|
||||
ac.C.JSON(http.StatusOK, staticFileDbToWs(&staticFile))
|
||||
}
|
||||
|
||||
func staticFileDbToWs(f *model.StaticFile) fileInfoPost {
|
||||
return fileInfoPost{
|
||||
FileID: f.ID,
|
||||
FilePath: fileutils.GetWsLinkPrefix() + f.Path,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user