From 27834d7292fe40677fb00506feeffcd6337dc736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Tue, 11 Apr 2023 16:02:29 +0800 Subject: [PATCH] implement delfile --- backend/global/file.go | 55 +++++++++++-------- backend/global/question.go | 47 ++++++++++++++-- backend/paper.go | 29 ++++++++++ frontend/vben/mock/page/filelist.ts | 4 +- frontend/vben/package.json | 2 - frontend/vben/src/api/page/index.ts | 4 +- .../vben/src/api/page/model/fileListModel.ts | 4 -- .../vben/src/views/page/filelist/index.vue | 2 +- frontend/vben/yarn.lock | 5 -- 9 files changed, 107 insertions(+), 45 deletions(-) diff --git a/backend/global/file.go b/backend/global/file.go index 4970de9..4cca775 100644 --- a/backend/global/file.go +++ b/backend/global/file.go @@ -490,7 +490,7 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func } // DelFile by listid -func (f *FileDatabase) DelFile(fileid, uid int, istemp bool) error { +func (f *FileDatabase) DelFile(lstid, uid int, istemp bool) error { user, err := UserDB.GetUserByID(uid) if err != nil { return err @@ -498,19 +498,14 @@ func (f *FileDatabase) DelFile(fileid, uid int, istemp bool) error { if !user.IsSuper() { return ErrInvalidRole } - var file File - f.mu.RLock() + ftable := "" if istemp { - file, err = sql.Find[File](&f.db, FileTableTempFile, "WHERE ID="+strconv.Itoa(fileid)) + ftable = FileTableTempFile } else { - file, err = sql.Find[File](&f.db, FileTableFile, "WHERE ID="+strconv.Itoa(fileid)) - } - f.mu.RUnlock() - if err != nil { - return err + ftable = FileTableFile } f.mu.RLock() - lst, err := sql.Find[List](&f.db, FileTableList, "WHERE ID="+strconv.Itoa(file.ListID)) + lst, err := sql.Find[List](&f.db, FileTableList, "WHERE ID="+strconv.Itoa(lstid)) f.mu.RUnlock() if err != nil { return err @@ -518,21 +513,33 @@ func (f *FileDatabase) DelFile(fileid, uid int, istemp bool) error { if lst.Path == "" || strings.Contains(lst.Path, "..") { return os.ErrNotExist } - ques := make([]QuestionJSON, 0, 64) - err = json.Unmarshal(file.Questions, &ques) - if err != nil { - return err + i := strings.LastIndex(lst.Path, "/") + if i <= 0 { + return os.ErrNotExist } - for _, q := range ques { - q.Delete(f, istemp) + parentfolder := lst.Path[:i] + if utils.IsNotExist(parentfolder) { + return os.ErrNotExist } - if istemp { - err = f.db.Del(FileTableTempFile, "WHERE ID="+strconv.Itoa(fileid)) - } else { - err = f.db.Del(FileTableFile, "WHERE ID="+strconv.Itoa(fileid)) + if !lst.HasntAnalyzed { + f.mu.RLock() + file, err := sql.Find[File](&f.db, ftable, "WHERE ListID="+strconv.Itoa(lstid)) + f.mu.RUnlock() + if err != nil { + return err + } + err = f.db.Del(ftable, "WHERE ListID="+strconv.Itoa(lstid)) + if err != nil { + return err + } + ques := make([]QuestionJSON, 0, 64) + err = json.Unmarshal(file.Questions, &ques) + if err != nil { + return err + } + for _, q := range ques { + q.Delete(f, istemp) + } } - if err != nil { - logrus.Warnln("[global.DelFile] err:", err) - } - + return os.RemoveAll(parentfolder) } diff --git a/backend/global/question.go b/backend/global/question.go index 5453640..9ff592f 100644 --- a/backend/global/question.go +++ b/backend/global/question.go @@ -6,7 +6,9 @@ import ( "encoding/json" "strconv" + sql "github.com/FloatTech/sqlite" "github.com/corona10/goimagehash" + base14 "github.com/fumiama/go-base16384" "github.com/fumiama/paper-manager/backend/utils" "github.com/sirupsen/logrus" ) @@ -19,7 +21,7 @@ type QuestionJSON struct { Sub []QuestionJSON `json:"sub,omitempty"` } -// Delete me and all subs +// Delete me and all subs, ignore errors func (q *QuestionJSON) Delete(f *FileDatabase, istemp bool) { if b, err := hex.DecodeString(q.Name); err == nil { err = f.DelQuestion(int64(binary.LittleEndian.Uint64(b)), istemp) @@ -32,14 +34,49 @@ func (q *QuestionJSON) Delete(f *FileDatabase, istemp bool) { } } -// DelQuestion 删除问题, 其它问题的 dup 可能会残留有 id, 使用时需要排除 +// DelQuestion 删除问题, 与其它问题的 dup func (f *FileDatabase) DelQuestion(id int64, istemp bool) error { + qtable := "" + if istemp { + qtable = FileTableTempQuestion + } else { + qtable = FileTableQuestion + } f.mu.Lock() defer f.mu.Unlock() - if istemp { - return f.db.Del(FileTableTempQuestion, "WHERE ID="+strconv.FormatInt(id, 10)) + q, err := sql.Find[Question](&f.db, qtable, "WHERE ID="+strconv.FormatInt(id, 10)) + if err != nil { + return err } - return f.db.Del(FileTableQuestion, "WHERE ID="+strconv.FormatInt(id, 10)) + if len(q.Dup) > 2 { + dupmap := make(map[string]float64, 64) + err = json.Unmarshal(q.Dup, &dupmap) + if err == nil { + var buf [8]byte + for k := range dupmap { + _, err = hex.Decode(buf[:], base14.StringToBytes(k)) + if err == nil { + qid := int64(binary.LittleEndian.Uint64(buf[:])) + qq, err := sql.Find[Question](&f.db, qtable, "WHERE ID="+strconv.FormatInt(qid, 10)) + if err == nil && len(qq.Dup) > 2 { + dupmap2 := make(map[string]float64, 64) + err = json.Unmarshal(qq.Dup, &dupmap2) + if err == nil { + delete(dupmap2, k) + qq.Dup, err = json.Marshal(dupmap2) + if err == nil { + err = f.db.Insert(qtable, &qq) + if err != nil { + logrus.Warnln("[global.DelQuestion] insert modified dup to id", k, "table", qtable, "err:", err) + } + } + } + } + } + } + } + } + return f.db.Del(qtable, "WHERE ID="+strconv.FormatInt(id, 10)) } type Question struct { diff --git a/backend/paper.go b/backend/paper.go index 5e4a838..cf0ca22 100644 --- a/backend/paper.go +++ b/backend/paper.go @@ -23,6 +23,7 @@ var analyzeper = ttl.NewCache[int, uint](time.Hour) var ( errNoAnalyzePermission = errors.New("no analyze permission") + errNoDeletePermission = errors.New("no delete permission") ) type filelist struct { @@ -200,6 +201,34 @@ func init() { writeresult(w, codeSuccess, &message{C: 0, M: "分析完成"}, messageOk, typeSuccess) } }} + apimap["/api/delFile"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) { + token := r.Header.Get("Authorization") + user := usertokens.Get(token) + if user == nil { + writeresult(w, codeError, nil, errInvalidToken.Error(), typeError) + return + } + if !user.IsSuper() { + writeresult(w, codeError, nil, errNoDeletePermission.Error(), typeError) + return + } + idstr := r.URL.Query().Get("id") + if idstr == "" { + writeresult(w, codeError, nil, "empty id", typeError) + return + } + id, err := strconv.Atoi(idstr) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + err = global.FileDB.DelFile(id, *user.ID, false) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + writeresult(w, codeSuccess, "删除成功", messageOk, typeSuccess) + }} } // PaperHandler serves protected contents in global.FileFolder diff --git a/frontend/vben/mock/page/filelist.ts b/frontend/vben/mock/page/filelist.ts index cccf424..4dd2576 100644 --- a/frontend/vben/mock/page/filelist.ts +++ b/frontend/vben/mock/page/filelist.ts @@ -70,7 +70,7 @@ export default [ }) }, },*/ - { + /*{ url: '/api/delFile', timeout: 200, method: 'get', @@ -84,7 +84,7 @@ export default [ msg: '已成功删除文件' + id + '.', }) }, - }, + },*/ /*{ url: '/api/analyzeFile', timeout: 1000, diff --git a/frontend/vben/package.json b/frontend/vben/package.json index 7215220..4aa8582 100644 --- a/frontend/vben/package.json +++ b/frontend/vben/package.json @@ -29,7 +29,6 @@ "test:gzip": "npx http-server dist --cors --gzip -c-1", "test:br": "npx http-server dist --cors --brotli -c-1", "reinstall": "rimraf pnpm-lock.yaml && rimraf package.lock.json && rimraf node_modules && pnpm run bootstrap", - "prepare": "husky install", "gen:icon": "esno ./build/generate/icon/index.ts" }, "dependencies": { @@ -108,7 +107,6 @@ "eslint-plugin-vue": "^8.6.0", "esno": "^0.14.1", "fs-extra": "^10.1.0", - "husky": "^7.0.4", "inquirer": "^8.2.2", "less": "^4.1.2", "lint-staged": "12.3.7", diff --git a/frontend/vben/src/api/page/index.ts b/frontend/vben/src/api/page/index.ts index 420b71d..3f03c74 100644 --- a/frontend/vben/src/api/page/index.ts +++ b/frontend/vben/src/api/page/index.ts @@ -1,5 +1,5 @@ import { defHttp } from '/@/utils/http/axios' -import { getFileListModel, DelFile, AnalyzeFile, FileListGroupItem } from './model/fileListModel' +import { getFileListModel, AnalyzeFile, FileListGroupItem } from './model/fileListModel' import { DownloadFile, FileStatus } from './model/fileModel' enum Api { @@ -37,7 +37,7 @@ export const getFilePercent = (id: number) => { * @description: Get file percent */ export const delFile = (id: number) => { - return defHttp.get({ url: Api.DelFile, params: { id: id } }) + return defHttp.get({ url: Api.DelFile, params: { id: id } }) } /** diff --git a/frontend/vben/src/api/page/model/fileListModel.ts b/frontend/vben/src/api/page/model/fileListModel.ts index 86a8f56..af85355 100644 --- a/frontend/vben/src/api/page/model/fileListModel.ts +++ b/frontend/vben/src/api/page/model/fileListModel.ts @@ -14,10 +14,6 @@ export interface FileListGroupItem { */ export type getFileListModel = FileListGroupItem[] -export interface DelFile { - msg: string -} - export interface AnalyzeFile { code: number msg: string diff --git a/frontend/vben/src/views/page/filelist/index.vue b/frontend/vben/src/views/page/filelist/index.vue index b3bbf57..35e0a8f 100644 --- a/frontend/vben/src/views/page/filelist/index.vue +++ b/frontend/vben/src/views/page/filelist/index.vue @@ -130,7 +130,7 @@ item.delloading = true const msg = await delFile(item.id) if (msg) { - createMessage.success(msg.msg) + createMessage.success(msg) setTimeout(() => { deleteFileByID(item.id) }, 1000) diff --git a/frontend/vben/yarn.lock b/frontend/vben/yarn.lock index 3385df3..ce135aa 100644 --- a/frontend/vben/yarn.lock +++ b/frontend/vben/yarn.lock @@ -5174,11 +5174,6 @@ "resolved" "https://registry.npmmirror.com/human-signals/-/human-signals-2.1.0.tgz" "version" "2.1.0" -"husky@^7.0.4": - "integrity" "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==" - "resolved" "https://registry.npmmirror.com/husky/-/husky-7.0.4.tgz" - "version" "7.0.4" - "iconv-lite@^0.4.24": "integrity" "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==" "resolved" "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz"